이번 시리즈에서는 STM32F407 기반 EVM Borad인 STM32F407G-DISC1을 IAR과 Standard Peripheral Libraries로 제어하기 위한 튜토리얼 내용이 담긴 포스팅입니다.

👨‍💻 개발일지 (2) : GPIO

다용도 입출력(general-purpose input/output, GPIO)은 입력이나 출력을 포함한 동작이 런타임시에 사용자에 의해 제어될 수 있는, 집적 회로나 전기 회로 기판의 디지털 신호 핀이다.

출처: 🔗 위키백과

GPIO는 사용자의 필요에 따라 사용하는 범용 입출력핀이다. 이를 통해 외부의 핀을 이용여 다른 기기와 주변장치를 이용해 서로 통신을 하거나 PWM등을 이용해 서보모터를 제어하는 응용이 가능하다.

1. STM32F407G-DISC1 GPIO

STM32F407VG에는 GPIO의 포트는 총 12개(A ~ K)이며 각각 16개(0 ~ 15)의 Pin을 가지고 있다. 각 포트와 핀들의 기능을 자세히 확인하고 싶다면 🔗 STM32F407 Datasheet에 page 41 Pinouts and pin description 을 확인하면 된다.

예시를 위해 Datasheet의 내용일부를 확인해보면, Port A의 9 pin과 Port A의 10번핀은 각각 USART1로 활용할 수 있다. 아래처럼 외부 GPIO핀에 원하는 Port와 Pin이 있다면(적색, 청색), USB to UART같은 모듈을 이용하여 PC의 터미널과 통신을 할 수 있다.

위의 표에서 나와있듯 당연하게 모든 Port와 Pin을 자기가 할당하고 싶은 기능을 다 할당할 수 없다.예를들어 Port A의 10 Pin에 I^2^C의 SCL 기능을 할당하고 싶더라도 가능하지 않다. 물론 GPIO을 Output으로 설정해 I^2^C의 기능을 유사하게 흉내낼 순 있지만 주변장치를 활용하는 것은 아니기 때문에 비효율적일 수 있다.

2. STL을 이용한 GPIO 폴링 제어

Standard Periph Library를 이용해 STM32F407G-DISC1을 제어하는 코드를 작성해 업로드해보자. 📝

2.1 STM32F407G-DISC1 Polling Code ✍

우선 STM32F407G-DISC1에 할당된 LED 4개와 Button이 어디 Port에 맵핑이 되어있는지 확인해 보자. LED와 Button의 위치는 지난번 포스팅 🔗 STM32F407G-DISC1 개발일지 (1)에서 확인할 수 있다.

  • LED: Port D pin12, pin13, pin14, pin15
  • Button: Port A pin0

각각 맵핑되어 있는 Port 와 Pin번호의 정보를 이용와 STL을 이용해 Button을 누를때 마다 LED를 토글시키는 코드를 작성해 보자.

/**
  ******************************************************************************
  * @file    Project/STM32F407G-DISC1_Tutorial/main.c
  * @author  Geunhyeok Lee
  * @version V0.0.1
  * @date    05-February-2022
  * @brief   Main program
  ******************************************************************************
  */

#include "main.h"

int main()
{
	GPIO_Configuration();
    
	while(1)
	{
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == SET)
		{
			GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
			GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
			GPIO_ToggleBits(GPIOD, GPIO_Pin_14);
			GPIO_ToggleBits(GPIOD, GPIO_Pin_15);
		}
	}
	
  return 0;
}

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Speed = GPIO_Medium_Speed;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Medium_Speed;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

}
/******************************** END OF FILE *********************************/
/**
  ******************************************************************************
  * @file    Project/STM32F407G-DISC1_Tutorial/main.h
  * @author  Geunhyeok Lee
  * @version V0.0.1
  * @date    05-February-2022
  * @brief   Main program header
  ******************************************************************************
  */
  
  
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void GPIO_Configuration(void);

#endif /* __MAIN_H */

/******************************** END OF FILE *********************************/

위 코드를 업로드하면 의도한 바처럼 파란 Button을 누르면 아래처럼 4개의 LED를 토글시킬 수 있다. LED가 자꾸 꺼지는건 바운싱(혹은 채터링)현상을 해결하지 않아서이다.

2.2 STM32F407G-DISC1 Polling Code 살펴보기 👨‍🏫

main.h 파일에는 void GPIO_Configuration(void); 라는 함수 프로토타입 선언을 위해 넣어둔 내용외에는 특별한 점이 없으므로 바로 mian.c 의 내용안의 GPIO_Configuration을 확인하자.

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Speed = GPIO_Medium_Speed;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Medium_Speed;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

}

GPIO_InitTypeDef 이라는 구조체는 GPIO의 초기화를 위해 존재하는 구조체이다. 이 구조체를 통해 GPIO에 관련된 레지스터값을 세팅하는 역할을 한다. 관련 레지스터는 잠시후에 알아보자.

STM32계열의 MCU는 내부 주변장치 및 여러 기능을 이용하기 위해서는 각 주변장치에 연결되어 있는 버스에 클럭을 인가시켜 사용을 해주어야 한다. RCC_AHB1PeriphClockCmd 는 GPIO 포트에 연결되있는 버스에 클럭을 인가시켜주는 함수 이다.

이러한 버스에 클럭을 인가시켜주기 위해서는 각각 내가 어떤 주변장치를 사용하는지 와 이 주변장치는 어떤 버스와 연결되어 있는지를 확인할 필요가 있다. 이러한 정보는 🔗 STM32F407 Datasheet 의 page 19 에 수록되어 있는 Figure 5. STM32F40xxx block diagram 을 확인하면 된다.

