본문 바로가기
Robot/Device Control

[STM32F10x-StdPeriph] 1. SmartRobot Board 실습 - GPIO Output Control

by lifeseed 2013. 11. 18.
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을 전송합니다.
자세한 다운로드 방법은 http://lifeseed.tistory.com/73 의 3번 항목을 참조하시면 됩니다.
(저는 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]