본문 바로가기
Robot/Device Control

[STM32F10x-StdPeriph] 2. SmartRobot Board 실습 - GPIO Input Control

by lifeseed 2013. 11. 18.
0. 들어가기 전에

   이번 강좌에서는 이전 강좌에 이어 GPIO Input 컨트롤을 해볼까 합니다.

앞의 예제를 그대로 이용할 생각이며, J7-4 번 핀을 Switch등을 통해 입력으로 받아 Low/High에 따라 J7 - 3번 핀의 출력을 제어해보는 것이 목적입니다.

Base Code는 http://lifeseed.tistory.com/75 게시물의 첨부파일이며, 컴파일 Error가 발생할 경우 http://lifeseed.tistory.com/76 의 1번항목을 정독 부탁드립니다.

 

 

1. 코드 작성 및 컴파일
SmartRobot Board의 J7-3 은 PB2, J7-4 는 PB10입니다. 

 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);

 

 /* J7-4 PB10 */

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
 GPIO_Init(GPIOB, &GPIO_InitStructure);
}

 

void loop(void)
{

 if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10))
 {
  GPIO_WriteBit(GPIOB, GPIO_Pin_2, 1);

 }
 else
 {
  GPIO_WriteBit(GPIOB, GPIO_Pin_2, 0);
 }

}


arch/main.c 의 setup 및 loop함수에 위와 같이 코딩하고 cs-make를 통하여 Build합니다.

 

컴파일 에러가 날 경우 gpio library를 include해야 합니다.

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              7392   134234112
.data                40   536870912
.heap              3072   536870952
.stack_dummy       1024   536870952
.ARM.attributes      41           0
.comment             48           0
.debug_info       17905           0
.debug_abbrev      3908           0
.debug_aranges      328           0
.debug_line        5727           0
.debug_str         7140           0
.debug_frame       3292           0
.debug_loc        12151           0
.debug_ranges       192           0
Total             62260
 
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-4 가 LOW 값이 인가될 경우 J7-3번 핀에 연결된 LED가 꺼지고,
J7-4 가 HIGH 값이 인가될 경우 J7-3번 핀에 연결된 LED가 켜지는 것을 확인할 수 있습니다.
Switch를 J7-4에 연결하여도 되고, Jump선을 통해 직접 J7-4를 Ground나 VCC 3.3V에 연결하여도 됩니다.


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);


3) GPIOB Pin10를 Input으로 설정 

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
 GPIO_Init(GPIOB, &GPIO_InitStructure);


4) GPIOB 10번핀 입력값 읽어오기 

 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10);

- GPIOB Port의 10번핀의 입력 Low/High 상태를 알수 있다.
 
5) 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와의 비교
역시 초기화 과정이 Simple한 API로 제공됩니다.
PB10라인을 BUTTON_PIN이라고 정의할 경우 아래와 같은 코드로 정리될 수 있습니다.
 
cf) Ardiono Code 

 void setup(void)
{
 pinMode(BOARD_LED_PIN, OUTPUT);

 pinMode(BUTTON_PIN, INPUT);
}

 

void loop(void)
{

 if(digitalRead(BUTTON_PIN)==HIGH)

 {
    digitalWrite(BOARD_LED_PIN, HIGH);

 }

 else

 {

    digitalWrite(BOARD_LED_PIN, LOW);

 }
}


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의 속성에 관한 설정을하며, Input Mode일 경우 IDR 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_IDR (x=A..G) 
- offset : 0x8
- 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으로 설정하면 된다.
10번핀의 속성을 Input으로 설정 하기 위해 CRH의 8~11번 비트를 Control하며, Input Level을 읽어오기 위해 IDR Register의 10번 비트를 1 혹은 0으로 설정하면 된다.
이 예제에서는 MODE[1:0] 는 00, CNF[1:0] 은 10 으로 설정하였다.

 void setup(void)
{

 int reg_value;

 

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE );

 

 // PB2 Output

 reg_value = *(volatile unsigned int *)0x40010c00; 

 reg_value &= (~0xF00);
 reg_value |= (0x300);
                                           
 *(volatile unsigned int *)0x40010c00 = reg_value;   

 

 // PB10 Input

 reg_value = *(volatile unsigned int *)0x40010c04; 

 reg_value &= (~0xF00);
 reg_value |= (0x800);
                                           
 *(volatile unsigned int *)0x40010c04 = reg_value;   

}

 

void loop(void)
{
 unsigned int reg_value, input_value;

 

 reg_value = *(volatile unsigned int *)0x40010c0c;

 input_value = *(volatile unsigned int *)0x40010c08;

 

 if(input_value & 0x400)

 {

   reg_value |= (0x4);
   *(volatile unsigned int *)0x40010c0C = reg_value;

 }

 else

 {

   reg_value &= (~0x4);
   *(volatile unsigned int *)0x40010c0C = reg_value;
 }

}


 
[참고자료]

[1] CD00171190 STM32F1xx Reference Manual
[2]
[3]