본문 바로가기

stm32 레지스터 직접 접근 (4. GPIO [Output Part 01])

반응형

관련글


잡동사니 세상 :: stm32 레지스터 직접 접근 (4. GPIO [Input]) (tistory.com)

 

stm32 레지스터 직접 접근 (4. GPIO [Input])

관련글 잡동사니 세상 :: stm32 레지스터 직접 접근 (소개) (tistory.com) 잡동사니 세상 :: stm32 레지스터 직접 접근 (0. Microcontroller와 ARM ) (tistory.com) 잡동사니 세상 :: stm32 레지스터 직접 접근 (1..

pkr7098.tistory.com


잡동사니 세상 :: stm32 레지스터 직접 접근 (소개) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (0. Microcontroller와 ARM ) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (1. STM32F10x란) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (2. 프로그램 설치 및 설정) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (3. RCC) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (4. GPIO [Input]) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (5. Exception / Interrupt [설명 & 코드 Part 01]) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (5. Exception / Interrupt [인터럽트 설정 Part 02]) (tistory.com)

stm32 레지스터 직접 접근 (5. Exception / Interrupt [중요 레지스터들 Part 03]) (tistory.com)


서론


기다리던 GPIO를 다루는 시간입니다. GPIO는 임베디드 시스템의 가장 기본적인 기능 중 하나로 GPIO가 없는 MCU는 없다고할 수 있을 정도로 기본 중의 기본적인 기능입니다. STM32에서는 단순한 출력, 입력에서 더 나아가 다음과 같은 기능을 제공합니다.

출력 형태 출력 속도 설명1 설명2
Push-Pull 10 MHz 기본적인 성능을 요구할 때 사용합니다. (평상시) 1일 때는 High,
0일 때는 Low
신호를 출력합니다.
2 MHz Low <-> High 전환이 비교적 느릴 때 사용합니다. (저전력)
50 MHz 통신할 때 등의 고속 전환이 필요할 때 사용됩니다. (고성능)
Open-drain 10 MHz 기본적인 성능을 요구할 때 사용합니다. (평상시) 1일 때는 Floating(unknown),
0일 때는 Low
신호를 출력합니다.
2 MHz Low <-> High 전환이 비교적 느릴 때 사용합니다. (저전력)
50 MHz 통신할 때 등의 고속 전환이 필요할 때 사용됩니다. (고성능)
입력 형태 ODR 상태 설명1 설명2
Input floating 상관 없음 플로팅 상태가 요구될 때 사용하는 모드입니다. .
Input pull-down Low 내부 Pull-down 저항 회로를 사용하는 모드입니다. ODR 비트가 0이어야 합니다.
Input pull-up High 내부 Pull-up 저항 회로를 사용하는 모드입니다. ODR 비트가 1이어야 합니다.

 

이번 포스트는 미리 만들어 둔 예제를 통해 코드와 데이터시트를 분석하면서 진행할 예정입니다.

 

STM32_Examples/Ex_05_GPIO_Output_Open_drain at master · KwangryeolPark/STM32_Examples (github.com)

STM32_Examples/Ex_05_GPIO_Output_Push_pull at master · KwangryeolPark/STM32_Examples (github.com)

 


Output

  Registers

    Code (방식 설정)

  Open-drain

    Code (출력 설정)


참고 자료


STM32F103ZET6 Reference Manual

Section 3.3 [Memory map] (51 page)

Section 9 [General-purpose and alternate-function I/Os] (159 ~ 182 page)

Section 9.5 [GPIO and AFIO register maps] (194 page)

 

 

Output

STM32는 GPIO 출력 속도, 방식을 설정할 수 있습니다. 서론에서 언급했던 것 처럼 출력 속도에는 10, 2, 50 MHz가 있고, 방식에는 Push-pull, Open-drain 방식이 있습니다. 각각의 속도는 MCU가 사용되는 목적에 따라 다음과 같이 나눌 수 있습니다.

용도 속도
평상시 (또는 기본 성능) 10 MHz
저전력 2 MHz
고성능 (또는 통신 핀으로 사용될 경우) 50 MHz

 

보통의 경우 GPIO의 출력 속도는 10 MHz를 사용하기 때문에 앞으로도 특수 기능을 사용하지 않는 이상은 10 MHz를 사용할 예정입니다. 앞으로 알아 볼 USART, I2C 등의 통신을 할 때는 Low <-> High 전환이 빨라야하기 때문에 50 MHz 속도를 사용합니다.

 

출력 속도 외에 출력 방식도 설정할 수 있다고 했습니다. 아두이노에는 없는 기능으로 처음 접하시는 분들은 둘의 차이에 대해 궁금해하실 것입니다. (회로를 보실 수 있는 분들은 더보기 란을 확인해 주세요.)

 

더보기

Push-pull & Open-drain

Reference Manual 

Section 9.1 [GPIO functional description] (160 page)

해당 부분의 Figure 13 (또는 14)를 보시면 다음과 같은 그림이 나와 있습니다.

그림 01 160 page

위의 도면은 GPIO핀 하나의 구조를 보여주고 있습니다. 

중앙 Output dricer 부분이 Output의 구조를 보여주고 있습니다. 여기서 Output control 박스가 GPIO의 출력 신호를 결정하고, 방식을 정합니다. 보다 자세한 설명을 위해 이를 확대하겠습니다.

 

그림 02 160 page

위의 그림에서 VDD는 3.3v, VSS는 0.0v를 의미한다고 여기셔도 무방합니다.

Output control은 1번 라인과 2번 라인을 제어하는 박스(장치)로 3.3v를 출력할지, 0.0v를 출력할지 아니면 Floating 상태로 만들지를 결정합니다.


Push-pull 모드


Push-pull 모드는 밀다라는 뜻의 push와 당기다라는 뜻의 pull로 밀고 당기는 모드라고 할 수 있습니다. 3.3v를 밀고, 0.0v로 당긴다는 의미로 해석할 수 있으며, 우리가 HIGH 신호를 보내고 싶을 때는 push(3.3v), LOW 신호를 보내고 싶은 때는 pull(0.0v)의 기능을 수행하는 모드입니다.

즉 HIGH, LOW 신호를 보낼 때 Output control의 동작과 그에 따른 출력 전압은 다음과 같습니다.

신호 Output control의 동작 트랜지스터 동작 출력 신호
1번 라인 2번 라인 P-MOS N-MOS
HIGH OFF OFF ON OFF HIGH (3.3v)
LOW ON ON OFF ON LOW(0.0v)

 

 

Open-drain 모드


Open-drain 모드는 drain을 열다라는 뜻을 의미합니다. drain을 공기중에 열어(노출)놓는다는 의미로 HIGH 신호를 보낼 때는 Floating(Open) 상태, LOW 신호를 보낼 때는 0.0v를 출력합니다.  

즉 HIGH, LOW 신호를 보낼 때 Output control의 동작과 그에 따른 출력 전압은 다음과 같습니다. 

신호 utput control의 동작 트랜지스터 동작 출력 신호
1번 라인 2번 라인 P-MOS N-MOS
HIGH ON OFF OFF OFF Floating (unknown)
LOW ON ON OFF ON LOW(0.0v)

 

 

일반적인 I/O 기능을 사용할 땐 Push-pull 모드를 사용하며, level shifter와 같이 서로 다른 전압으로 제어해야하는 경우 Open-drain을 사용하기도 합니다.

 

 

방식 동작
Push-pull High 신호를 출력할 때 High 신호가 출력됨
Low 신호를 출력할 때 Low 신호가 출력됨
Open-drain High 신호를 출력할 때 어떤 신호가 나갈지 모름
Low 신호를 출력할 때 Low 신호가 출력됨

 

 

 

Registers

STM32F103ZET6에서 GPIO를 사용하기 위해서는 GPIO의 configuration register low(CRL), configuration register low(CRH) 레지스터를 봐야합니다. 두 레지스터는 같은 기능을 수행하며, 그 기능은 다음과 같습니다.

1. 입출력 방향 설정

2. 특수목적(PWM, 통신 등)으로 사용할 것인가에 대한 설정

3. 출력/입력 방식 설정(출력 속도, 출력 방식 / 입력 방식)

CRL, CRH 둘 모두 같은 기능을 수행하며, 단지 STM32에는 PA0 ~ 15, PF0 ~ 15처럼 각 A ~ G 채널마다 16개의 핀을 담당하기 때문에 이들의 설정을 0 ~ 7은 CRL에서, 8 ~ 15는 CRH에서 설정할 수 있게 나눈 것입니다.

다음은 CRL, CRH의 구조입니다.

그림 03 171 page
그림 04 172 page

CNFn[1:0], MODEn[1:0]이런 것들이 보이는데, 둘의 조합으로 I/O 핀을 설정할 수 있습니다. (소문자 n은 0 ~ 15 사이의 숫자입니다.)

예를 들어 PF2핀을 일반 Push-pull 10 MHz로 동작시키고 싶을 때는  GPIOF의 CRL 레지스터의 CNF2[1:0]을 00, MODE2[1:0]을 01로 설정하면 됩니다.

다음 표의 붉은색 부분이 일반 입출력 모드에 관한 설정입니다.

그림 04 161 page [입출력 모드 지정]

 

그림 05 161 page [출력 속도 지정]

우측의 PxODR 부분을 제외하고 CNF1, CNF0, MODE1, MODE0을 보시면 됩니다. 여기서 CNF1과 CNF0는 CNFn[1:0]에 대응하며, MODE1과 MODE0는 MODEn[1:0]에 대응합니다.

위의 표를 기반으로 이번에는 PG9를 Open-drain, 2 MHz로 설정하고 싶다면 GPIOG의 CRH 레지스터에 CNF9[1:0]을 01로, MODE9[1:0]을 10으로 설정하면 될 것입니다.

 

Code (방식 설정)

코드로 쓰면 다음과 같습니다.

// PG9를 Open-drain, 2 MHz
GPIOG -> CRH = (1 << CNF9) | (2 << MODE9); // 또는 GPIOG -> CRH = (6 << MODE9);도 동일한 기능 수행

 

PF2핀을 일반 Push-pull 10 MHz로 동작시키고 싶을 때

// PF2을 Push-pull 10 MHz
GPIOF -> CRL = (0 << CNF2) | (1 << MODE2); // 또는 GPIOF -> CRL = (1 << MODE2);도 동일한 기능 수행

 

 

 

신호는 output data register(ODR)에서 관장합니다.

CRL 또는 CRH로 방식을 설정했다면, ODR로 신호를 제어합니다. High를 출력하고 싶다면 1을, Low를 출력하고 싶다면 0을 설정하는 방식으로 말입니다.

다음은 ODR 레지스터 구조입니다.

 그림 06 173 page [ODR 구조]

ODR 구조는 CRL, CRH에 비해 간단하게 되어 있는 구조로, PF1에 High 신호를 넣고 싶다면 ODR1을 1로 PF9를 ODR9를 1로 설정하는 방식 제어하면 됩니다. 

ODRn (n은 0 ~ 15)의 특정 비트를 1 또는 0으로 설정하면, Push-pull 또는 Open-drain 방식에 따라 I/O핀에 HIGH, LOW, Floating 신호를 보낼 수 있습니다. 방식과 ODRn에 따른 출력 신호는 다음 표에 의해 결정됩니다.

방식 ODRn 출력 신호
Push-pull 1 HIGH (3.3v)
0 LOW (0v)
Open-drain 1 Floating (Unknow)
0 LOW (0v)

 

Code (출력 설정)

예를 들어 PF8을 Push-pull 10 MHz, HIGH 신호로 만들고 싶으면 다음과 같이 코드를 작성하시면 됩니다.

// PF8을 Push-pull 10 MHz, HIGH
GPIOF -> CRH = (0 << CNF8) | (1 << MODE8);	// Push-pull, 10 MHz로 설정
GPIOF -> ODR = (1 << 8);	// PF8 핀을 HIGH로, 나머지는 LOW로

 

반대로 LOW 신호를 만들고 싶으면 다음과 같이 코드를 수정하시면 됩니다.

// PF8을 Push-pull 10 MHz, LOW
GPIOF -> CRH = (0 << CNF8) | (1 << MODE8);	// Push-pull, 10 MHz로 설정
GPIOF -> ODR = 0;	// 모든 핀을 LOW로

 

위의 두 코드는 ODR의 모든 비트를 수정하기에 좋지 못한 코드입니다.

다음 코드는 PF8 핀만 HIGH, LOW로 수정하는 코드입니다.

// PF8을 Push-pull 10 MHz, HIGH
GPIOF -> CRH = (0 << CNF8) | (1 << MODE8);	// Push-pull, 10 MHz로 설정
GPIOF -> ODR |= (1 << 8);	// PF8 핀만을 HIGH로, 나머지는 유지
// PF8을 Push-pull 10 MHz, LOW
GPIOF -> CRH = (0 << CNF8) | (1 << MODE8);	// Push-pull, 10 MHz로 설정
GPIOF -> ODR &= ~(1 << 8);	// PF8 핀만 LOW로, 나머지는 유지

 

다음 코드는 PF7의 상태를 변경하는 코드입니다. README.md의 주의 사항 부분을  꼭 읽으셔서 오류 없이 동작시키시길 바랍니다.

github 사이트의 STM32_Example을 다운 받으신 후, Ex_05_GPIO_Output_Push_pull과 Ex_05_GPIO_Output_Open_drain을 실행시켜보시면 됩니다.

 

Open_drain

더보기
/*      기본 정보
  * Ex_05_GPIO_Output_Open_drain.c
  * 2021-02-12
  * 박광렬
  * @copyright Copyright (c) Park Kwangryeol All right reserved.
  * https://pkr7098.tistory.com/165
  * pkr7098@gmail.com
*/
/*      설명
  GPIO를 다루는 예제입니다.
  
  Open103Z 보드 우측 LED 부분의 위에서 2 번째 LED를 사용합니다.  
  해당 LED는 STM32 칩의 PF7핀에 연결되어 있습니다.
  
  PF7핀을 사용하기 위해 GPIOF에 클럭을 인가하고, Open-drain, 100 MHz 모드로 설정합니다. 
  
  모든 설정이 끝났으면 PF7에 HIGH와 LOW 신호를 반복적으로 보냅니다.
*/

#include "gpio.h"
#include "rcc.h"

void Delay(unsigned long delay);        // 임시로 만든 Delay 함수입니다.

int main(void) {
  
  RCC -> APB2ENR = (1 << IOPFEN);       // GPIOF에 클럭을 인가합니다.

  GPIOF -> CRL = (5 << MODE7);          // PF7핀을 Push-pull, 10 MHz 모드로 설정합니다.
  
  while(1) {
    GPIOF -> ODR = (1 << 7);              // PF7핀에 HIGH 신호를 보냅니다.
    Delay(0xFFFFFF);
    GPIOF -> ODR = 0;              // PF7핀에 HIGH 신호를 보냅니다.
    Delay(0xFFFFFF);
  }
  
  return 0;
}


void Delay(unsigned long delay) {
  for(; delay; delay--) ;
}

 

PF7 Open-drain 10 MHz High <-> Low 영상

동영상 01 [Open-drain]

Open-drain은 앞에서 설명한 것처럼 HIGH에는 Floating, LOW에서는 Low (0.0v) 신호를 보내기 때문에 결과적으로 동영상에서는 LED가 켜지지 않습니다. High (3.3v)를 출력할 수 없으니까요.

 

다음은 멀티미터로 Floating, Low 상태가 되는지 확인하는 영상입니다.

Floating일 때는 전압이 2.0 ~ 9.0 mV를 왔다 갔다 하는 것을 확인할 수 있습니다.

Low일 때는 전압이 0.2 ~ 0.3 mV로 유지되는 것을 확인할 수 있습니다.

 

동영상 02 [Open-drain multimeter]

 

 

Push-pull

더보기
/*      기본 정보
  * Ex_05_GPIO_Output_Push_pull.c
  * 2021-02-12
  * 박광렬
  * @copyright Copyright (c) Park Kwangryeol All right reserved.
  * https://pkr7098.tistory.com/164
  * pkr7098@gmail.com
*/
/*      설명
  GPIO를 다루는 예제입니다.
  
  Open103Z 보드 우측 LED 부분의 위에서 2 번째 LED를 사용합니다.  
  해당 LED는 STM32 칩의 PF7핀에 연결되어 있습니다.
  
  PF7핀을 사용하기 위해 GPIOF에 클럭을 인가하고, 많이 사용되는 Push-pull, 100 MHz 모드로 설정합니다. 
  
  모든 설정이 끝났으면 PF7에 HIGH와 LOW 신호를 반복적으로 보냅니다.
*/

#include "gpio.h"
#include "rcc.h"

void Delay(unsigned long delay);        // 임시로 만든 Delay 함수입니다.

int main(void) {
  
  RCC -> APB2ENR = (1 << IOPFEN);       // GPIOF에 클럭을 인가합니다.

  GPIOF -> CRL = (1 << MODE7);          // PF7핀을 Push-pull, 10 MHz 모드로 설정합니다.
  
  while(1) {
    GPIOF -> ODR = (1 << 7);              // PF7핀에 HIGH 신호를 보냅니다.
    Delay(0xFFFFF);
    GPIOF -> ODR = 0;              // PF7핀에 HIGH 신호를 보냅니다.
    Delay(0xFFFFF);
  }
  
  return 0;
}


void Delay(unsigned long delay) {
  for(; delay; delay--) ;
}

 

PF7 Push-pull 10 MHz High <-> Low 영상

 

동영상 03 [Push-pull]

 

Open-drain 때와는 다르게 HIGH일 때 High (3.3v), LOW일 때 Low(0.0v)가 출력되기 때문에 LED가 정상적으로 켜지는 것을 확인할 수 있습니다.

 

 

반응형