GPIO User Description
현재 구현에서 학생이 GPIOA/GPIOB 핀을 어떤 레지스터로 조작하고 어디서 확인하는지 연결합니다.
GPIO Datasheet 현재 Trainer 실행 예제 RCC Datasheet EXTI Datasheet ADC User Description TIM User Description Lab Guide
1. 그림에서 먼저 보기
Figure 1의 번호는 아래 표의 같은 번호 행으로 이어집니다. 1은 입력 상태를 읽는 IDR, 2는 출력 논리값을 기억하는 ODR, 3은 ODR을 set/reset하는 BSRR/BRR, 4는 핀별 입출력 방식과 출력 형식을 정하는 CRL/CRH입니다. P-MOS/N-MOS는 레지스터가 아니라 실제 pad를 구동하는 물리 회로입니다.
Figure 1. GPIO input state, output data, atomic set/reset, pin configuration, and physical pad driver
Source reconstruction: RM0008 Rev 21 Figure 13. The numbered IDR, ODR, BSRR/BRR, and GPIOx_CRL/CRH callouts are teaching annotations for this User Description; the unnumbered P-MOS/N-MOS stage is the physical pad driver.
2. 블록 → 레지스터 비트
읽는 순서: 지원되는 항목을 먼저 확인하고, 미지원 항목은 문서 하단의 지원하지 않는 항목에서 확인합니다.
2.1 GPIO 데이터시트 값 읽는 법
Pxy에서 x는 port, y는 pin 번호입니다. 예를 들어 PA0은 GPIOA의 0번 필드, PB3은 GPIOB의 3번 필드를 사용합니다. GPIOx_CRL은 pin 0~7, GPIOx_CRH는 pin 8~15를 설정합니다. 각 핀은 CNF[1:0]:MODE[1:0] 순서의 4-bit 값 하나를 사용합니다. GPIO Datasheet Section 4.1의 pin-number lookup에서 모든 필드 위치를 찾을 수 있습니다.
| 핀 번호 y | MODE/CNF 위치 | IDR / ODR | BSRR set / reset | BRR reset |
|---|---|---|---|---|
| 0..7 | CRL[4y+3:4y] | IDRy[y] / ODRy[y] | BSy[y] / BRy[y+16] | BRy[y] |
| 8..15 | CRH[4(y-8)+3:4(y-8)] | IDRy[y] / ODRy[y] | BSy[y] / BRy[y+16] | BRy[y] |
| PA0 예 | GPIOA_CRL[3:0] CNF0[3:2], MODE0[1:0] | IDR0[0] / ODR0[0] | BS0[0] / BR0[16] | BR0[0] |
| 필드 | 값 의미 | 이 문서에서 쓰는 예 |
|---|---|---|
| MODE[1:0] | 00 = 입력 모드01 = 출력, 최대 10 MHz10 = 출력, 최대 2 MHz11 = 출력, 최대 50 MHz | PA5/PA6 입력은 MODE=00, PA3/PA4 출력은 MODE=10입니다. |
| CNF[1:0] (MODE=00) | 00 = analog input01 = floating digital input10 = pull-up / pull-down input11 = 예약값 | PA1은 0x0(analog), PA5는 0x4(floating)입니다. PA6은 P01에서 0x4 Hall 입력, P02에서 0x0 AS5600 analog 입력입니다. |
| CNF[1:0] (MODE≠00) | 00 = general-purpose push-pull01 = general-purpose open-drain10 = alternate-function push-pull11 = alternate-function open-drain | PA3/PA4/PB0은 0x2, PB1은 0x6, 공식 PA2/PA9 AF 출력은 0xB입니다. |
| 4-bit nibble | 0x0 = analog input0x2 = push-pull output, 2 MHz0x4 = floating input0x6 = open-drain output, 2 MHz0xB = alternate-function push-pull, 50 MHz | 전체 0x0~0xF 의미는 GPIO Datasheet 표를 기준으로 합니다. |
자주 헷갈리는 부분: STM32F103은 이후 계열의 GPIOx_MODER/OTYPER/OSPEEDR/PUPDR 대신 CRL/CRH의 CNF:MODE 4-bit 값을 사용합니다. MODE=00이면 CNF가 입력 형식을 정하고, MODE!=00이면 MODE는 출력 최대 속도이며 CNF가 push-pull/open-drain/alternate-function 형식을 정합니다. MODE의 MHz 값은 PWM 주파수가 아닙니다. Pull 입력에서는 ODRy=0이 pull-down, ODRy=1이 pull-up 방향을 선택합니다.
2.2 그림 블록과 실제 레지스터
레지스터와 필드 / bit 열은 RM0008 데이터시트 표기만 사용합니다. PA5/FAULT_IN 같은 화면 신호 이름과 코드에서 쓰는 값은 설명 칸에서 연결합니다.
| 그림 블록 | 레지스터 | 필드 / bit | 그림에서 하는 일 / 값 의미 | 지원 여부 |
|---|---|---|---|---|
| 1Figure 1 입력 버퍼 → IDR | ||||
| PA5 / PA6 입력값 | GPIOA_IDR | IDR5[5] IDR6[6] | 그림에서: 외부 pad 전압을 digital 0/1로 읽습니다.0 = pin LOW1 = pin HIGH현재 구현에서는 PA5/FAULT_IN과 PA6/HALL_IN이 보드 입력으로 이 값을 만듭니다. | 지원됨 |
| 2Figure 1 ODR → 출력 논리값 저장 | ||||
| PA3 / PA4 출력값 | GPIOA_ODR | ODR3[3] ODR4[4] | 그림에서: 핀에 내보낼 논리값을 기억합니다. ODR에 직접 쓰거나 BSRR/BRR을 쓰면 이 bit가 바뀝니다.0 = push-pull 출력은 LOW 구동1 = push-pull 출력은 HIGH 구동CRL에서 pin이 output mode이고 IOPAEN=1일 때 PA3/DRV_EN, PA4/DRV_DIR pad에 반영됩니다. | 지원됨 |
| PB0 / PB1 출력값 | GPIOB_ODR | ODR0[0] ODR1[1] | 그림에서: 같은 ODR 값이라도 CRL에서 선택한 출력 형식에 따라 pad 동작이 달라집니다.0 = push-pull과 open-drain 모두 LOW 구동1 = push-pull은 HIGH 구동, open-drain은 출력을 놓는 high-impedance 상태현재 구현에는 PB1 외부 pull-up 모델이 없으므로 PB1 open-drain에서 ODR1=1이면 Board와 Graph에 floating으로 표시합니다. | 지원됨 |
| 그 밖의 출력 저장 bit | GPIOA_ODR GPIOB_ODR | ODRy[y] | 그림에서: 각 GPIO pin에 대응하는 출력 논리값을 저장합니다.0 = 저장 bit 01 = 저장 bit 1y=0..15입니다. 현재 구현은 GPIOA/GPIOB ODR 하위 16bit 저장값을 Registers에서 확인할 수 있습니다. 다만 보드에 연결되지 않은 bit는 pad 전압이 아니라 저장값만 지원합니다. | 지원됨 |
| 3Figure 1 BSRR / BRR → ODR 변경 명령 | ||||
| PA3 / PA4 set | GPIOA_BSRR | BS3[3] BS4[4] | 그림에서: BSRR 자체가 출력값을 저장하지 않고, 같은 핀 번호의 ODR bit를 한 번의 write로 1로 바꿉니다.0 write = 변화 없음1 write = 같은 번호의 ODR bit를 1로 set다른 ODR bit를 먼저 읽고 다시 쓰지 않으므로 선택한 bit만 원자적으로 변경합니다. | 지원됨 |
| PA3 / PA4 reset | GPIOA_BSRR | BR3[19] BR4[20] | 그림에서: BSRR의 상위 BR 영역이 같은 핀 번호의 ODR bit를 한 번의 write로 0으로 바꿉니다.0 write = 변화 없음1 write = 같은 번호의 ODR bit를 0으로 resetGPIOA 예제는 BSRR.BR4와 GPIOA_BRR.BR3를 각각 실행해 두 reset 경로를 비교합니다. | 지원됨 |
| 그 밖의 BSRR set/reset bit | GPIOx_BSRR | BSy[y] BRy[y+16] | 그림에서: x 포트의 y번 ODR 저장 bit를 BSRR 하나로 set/reset합니다.BSy 1 write = 해당 ODR bit setBRy 1 write = 해당 ODR bit resetx=A/B, y=0..15입니다. 같은 write에서 같은 y의 BSy와 BRy가 모두 1이면 공식 동작대로 set이 우선합니다. 현재 구현의 보드 연결이 없는 bit는 ODR 저장값만 확인할 수 있습니다. | 지원됨 |
| BRR reset 전용 bit | GPIOx_BRR | BRy[y] | 그림에서: BSRR 상위 BR 영역과 같은 reset 명령을 별도 register에서 제공합니다.0 write = 변화 없음1 write = 같은 번호의 ODR bit를 0으로 resetx=A/B, y=0..15입니다. GPIOA/GPIOB 예제 모두 BRR을 실제로 실행하며, 보드 연결이 없는 bit는 ODR 저장값만 바뀝니다. | 지원됨 |
| 4Figure 1 CRL / CRH → 핀별 입출력 구성 | ||||
| PA3 output mode | GPIOA_CRL | CNF3[15:14] MODE3[13:12] | 그림에서: PA3 pad를 일반 push-pull 출력 드라이버에 연결합니다.CRL[15:12] = 0x2 CNF3=00, MODE3=10, push-pull output 2 MHz이후 ODR3 또는 BS3/BR3가 DRV_EN 값을 결정합니다. | 지원됨 |
| PA4 output mode | GPIOA_CRL | CNF4[19:18] MODE4[17:16] | 그림에서: PA4 pad를 일반 push-pull 출력 드라이버에 연결합니다.CRL[19:16] = 0x2 CNF4=00, MODE4=10, push-pull output 2 MHz이후 ODR4 또는 BS4/BR4가 DRV_DIR 값을 결정합니다. | 지원됨 |
| PA5 / PA6 project modes | GPIOA_CRL | CNF5[23:22] / MODE5[21:20] CNF6[27:26] / MODE6[25:24] | 그림에서: PA5는 두 프로젝트 모두 digital Fault 입력입니다. PA6는 프로젝트별로 모드가 달라집니다.PA5 = 0x4 floating digital inputP01 PA6 = 0x4 HALL_IN / EXTI6P02 PA6 = 0x0 ANGLE_SENSE / ADC1_IN6 analog inputP02에서는 PA6 digital IDR와 EXTI6를 사용하지 않고 AS5600 0..3.3 V를 ADC로 읽습니다. | 지원됨 |
| PA1 analog mode | GPIOA_CRL | CNF1[7:6] MODE1[5:4] | 그림에서: digital 입력 버퍼와 출력 드라이버를 끄고 analog 경로를 엽니다.CRL[7:4] = 0x0 CNF1=00, MODE1=00, analog inputADC1_IN1/CURRENT_SENSE를 쓰기 위한 GPIO 쪽 전제 조건이며 변환 동작은 ADC User Description에서 확인합니다. | 지원됨 |
| PA2 PWM mode | GPIOA_CRL | CNF2[11:10] MODE2[9:8] | 그림에서: timer의 alternate-function 출력을 PA2 pad로 내보내는 경로입니다.CRL[11:8] = 0xB 공식 AF push-pull 50 MHz, PA2의 공식 PA2 기능은 TIM2_CH3CRL[11:8] = 0x2 현재 구현이 사용하는 output 설정현재 구현의 PA2/PWM_OUT은 TIM2_CCR1에 연결된 고정 경로입니다. 공식 TIM2_CH3 AF mux 동작은 구현하지 않습니다. | 지원됨 |
| PB0 output mode | GPIOB_CRL | CNF0[3:2] MODE0[1:0] | 그림에서: PB0 pad를 일반 push-pull 출력 드라이버에 연결합니다.CRL[3:0] = 0x2 CNF0=00, MODE0=10, push-pull output 2 MHzODR0 또는 BS0/BR0가 PB0/STATUS_LED 값을 결정합니다. | 지원됨 |
| PB1 output mode | GPIOB_CRL | CNF1[7:6] MODE1[5:4] | 그림에서: PB1 pad를 일반 open-drain 출력 드라이버에 연결합니다.CRL[7:4] = 0x6 CNF1=01, MODE1=10, open-drain output 2 MHzPB1/USER_OUT은 ODR1=0이면 LOW, ODR1=1이면 외부 pull-up이 없는 released 상태이므로 floating으로 표시합니다. | 지원됨 |
3. 데이터시트 필드 ↔ 현재 코드
| 현재 코드 / 값 | 데이터시트 필드로 해석 | 화면에서 확인 |
|---|---|---|
| RCC->APB2ENR = AFIOEN | IOPAEN | IOPBEN | ADC1EN | GPIOA·GPIOB와 ADC1의 PCLK2 gate를 한 번에 엽니다. | Registers → Clock |
| GPIOA->CRL = 0x40422B00u | PA1·PA6 analog, PA2 AF output, PA3·PA4 push-pull output, PA5 floating input입니다. | Registers → GPIOA_CRL |
| GPIOB->CRL = 0x44444440u | PB0는 NTC용 analog input이고 PB1~PB7은 floating input입니다. | Registers → GPIOB_CRL |
| GPIOA->ODR &= ~(EN | DIR) | ODR3=0, ODR4=0으로 안전 시작합니다. | PA3/DRV_EN LOW, PA4/DRV_DIR CW |
| GPIOA->ODR |= EN 또는 DIR | ODR3 또는 ODR4를 직접 set합니다. | Registers의 GPIOA_ODR, Board pin route |
| GPIOA->ODR &= ~EN 또는 ~DIR | ODR3 또는 ODR4를 직접 clear합니다. 현재 최소 예제는 BSRR/BRR를 사용하지 않습니다. | Registers의 GPIOA_ODR, Board pin route |
4. 현재 Trainer 실행 예제
FW EDIT에 그대로 붙여넣어 PA1·PA6·PB0 입력 mode와 PA2~PA4 출력 mode, PA3·PA4 ODR 변화를 확인합니다. 각 주석의 번호는 위 블록 → 레지스터 비트 표와 연결됩니다.
#include "training_api.h"
static uint32_t gpio_stage = 0u;
static void gpio_init(void)
{
GPIOA->CRL = 0x40422B00u; /* GPIO User Description 4번: PA1·PA6 analog, PA2 AF, PA3·PA4 output */
GPIOB->CRL = 0x44444440u; /* GPIO User Description 4번: PB0 analog, PB1~PB7 floating input */
GPIOA->ODR &= ~(GPIOA_DRV_EN_BIT | GPIOA_DRV_DIR_BIT); /* GPIO User Description 2번: PA3·PA4 ODR=0 */
}
void user_init(void)
{
trainer_clock_init_72mhz(); /* RCC User Description 1~4번: 72 MHz clock 경로 */
RCC->APB2ENR = RCC_APB2ENR_AFIOEN; /* RCC User Description 5번: AFIO gate */
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; /* RCC User Description 5번: GPIOA gate */
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; /* RCC User Description 5번: GPIOB gate */
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* P02 공통 Port API의 ADC1 gate */
RCC->APB1ENR = RCC_APB1ENR_TIM2EN; /* P02 공통 Port API의 TIM2 PWM gate */
gpio_init(); /* GPIO User Description 2번·4번 설정 적용 */
}
void user_loop(void)
{
switch (gpio_stage)
{
case 0u: GPIOA->ODR |= GPIOA_DRV_EN_BIT; break; /* 2번: ODR3 set */
case 1u: GPIOA->ODR |= GPIOA_DRV_DIR_BIT; break; /* 2번: ODR4 set */
case 2u: GPIOA->ODR &= ~GPIOA_DRV_EN_BIT; break; /* 2번: ODR3 clear */
case 3u: GPIOA->ODR &= ~GPIOA_DRV_DIR_BIT; break; /* 2번: ODR4 clear */
default: break;
}
if (gpio_stage < 4u) gpio_stage++;
watch_u32("gpio_stage", gpio_stage);
watch_u32("GPIOA_CRL", GPIOA->CRL); /* 4번 pin mode */
watch_u32("GPIOB_CRL", GPIOB->CRL); /* 4번 pin mode */
watch_u32("GPIOA_IDR", GPIOA->IDR); /* 1번 input value */
watch_u32("GPIOA_ODR", GPIOA->ODR); /* 2번 output latch */
}
5. 사이트에서 확인
바로 위 실행 예제를 실행하고 PA3·PA4 ODR 단계와 PB0 analog mode를 아래 화면에서 확인합니다.
- Registers: Clock 그룹의 IOPAEN/IOPBEN, GPIO mode 그룹의 GPIOA_CRL/GPIOB_CRL, latch/input 그룹의 GPIOA_ODR/GPIOA_IDR/GPIOB_ODR을 확인합니다.
- Board · Lab pin routes: PA3/DRV_EN, PA4/DRV_DIR, PA6/ANGLE_SENSE, PB0/SYSTEM_TEMP를 선택해 P02 route와 voltage를 확인합니다.
- Graph: PA3/DRV_EN과 PA4/DRV_DIR을 선택하면 trace 목록에 자동으로 추가되며 ODR 단계별 변화를 확인합니다.
- Code Watch: GPIOA 예제는 gpio_stage와 GPIOA_ODR에서 PA3·PA4 변화만 확인합니다.
- Code Watch: GPIOB 예제는 RCC_APB2ENR와 GPIOB_CRL에서 PB0 analog mode를 확인합니다.
- Docs / Log: GPIOA_BSRR/BRR와 GPIOB_BSRR/BRR updated 메시지, 그리고 각 Lab pin route voltage 변화를 같이 확인합니다.
6. 지원하지 않는 항목
공식 STM32에는 있지만 현재 보드 경로에서 실행되지 않는 항목을 아래에서 구분합니다.
6.1 그림 번호와 연결되는 미지원 항목
| 그림 블록 | 레지스터 | 필드 / bit | 공식 의미와 현재 구현 범위 | 지원 여부 |
|---|---|---|---|---|
| 그 밖의 입력 bit | GPIOA_IDR | IDRy[y] | 그림에서: 같은 방식으로 각 GPIOA pad의 digital level을 읽습니다.0 = pin LOW1 = pin HIGHy=0..4, 7..15입니다. 공식 STM32 register에는 존재하지만 현재 구현의 주 보드 입력 경로는 아닙니다. | 미지원 |
| PA9 USART1_TX | GPIOA_CRH | CNF9[7:6] MODE9[5:4] | 그림에서: USART1_TX alternate-function 출력을 PA9 pad로 보냅니다.CRH[7:4] = 0xB CNF9=10, MODE9=11, AF push-pull 50 MHz현재 구현은 USART1_DR 전송 로그만 제공하고 별도 PA9 보드 wire는 없습니다. | 미지원 |
| PA10 USART1_RX | GPIOA_CRH | CNF10[11:10] MODE10[9:8] | 그림에서: PA10 pad의 digital 입력을 USART1_RX 경로로 읽습니다.CRH[11:8] = 0x4 CNF10=01, MODE10=00, floating input현재 구현의 COMM_RX 수신은 별도 고정 경로이며 이 GPIO CRH 필드가 동작을 제어하지 않습니다. | 미지원 |
6.2 추가 지원 경계
| 항목 | 공식 STM32 의미 | 현재 구현 경계 | 지원 여부 |
|---|---|---|---|
| GPIOA_LCKR / GPIOB_LCKR | GPIO configuration lock sequence | register 값은 저장할 수 있지만 lock key sequence와 configuration freeze side effect는 모델링하지 않으므로 제어 예제에서 제외합니다. | 미지원 |
| GPIOA_CRH / GPIOB_CRH | pin 8~15의 MODEy/CNFy를 설정합니다. | 값은 저장되지만 현재 보드 출력 경로를 제어하지 않습니다. PA9 TX는 log-only이고 PA10 RX는 고정 수신 경로이므로 실행 가능한 GPIO 제어로 세지 않습니다. | 미지원 |
| GPIOB_IDR | GPIOB pad의 digital 입력값을 읽습니다. | 현재 보드가 구동하는 GPIOB 입력 source가 없습니다. register 표시만으로 입력 경로 지원을 주장하지 않습니다. | 미지원 |
| Input pull-up / pull-down + ODR | STM32F1 input pull-up/pull-down mode에서는 ODRy가 pull 방향을 선택합니다. | 현재 구현은 이 내부 pull resistor 전기 모델을 구현하지 않습니다. 이 경우 ODR을 output pad 구동 예제로 해석하지 않습니다. | 미지원 |
| Full alternate-function mux | 핀별 AF 선택과 remap으로 USART/TIM/SPI 등의 출력 경로를 선택합니다. | 현재 구현은 PA2/PWM_OUT, PA9/PA10 USART 등 고정 교육 경로만 설명하고 full AF remap mux는 실행하지 않습니다. | 미지원 |
전체 0x0..0xF GPIO nibble 의미, PA9/PA10 USART, PA2의 공식 TIM2_CH3, PA1·PA6의 ADC conversion, P01 PA6의 EXTI6 세부 동작은 각각 대응 Datasheet/User Description에서 확인합니다. P02 PA6는 ADC1_IN6 analog mode이며 P01 Hall 경로와 동시에 사용하지 않습니다.