0. 들어가기 전에
이번 강좌에서는 GPIO컨트롤을 해볼까 합니다.
GroundZero님이 http://cafe.naver.com/openrt/2669 게시물에 올리신 아두이노를 이용한 J7-3 번 핀에 대한 컨트롤을 Standard Peripheral Library를 이요하여 구현해보는 것이 목적입니다.
Base Code는 http://lifeseed.tistory.com/75 게시물의 첨부파일이며, 1초마다 LED가 켜졌다, 꺼졌다를 반복하는 코드입니다.
1. 코드 작성 및 컴파일
void setup(void) { GPIO_InitTypeDef GPIO_InitStructure; // RCC Configuration
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE );
/* J7-3 PB2 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); }
void loop(void) { GPIO_WriteBit(GPIOB, GPIO_Pin_2, 1); osa_mdelay(1000); GPIO_WriteBit(GPIOB, GPIO_Pin_2, 0); osa_mdelay(1000); } |
arch/main.c 의 setup 및 loop함수에 위와 같이 코딩하고 cs-make를 통하여 Build합니다.
첨부된 코드를 이용하여 Build하니 아래와 같은 에러가 발생합니다.
. . .
./arch/main.c:53:2: warning: implicit declaration of function 'GPIO_WriteBit' [- Wimplicit-function-declaration] ./arch/main.c:53:2: warning: nested extern declaration of 'GPIO_WriteBit' [-Wnes ted-externs] ./arch/main.c:53:23: error: 'GPIO_Pin_13' undeclared (first use in this function ) cs-make: *** [obj.stm32f103cb/main.o] Error 1 |
라이브러리에서 제공하는 함수가 define이 안되어 있다는 군요.
모든 라이브러리를 한번에 include를 하고 빌드를 하면 좋겠지만, 코드 사이즈가 커져서 Flash용량보다 커지는 경우가 발생할 수 있어 필요한 라이브러리만 include하여 사용하게 됩니다.
필요한 라이브러리를 include하는 방법은 다음과 같이 2개의 파일을 수정합니다.
1) arch/include/stm32f10x_conf.h 의 38라인의 주석을 풀어줍니다.
/* #include "stm32f10x_gpio.h" */
=>
#include "stm32f10x_gpio.h"
|
2) arch/STM32F10x_StdPeriph_Driver/src/Makefile.inc 의 18번째 라인의 주석을 풀어 줍니다.
#STM32F10X_DRV_SRC += stm32f10x_gpio.c
=>
STM32F10X_DRV_SRC += stm32f10x_gpio.c
|
그리고 다시 빌드를 하면
stm32f103cb.bin 파일이 생성됩니다.
arm-none-eabi-objcopy -O binary stm32f103cb.elf stm32f103cb.bin arm-none-eabi-objdump -h -S -C stm32f103cb.elf > stm32f103cb.lss arm-none-eabi-nm -n stm32f103cb.elf > stm32f103cb.sym arm-none-eabi-size -A stm32f103cb.elf stm32f103cb.elf : section size addr .text 7356 134234112 .data 40 536870912 .heap 3072 536870952 .stack_dummy 1024 536870952 .ARM.attributes 41 0 .comment 48 0 .debug_info 17894 0 .debug_abbrev 3895 0 .debug_aranges 328 0 .debug_line 5702 0 .debug_str 7094 0 .debug_frame 3288 0 .debug_loc 12151 0 .debug_ranges 192 0 Total 62125 |
2. Download 및 실행
SW3을 누른채로 Reset하여 부트모드로 진입후 1번항목을 선택하고 TeraTerm등의 Terminal 창에서 Y-Modem으로 빌드된 stm32f103cb.bin을 전송합니다.
(저는 Teraterm V4.79를 사용하고 있습니다.)
================== Main Menu ============================
Download Image To Flash ------- 1
Upload Image From Flash ------- 2
Execute ------------------------------ 3
==========================================================
Waiting for the file to be sent ... (press 'a' to abort) C
Programming Completed Successfully! -------------------------------- Name: stm32f103cb.bin Size: 7396 Bytes ------------------- |
다운로드가 완료되면 Reset버튼을 눌러 코드를 실행합니다.
그러면 J7-3번 핀에 연결된 LED가 1초마다 한번씩 깜빡이는 것을 확인 할 수 있습니다.
3. Code 설명
1) GPIOB Clock 인가
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE ); |
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE );
- SmartRobot Board의 J7-3 번핀은 PB2번이 할당되어 있습니다. 위의 코드는 GPIOB port에 Clock을 인가해 실제 GPIO가 동작하도록 합니다. 모든 Peri. 들은 사용전에 반드시 Clock을 인가해 주어야 합니다.
2) GPIOB Pin2를 Output으로 설정
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); |
- GPIOB의 2번핀을 Output push-pull 모드로 설정합니다.
3) GPIOB 2번핀 Low/High Setting
GPIO_WriteBit(GPIOB, GPIO_Pin_2, 1); osa_mdelay(1000); GPIO_WriteBit(GPIOB, GPIO_Pin_2, 0); osa_mdelay(1000); |
- GPIOB Port의 2번핀을 High로 설정후 1000msec 유지 그리고 Low로 설정후 1000msec 유지 합니다.
4) Arudino code와의 비교
이렇게 보면 Arduino Code가 굉장히 Simple함을 알 수 있습니다.
초기화를 위하여 변수선언까지 5라인으로 구성된 2) 번코드가 Arduino에서는
pinMode(BOARD_LED_PIN, OUTPUT);
이라는 한줄의 함수 호출로 정리가 됩니다.
cf) Ardiono Code
void setup(void) { pinMode(BOARD_LED_PIN, OUTPUT); }
void loop(void) { digitalWrite(BOARD_LED_PIN, HIGH); delay(1000); digitalWrite(BOARD_LED_PIN, LOW);
delay(1000); } |
4. Register Control
1) GPIO Base Address
GPIO는 A ~ G까지 총 7개의 Port를 제공하며 각각의 Register Base Address는 다음과 같다.
GPIO A ~ D Base Address : [0x40010800, 0x40010C00, 0x40011000, 0x40011400]
GPIO E ~ G Base Address : [0x40011800, 0x40011C00, 0x40012000] |
각각의 Port는 0 ~ 16번의 pin을 가지며, CLR, CRH Register를 통하여 Pin의 속성에 관한 설정을하며, Output Mode일 경우 ODR Register를 통하여 출력 Level을 설정할 수 있다.
2) Register Description
GPIOx_CRL (x=A..G)
- offset : 0x0
- 0 ~ 7 번 Pin의 속성을 결정
- 각 pin당 CNF 2bit, MODE 2bit 로 총 4bit가 할당된다.
GPIOx_CRH (x=A..G)
- offset : 0x4
- 8 ~ 15 번 Pin의 속성을 결정
- 각 pin당 CNF 2bit, MODE 2bit 로 총 4bit가 할당된다.
MODE 및 CNF 의 pin에 대한 description은 다음과 같다.
GPIOx_ODR (x=A..G)
- offset : 0xC
- 0 ~ 15 번 Pin의 Output Level을 결정
3) Example
본 예제의 동일한 기능을 위해 다음과 같은 세팅이 가능하다.
우선 GPIO Port B이므로 Base Address는
0x40010C00 이다.
그리고 2번핀의 속성을 Output으로 설정 하기 위해 CRL의 8~11번 비트를 Control하며, Output Level을 조정하기 위해 ODR Register의 2번 비트를 1 혹은 0으로 설정하면 된다.
이 예제에서는 MODE[1:0] 는 11, CNF[1:0] 은 00 으로 설정하였다.
void setup(void) {
int reg_value;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE );
reg_value = *(volatile unsigned int *)0x40010c00;
reg_value &= (~0xF00); reg_value |= (0x300); *(volatile unsigned int *)0x40010c00 = reg_value;
}
void loop(void) { unsigned int reg_value;
reg_value = *(volatile unsigned int *)0x40010c0c;
reg_value |= (0x4); *(volatile unsigned int *)0x40010c0C = reg_value;
osa_mdelay(1000);
reg_value &= (~0x4); *(volatile unsigned int *)0x40010c0C = reg_value;
osa_mdelay(1000); } |
[참고자료]
[1] CD00171190 STM32F1xx Reference Manual
[2]
[3]