STM32 GPIO 설정 — Push-Pull, Open-Drain, 속도, 풀업/풀다운
STM32 GPIO 모드(Input/Output/AF/Analog), Push-Pull vs Open-Drain, 속도 설정, 풀업/풀다운 완전 정리.
7분 읽기by Henry
stm32gpioembedded
GPIO Input/Output/AF/Analog 모드 비교
4.1 GPIO 4가지 모드
모든 GPIO 핀은 4가지 모드 중 하나로 설정된다:
| 모드 | MODER 값 | 설명 | 사용 예시 |
|---|---|---|---|
| Input | 00 | 외부 신호 읽기 | 버튼, 모터 에러 핀, 인터럽트 입력 |
| Output | 01 | 신호 내보내기 | LED, 모터 Enable, Motor Stop |
| Alternate Function | 10 | 페리페럴에 핀 연결 | UART TX/RX, SPI, CAN, PWM |
| Analog | 11 | 아날로그 입출력 | ADC 입력 (토크센서, 각도센서), DAC |
4.2 Output Type: Push-Pull vs Open-Drain
Push-Pull과 Open-Drain 출력 비교
Output 또는 AF 모드에서 출력 타입을 선택한다:
Push-Pull (PP):
VDD ─── [P-FET] ─┬── 핀 출력
│
GND ─── [N-FET] ─┘
출력 HIGH → P-FET ON, N-FET OFF → VDD 출력 (3.3V)
출력 LOW → P-FET OFF, N-FET ON → GND 출력 (0V)
- 능동적으로 HIGH/LOW 모두 구동
- 대부분의 경우 Push-Pull 사용 (LED, SPI, UART TX, PWM 등)
Open-Drain (OD):
┌── 외부 풀업 저항 ── VDD (또는 5V!)
핀 출력 ──┤
└── [N-FET] ── GND
출력 LOW → N-FET ON → GND 출력
출력 HIGH → N-FET OFF → 풀업 저항에 의해 VDD로 올라감
- LOW만 능동 구동, HIGH는 외부 풀업에 의존
- I2C 통신에 필수 (SDA/SCL)
- 레벨 시프팅: 3.3V MCU에서 5V 장치와 통신 시 사용
4.3 Pull 설정
| 설정 | 효과 | 사용 시기 |
|---|---|---|
| No Pull | 풀업/풀다운 없음 | AF 모드 (페리페럴이 제어), 외부 풀업/풀다운 있을 때 |
| Pull-Up | 내부 ~40kΩ 저항으로 VDD 연결 | 버튼 입력 (액티브 로우), UART RX 유휴 상태 |
| Pull-Down | 내부 ~40kΩ 저항으로 GND 연결 | 플로팅 방지, 기본값 LOW 필요 시 |
4.4 출력 속도
| 속도 | 최대 주파수 | 사용 시기 |
|---|---|---|
| Low | ~12 MHz | GPIO 토글 (LED), 저속 신호 |
| Medium | ~60 MHz | UART, I2C |
| High | ~85 MHz | SPI, SDMMC |
| Very High | ~100 MHz | 고속 SPI, FMC |
⚠️ 규칙: 필요한 최소 속도를 선택한다. 속도가 높을수록 EMI(전자파 간섭)가 증가하고 소비전류가 늘어난다.
- LED, Enable 핀 → Low
- CAN, UART → Medium
- SPI → High 또는 Very High
4.5 HAL 라이브러리로 GPIO 설정
CubeMX가 자동 생성하는 코드의 구조:
/* Core/Src/main.c — MX_GPIO_Init() 함수 내부 */
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO 포트 클럭 활성화 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/* === 예시 1: LED 출력 (PB0) === */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 초기값 LOW
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // Output Push-Pull
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 없음
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 저속 (LED니까)
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* === 예시 2: 버튼 입력 + 인터럽트 (PC13) === */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 하강 에지 인터럽트
GPIO_InitStruct.Pull = GPIO_PULLUP; // 내부 풀업
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* EXTI 인터럽트 활성화 */
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
/* === 예시 3: 모터 Enable 핀 (PD3) === */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN; // 기본 OFF (안전)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
4.6 GPIO 제어 함수
/* 핀 출력 HIGH */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
/* 핀 출력 LOW */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
/* 핀 토글 */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
/* 핀 읽기 */
GPIO_PinState state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
if (state == GPIO_PIN_SET) {
// HIGH 상태
}
4.7 실습: LED 깜빡이기 (첫 번째 테스트)
보드를 만들고 가장 먼저 해야 할 테스트:
/* Core/Src/main.c */
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
// (추가 초기화 코드)
/* USER CODE END 2 */
while (1)
{
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); // LED 토글
HAL_Delay(500); // 500ms 대기
/* USER CODE END 3 */
}
}
LED가 0.5초 간격으로 깜빡이면 다음을 확인한 것이다:
- 전원이 정상 (VDD 3.3V)
- 클럭이 정상 (HSE → PLL → SYSCLK)
- GPIO가 정상 (출력 동작)
- HAL 라이브러리가 정상 (HAL_Delay 동작 = SysTick 정상)
- 플래시 프로그래밍이 정상 (코드가 실행됨)
Henry — 로봇 교육 창시자
모두를 위한 로봇 교육을 꿈꾸는 엔지니어입니다. 하드웨어 브링업부터 AI 지능형 로봇까지, 실제 학습 과정을 기록하고 공유합니다.
기술 여정 함께하기
Comments
Loading comments...