앞 글의 문자형 lcd에도 lcd로부터 정보를 읽어 오는 기능이 있기는 하지만, 대부분의 경우 글자를 출력하는 기능만 실행하면 되므로 여러가지 이유로 lcd 상태를 체크하지 안습니다. 대부분의 문자형 lcd는 영문자와 숫자 일부 일본어 표시가 가능며, 한글을 지원하는 경우는 별로 없습니다. 한글을 표시하려면 그래픽 lcd를 사용해야 합니다. 그래픽으로 화면을 표시하려면 현재 화면에 표시되어 있는 내용과 새로 표시할 내용을 OR 또는 AND 또는 EOR로 표시할 필요가 있습니다. 따라서 대부분의 경우 lcd로부터 정보를 읽어오는 기능이 필요합니다.
STM32CubeMX는 처음 시작할 때 GPIO를 설정하는 루틴을 만들어 주지만, 프로그램 실행 도중에 GPIO를 출력 모드 또는 입력 모드로 바꾸려면 GPIO 설정을 바꿀 수 있어야 합니다. HAL 드라이버를 이용하여 GPIO 설정을 바꾸는 것은 비교적 간단합니다. 그러나, 기초 사항을 알고 응용법을 익힌 것과 그렇지 않은 것은 커다란 차이가 있으므로 우선 STM32F103의 GPIO에 관한 기본적인 사항을 학습하기로 했습니다.
STM32F1xx의 reference manual 중에서 GPIO에 관한 내용이 약 40쪽 정도 됩니다. 이 내용을 다 다룰 수는 없어 일부만 발췌하여 거의 번역 수준으로 다루어 봅니다.
1. STM32F103의 GPIO
STM32F103CxT6은 최대로 PORT A, PORTB, PORT C, PORT D의 4개의 포트를 사용할 수 있습니다. MCU의 핀의 개수가 많은 모델의 제품들은 더 많은 GPIO를 가지고 있습니다.
1) GPIO의 레지스터
STM32F1xx 시리즈는 PORTA부터 PORTG까지 가질 수 있습니다고, 모든 포트에서 외부 인터럽트를 사용할 수 있습니다. 각 포트의 외부 인터럽트를 사용하려면 포트는 입력 모드이어야 합니다. 외부 인터럽트 설정에 관해서는 나중에 별도의 글로 학습할 예정입니다.
각각의 포트들은 다음과 같은 레지스터를 가지고 있습니다. 각 레지스터의 기능들은 이글 후반부에서 다룹니다.
① 32비트 configuration register 2개(GPIOx_CRL, GPIOx_CRH)
② 32비트 data register 2개(GPIOx_IDR, GPIOx_ODR)
③ 32비트 set/reset register 1개(GPIOx_BSRR)
④ 16비트 reset register 1개(GPIOx_BRR)
⑤ 32비트 locking register 1개(GPIOx_LCKR)
BSRR 레지스터와 BSR 레지스터는 비트 단위로 제어할 수 있으며, 이 방법으로 핀을 제어할 때에는 IRQ 상태를 변화시키지 않기 때문에 인터럽트를 발생시키지 않습니다.
BSRR 레지스터와 BSR 레지스터를 제외한 다른 32비트 레지스터들은 32비트 워드 단위로 프로그래밍해야 합니다. 바이트나 반 워드(half-word) 단위로 프로그래밍할 수는 없습니다.
GPIO 핀들은 내부의 pull-up 혹은 pull-down을 이용할 수도 있습니다.
GPIO 핀들을 push-pull 이나 open-drain 출력 모드로 설정하면 GPIO Output Data register(GPIOx_ODR)의 값에 따라 GPIO 포트의 핀 값이 결정됩니다.
GPIO Input Data register(GPIOx_IDR)은 APB2 버스의 클록 사이클마다 그 때의 핀들의 상태를 갖습니다.
2) GPIO 모드
각각의 GPIO 포트들은 소프트웨어로 다음과 같은 여러 상태로 설정 가능합니다.
① analog 입력 모드
② floating 입력 모드
③ pull-down 입력 모드
④ pull-up 입력 모드
⑤ push-pull 출력 모드
⑥ open-drain 출력 모드
⑦ alternate function push-pull 출력 모드
⑧ alternate function open-drain 출력 모드
포트의 각 핀 모드 설정은 configuration register(GPIOx_CRL, GPIOx_CRH)에 적당한 값을 기록함으로써 이루어 집니다. 각 핀들 마다 configuration bit 2개(CNF[1:0])와 mode bit 2개(MODE[1:0])가 할당되어 있습니다. 이 4개의 비트로 GPIO 각 핀의 모드를 결정합니다. 입력 모드의 경우는 Output Data Register(GPIOx_ODR)의 값을 참조하기도 합니다.
각 모드 설정을 위한 CNF[1:0]과 MODE[1:0], ODR의 값을 정리했습니다.
모드 |
CNF1 |
CNF0 |
MODE[1:0] |
ODR | |
analog 입력 모드 |
0 |
0 |
0 |
0 |
don't care |
floating 입력 모드 |
0 |
1 |
0 |
0 |
don't care |
pull-down 입력 모드 |
1 |
0 |
0 |
0 |
0 |
pull-up 입력 모드 |
1 |
0 |
0 |
0 |
1 |
push-pull 출력 모 드 |
0 |
0 |
00: Reserved |
0 or 1 | |
open-drain 출력 모드 |
0 |
1 |
0 or 1 | ||
Alternative push-pull 출력 모드 |
1 |
0 |
don't care | ||
Alternative open-drain 출력 모드 |
1 |
1 |
don't care |
HAL 드라이버에서는 위의 값을 모두 매크로로 정의하여 사용하기 때문에 굳이 외울 필요는 없습니다.
Reset 후에는 다음의 JTAG 핀들을 제외한 GPIO 포트의 핀들은 floating 입력 모드 상태가 됩니다. (CNFx[1:0]=01b, MODEx[1:0]=00b)
PA15: JTDI pull-up 입력 모드
PA14: JTCK pull-down 입력 모드
PA13: JTMS pull-up 입력 모드
PB4: NJTRST pull-up 입력 모드
3) 입력 모드
I/O 포트를 입력 모드로 설정하면 다음과 같은 상태가 됩니다.
① 출력 버퍼를 사용 불가.
② 슈미트 트리거 입력 활성화.
③ 입력 환경 설정(pull-up, pull-down or floation)에 따라 내부의 pull-up과 pull-down 저항이 사용되거나 관계없는 상태가 됨.
④ APB2 버스 한 클럭마다 IO 핀의 값이 Input Data Register(GPIOx_IDR)에 샘플링됨.
⑤ GPIOx_IDR 레지스터를 읽으면 IO 포트 값을 알 수 있음.
4) 출력 모드
I/O 포트를 출력 모드로 설정하면 다음과 같은 상태가 됩니다.
① 출력 버퍼 사용 가능.
ⓐ open-drain 모드 : 출력 레지스터의 0은 N-MOS를 활성화시키고, 1은 Hi-Z 상태에 있게 함. (P-MOS는 활성화 되지 않음.)
ⓑ push-pull 모드 : 출력 레지스터의 0은 N-MOS를 활성화시키고, 1은 P-MOS를 활성화시킴.
② 슈미트 트리거 입력을 활성화 시킴.
③ 내부의 pull-up과 pull-down 저항은 비활성화됨.
④ APBS 클럭마다 IO 핀의 데이터 Input Data Register(GPIOx_IDR)에 샘플링됨.
⑤ open-drain 모드에서 GPIOx_IDR 값을 읽으면 IO 포트의 값을 알 수 있음.
⑥ push-pull 모드에서 GPIOx_ODR 값을 읽으면 최근에 기록한 값을 알 수 있음.
5) Alternative Function 모드
IO 포트를 Alternative Function 모드로 설정하면 다음과 같은 상태로 됨.
① 출력 버퍼는 설정한 바에 따라 open-drain 또는 push-pull로 켜짐.
② 출력 버퍼는 주변장치로부터 오는 신호(alternative function out)에 의해 구동됨.
③ 슈미트 트리거 입력이 활성화됨.
④ 내부의 pull-up과 pull-down 저항들이 비활성화 됨.
⑤ APBS 클럭마다 IO 핀의 데이터 Input Data Register(GPIOx_IDR)에 샘플링됨.
⑥ open-drain 모드에서 GPIOx_IDR 값을 읽으면 IO 포트 값을 알 수 있음.
⑦ push-pull 모드에서 GPIOx_ODR 값을 읽으면 최근에 기록한 값을 알 수 있음.
포트의 비트를 Alternate Function Output으로 설정한 경우, 출력 레지스터와 단절되고 주변장치의 출력 신호와 연결됩니다. 만약에 주변장치가 활성화 되지 않은 상태에서 소프트웨어로 GPIO 핀을 Alternate Function 출력으로 설정하면, 핀은 어떤 값을 가질지 모르는 상태가 됩니다.
Alternate Function IO들도 다른 핀으로 리매핑할 수 있습니다. AFIO 레지스터에 있는 비트를 소프트웨어로 프로그래밍함으로써 리매핑이 이루어집니다. 이렇게 한 경우에는 더 이상 alternate function은 원래 할당된 핀이 아니라 새로 매핑된 핀에서 동작합니 다.본 글 뒷 부분의 Alternate Function I/O(AFIO)와 디버그 설정에서 자세히 학습할 예정입니다.
6) GPIO Lock
Port Configuration Lock Register(GPIOx_LCKR)의 해당 비트에 1을 기록하면, 해당 비트의 설정이 잠기고 그 비트의 값은 고정됩니다. 비트에 설정된 잠금 기능은 리셋을 해야만 풀립니다. 자세한 내용은 다음의 2. GPIO Register 7) Port configuration lock register에서 다릅니다.
2. GPIO Register
각 포트의 GPIO 기본 주소 값은 다음과 같습니다. 각 레지스터의 실제 주소값은 아래의 기본 주소에 오프셋 주소를 더한 값입니다.
포트 |
기본 주소 |
PORT A |
0x4001 0800 |
PORT B |
0x4001 0C00 |
PORT C |
0x4001 1000 |
PORT D |
0x4001 1400 |
PORT E |
0x4001 1800 |
PORT F |
0x4001 1C00 |
PORT G |
0x4001 2000 |
HAL 드라이버를 이용해서 프로그래밍하는 경우에는 HAL 드라이버에서 구조체나 매크로로 모두 저장해 놓았으므로 주소값을 기억할 필요는 없습니다.
1) Port configuration register low (GPIOx_CRL) (x=A..G)
오프셋 주소 : 0x0000 0000
기본 값 : 0x4444 4444
2) Port configuration register high (GPIOx_CRH) (x=A..G)
오프셋 주소 : 0x0000 0004
기본 값 : 0x4444 4444
위의 두 레지스터의 기능은 앞 1.의 2) GPIO 모드에서 설명한 바 있습니다.
3) Port input data register (GPIOx_IDR) (x=A..G
오프셋 주소 : 0x0000 0008
기본 값 : 0x0000 XXXX
비트 0~15는 각 비트의 값을 가지고 있으며, 비트 16~31은 사용하지 않습니다.
4) Port output data register (GPIOx_ODR) (x=A..G
오프셋 주소 : 0x0000 000C
기본 값 : 0x0000 0000
비트 0~15는 출력할 값을 지정하며, 비트 16~31은 사용하지 않습니다. 이 레지스터는 32비트 워드로 출력을 해야합니다. 비트 단위로 출력하려면 다음의 GPIOx_BSRR 레지스터나 GPIOx_BRR 레지스터를 이용해야 합니다.
5) Port bit set/reset register (GPIOx_BSRR) (x=A..G
오프셋 주소 : 0x0000 0010
기본 값 : 0x0000 0000
비트 0~15는 Bit Set 영역입니다. 이 영역에 1로 지정한 비트의 값을 1로 설정합니다. 이 레지스터의 비트 15는 BS15입니다. 이 비트에 1을 기록하면 비트 15의 값이 1로 설정됩니다. 이때에 다른 비트들 즉 BS0부터 BS14 및 BR0부터 BR15비트 0부터 비트 14까지까지의 값이 0이라면, 다른 15번 핀 이외의 다른 핀의 값은 영향을 받지 않습니다.
비트 16~31은 Bit Reset 영역입니다. 이 영역에 1로 지정한 비트의 값을 0으로 설정합니다. 비트 30은 BR14입니다. 이 비트에 1을 기록하면 비트 14가 0으로 설정됩니다.
6) Port bit reset register (GPIOx_BRR) (x=A..G
오프셋 주소 : 0x0000 0014
기본 값 : 0x0000 0000
비트 0~15는 GPIOx_BSRR 레지스터의 16~31까지의 역할과 같습니다. 비트 16~31을 사용하지 않습니다. 아마 처음에는 GPIOx_BSRR 레지스터 하나로만 사용하다가, 연산을 한 번이라도 줄이려고 이 레지스터를 추가하지 않았을까 추측해 봅니다.
7) Port configuration lock register (GPIOx_LCKR) (x=A..G
오프셋 주소 : 0x0000 0018
기본 값 : 0x0000 0000
비트 31~17은 사용하지 않습니다.
비트16(LCKK)은 읽기와 쓰기가 모두 가능합니다. 이 비트의 값이 0이면 잠금 기능이 비활성화된 상태입니다. 이잠금 비트의 값이 1이면 잠금 기능이 활성화 된 상태입니다.
실수로 비트가 잠기는 것을 방지하기 위해서 LCKK 비트의 lock 작업은 다음의 순서대로 실행해야 합니다.
① LCKR 레지스터의 LCKK 비트에 1 기록
② LCKR 레지스터의 LCKK 비트에 0 기록
③ LCKR 레지스터의 LCKK 비트에 1 기록
④ LCKR 레지스터의 LCKK 비트에 읽기. LCKK 값 0
⑤ LCKR 레지스터의 LCKK 비트에 읽기. LCKK 값 0
(⑤ 단계는 필수는 아니지만 잠금 기능이 활성화 되었는지 확인하는 것임)
위의 과정 동안 LCKR 레지스터의 LCK[15:0]의 내용에 변화가 없어야 합니다. 잠금 작업 중에 에러가 생기면 잠금 기능은 취소됩니다.
비트 0~15(LCK0~LCK15)를 1로 설정하면 해당 비트의 control register CNF[1:0]과 MODE[1:0]을 잠금 조치합니다. 이로 인하여 해당 비트의 설정은 고정되며, 해당 비트의 값도 고정됩니다. 잠금 조치를 해제하려면 MCU를 리셋해야 합니다.
LCK[15:0] 비트는 읽기, 쓰기가 모두 가능하지만, 쓰기는 LCKK(비트16)이 0일 때에만 가능합니다.
비트를 잠금 조치하는 과정을 정리하면 다음과 같습니다.
① LCKK 비트가 0인지 확인.
② 원하는 LCK 비트를 1로 설정.
③ 위의 LCKK lock 작업 ①~⑤ 실행.
이상으로 STM32F103의 GPIO 다루기(1)을 마칩니다. 다음 글 제3편 GPIO 다루기(2)에서는 AFIO와 GPIO remapping을 다루겠습니다.
'STM32F103' 카테고리의 다른 글
RA8835 GLCD 제어하기(제4편) - RA8835 제어함수 만들기 (0) | 2018.11.15 |
---|---|
RA8835 GLCD 제어하기(제3편) - STM32F103 GPIO 다루기(2) (0) | 2018.11.15 |
RA8835 GLCD 제어하기(제1편) - 회로도와 프로젝트 만들기 (0) | 2018.11.11 |
문자형 LCD 4비트로 제어하기 (GPIO와 Timer2 인터럽트 이용) (2) | 2018.11.11 |
STM32F103C8T6 도착 (0) | 2018.11.11 |