예를들어 모든 GPIO를 제어하기 위해서는 AHB1 Bus에 클럭을 인가하면된다. 반면 TIM2 혹은 UART나 SPI2 등을 사용하기위해서는 APB1 버스에 클럭을 인가하면된다.

STM32F407VG가 Arm® 32-bit Cortex®-M4 CPU를 채택하고 있어 AMBA와 각 주변장치들이 연결되어있음을 알 수 있다.

이제 GPIO_InitTypeDef 구조체 멤버 변수에대해 확인해 보자.

  • GPIO_Pin: GPIO Port에서 어떤 pin을 사용하지를 정한다. bit or(|)를 이용하여 여러개를 선택 할 수 있다.
  • GPIO_Mode: 총 네가지 값을 가질 수 있다.
    • 인풋(GPIO_Mode_IN): GPIO port에서 선택된 pin을 입력으로 사용한다.
    • 출력(GPIO_Mode_OUT): GPIO port에서 선택된 pin을 출력으로 사용한다.
    • 대체기능(GPIO_Mode_AF): GPIO port에서 선택된 pin을 다른기능을 사용한다. 예를들어 UART 나 SPI 같은 주변장치 기능을 활성화 한다.
    • 아날로그(GPIO_Mode_AN) : 아날로그 모드.
  • GPIO_OType: Output 타입으로 총 2가지를 가질 수 있다.
    • GPIO_OType_PP: Push Pull 타입으로 사용
    • GPIO_OType_OD: Open drain 타입으로 사용
  • GPIO_PuPd: PullUp, PullDown 선택 혹은 비활성하며 3가지값을 가질 수 있다.
    • GPIO_PuPd_NOPULL: 비활성화
    • GPIO_PuPd_UP: Pull Up 레지스터 활성화
    • GPIO_PuPd_DOWN: Pull Down 레지스터 활성화
  • GPIO_Speed: 출력 속도를 결정한다.
    • GPIO_Low_Speed: GPIO_Speed_2MHz
    • GPIO_Medium_Speed: GPIO_Speed_25MHz
    • GPIO_Fast_Speed: GPIO_Speed_50MHz
    • GPIO_High_Speed: GPIO_Speed_100MHz

마지막으로 GPIO_Init 함수를 확인해보자. 이 함수는 두개의 파라미터를 확인하는데 GPIO를 사용하려는 포트 번호 와 GPIO_InitTypeDef 구조체의 주소를 받는다. 이 두 가지의 파라미터를 이용해 원하는 GPIO 포트 레지스터에 각각의 값을 할당하는 역할을 한다.

2.3 STM32F407G-DISC1 GPIO Register 🔬

GPIO를 이용하기위해 STM32F407VG에서 사용하는 Register를 확인해보자 이러한 Register의 설명서를 읽어보기위해서는 🔗 STM32F047 Reference Manual 에서 확인할 수 있다. 우선 page 65에 Table 1. STM32F4xx register boundary addresses 을 확인해보면 GPIO 포트의 실제 주소를 알 수 있다.

우리가 사용하는 LED들은 GPIOD 포트에 12 에서 15번 까지 사용하고 있으므로 관련된 레지스터들은 0x4002 0C00 - 0x4002 0FFF 사이에 존재한다.

간단하게 위 GPIO_InitTypeDef 의 멤버변수와 관련되었던 Register 4가지만 살펴보자.

  • GPIO port mode register (GPIOx_MODER) (x = A..I/J/K): Address offset: 0x00


    offeset이 0x00 이므로 실제 Register의 주소는 0x4002 0C00이다. 이 Register를 이용하면 특정핀의 GPIO Mode를 설정할 수 있다.

    • 00: Input (reset state)
    • 01: General purpose output mode
    • 10: Alternate function mode
    • 11: Analog mode

    우리는 12 ~ 15번을 모두 Out으로 설정했으니 초기화 직후 이 Register의 주소에 있는 값을 읽어보면 0x5500 0000 으로 나타난다.

  • GPIO port output type register (GPIOx_OTYPER) (x = A..I/J/K): Address offset: 0x04

    offeset이 0x04이므로 실제 Register의 주소는 0x4002 0C04 이다. 이 Register를 이용해 Output Type을 설정한다.

    • 0: Output push-pull (reset state)
    • 1: Output open-drain
  • GPIO port output speed register (GPIOx_OSPEEDR) (x = A..I/J/K): Address offset: 0x08

    offeset이 0x04이므로 실제 Register의 주소는 0x4002 0C08 이다. 이 Register를 이용해 Output Speed를 설정한다.

    • 00: Low speed
    • 01: Medium speed
    • 10: High speed
    • 11: Very high speed
  • GPIO port pull-up/pull-down register (GPIOx_PUPDR) (x = A..I/J/K): Address offset: 0x0C

    offeset이 0x0C이므로 실제 Register의 주소는 0x4002 0C0C 이다. 이 Register를 이용해 Pull Up/Pull Down을 설정한다.

    • 00: No pull-up, pull-down
    • 01: Pull-up
    • 10: Pull-down
    • 11: Reserved

지난번 포스팅 🔗 STM32F407G-DISC1 개발일지 (1) 마지막코드를 확인해보면 위 레지스터 주소값에 직접 HEX 값을 할당해 4개의 LED를 점등하는 코드를 확인할 수 있다.

🔗 Cheesam31 GitHub STM32F407VG_Basic Repository(GPIO_Basic)

0개의 댓글