출력 핀이 High와 Low를 모두 능동적으로 구동하는 방식.
구조
VCC
│
[P-MOS] ← High 출력 시 켜짐 (전류를 밀어낸다, push)
│
├──── 출력 핀
│
[N-MOS] ← Low 출력 시 켜짐 (전류를 빨아들인다, pull)
│
GND
두 트랜지스터가 번갈아 켜진다. 둘 다 켜지면 전원이 단락되므로 절대 동시에 켜지지 않도록 설계된다.
open-drain과의 대비
| push-pull | open-drain | |
|---|---|---|
| High 구동 | 능동적(P-MOS) | 불가(풀업 저항이 만든다) |
| Low 구동 | 능동적 | 능동적 |
| 외부 풀업 | 불필요 | 필수 |
| 상승 속도 | 빠르다 | 느리다 (RC 시정수) |
| 여러 출력 연결 | 금지(단락 위험) | 가능(와이어드 AND) |
| 레벨 변환 | 불가 | 가능(풀업 전압을 다르게) |
| 소비 전류 | 스위칭 시에만 | Low일 때 계속 흐름 |
언제 무엇을 쓰나
push-pull 을 쓰는 경우 ✅ LED, 버저 구동 ✅ SPI (SCLK, MOSI, CS) ✅ UART TX ✅ 빠른 상승이 필요한 신호 ✅ 1:1 연결
open-drain 을 쓰는 경우 ✅ I2C (SDA, SCL) — 규격상 필수 ✅ 인터럽트 라인 공유 (여러 장치가 하나의 INT 핀에) ✅ 레벨 변환 (3.3V MCU → 5V 장치) ✅ 릴레이·MOSFET 게이트 구동
여러 출력을 연결하면 안 되는 이유
장치 A가 High(P-MOS 켜짐, VCC 연결) 장치 B가 Low (N-MOS 켜짐, GND 연결)
- VCC에서 GND로 트랜지스터 두 개를 통과하는 경로
- 큰 전류가 흐른다 → 발열 → 소자 파괴
"버스에 여러 마스터가 있으면 open-drain" 이 규칙이다.
슬루 레이트 제어
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 2MHz
// GPIO_SPEED_FREQ_MEDIUM // 25MHz
// GPIO_SPEED_FREQ_HIGH // 50MHz
// GPIO_SPEED_FREQ_VERY_HIGH// 100MHz
빠를수록 좋은 것이 아니다.
가파른 에지 = 넓은 주파수 성분 = EMI 방출 증가
-
- 링잉·오버슈트 증가
-
느린 에지 — = EMI 감소, 신호 무결성 향상
-
- 하지만 고속 통신에는 부족
-
필요한 만큼만 빠르게 설정하는 것이 EMC 대책의 기본이다. LED 구동에 VERY_HIGH를 쓰면 불필요한 노이즈만 만든다.
전류 제한 — 반드시 확인
핀 하나당 최대 전류 : 보통 20~25mA
- 포트 전체 합계 — : 보통 100~150mA 칩 전체 (VDD/VSS) : 데이터시트 확인
LED를 직결하면 안 된다. (3.3V - 2.0V) / 저항 = 원하는 전류 저항 = 1.3V / 10mA = 130Ω
여러 LED를 동시에 켜면 포트 합계 제한에 걸린다. 많이 구동해야 하면 트랜지스터나 LED 드라이버 IC를 쓴다.
소스와 싱크 능력이 다를 수 있다
- 많은 MCU가 싱크(Low로 당기기)를 소스(High로 밀기)보다 잘한다
- LED를 VCC-저항-핀 으로 연결해 Low에서 켜는(active low) 회로가 흔한 이유
데이터시트의 I_OL(싱크)과 I_OH(소스)를 비교해 보면 알 수 있다.
대체 기능 모드
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // Alternate Function Push-Pull
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
UART·SPI 같은 주변장치가 핀을 제어하려면 AF 모드로 설정해야 한다.
GPIO_MODE_OUTPUT_PP로 두면 소프트웨어만 제어할 수 있고
UART가 아무리 전송해도 핀이 움직이지 않는다.
"UART 설정은 다 했는데 파형이 안 나온다" 의 흔한 원인이다.