지난 포스팅에서 MCU 레벨을 마무리했다.
이번 단계는 PAC (Peripheral Access Crate)이다.
들어가기에 앞서, PAC가 어떤 것인지 공부해보자.
RCC : Reset and Clock Control
→ STM32 시리즈에서 칩 내부 모든 주변장치(Peripheral)에 전원(클럭) 공급. 리셋 제어를 담당하는 중앙 제어 블록.
비유
- MCU = 큰 빌딩
- 주변장치(GPIO, USART, I2C…) = 각 방
- RCC = 각 방에 전기 공급하는 분전함
스위치 내리면 방이 꺼짐 (전력 절약)
스위치 올려야만 방 안에 불을 켜거나 기기를 돌릴 수 있음
GPIOA_MODER (0x4002_000) 같은 레지스터를 pac::GPIOA::ptr().MODER 같은 Rust 구조체/메서드로 접근 가능하게 해준다.
- GPIO : General Purpose Input/Output
MCU(마이크로컨트롤러) 핀을 프로그램으로 입력/출력으로 자유롭게 쓸 수 있게 해주는 주변장치.
예: 버튼 입력 받기, LED 켜기, 센서 데이터 읽기, 모터 제어 등.
- GPIOA란?
STM32 시리즈 같은 칩에는 여러 개의 GPIO 포트가 있음:
GPIOA, GPIOB, GPIOC, … 이런 식으로 알파벳으로 구분.각 "포트"는 최대 16개의 핀을 가짐 (핀 번호 0~15).
예: PA5는 "GPIO A 포트의 핀 5"를 의미.즉:
GPIOA = A번 포트
PA5 = A포트의 5번 핀 (Nucleo-F446RE 보드의 LD2 LED가 여기 연결되어 있음)
- 왜 A, B, C로 나눌까?
MCU에는 수십~수백 개의 핀이 있는데, 그걸 그룹으로 묶어서 관리하기 위해.
- STM32F446RE는 GPIOA ~ GPIOI 까지 제공.
A~I 각각 최대 16핀 → 이론적으로 144개 핀까지.
예:
GPIOA 포트 = PA0 ~ PA15
GPIOB 포트 = PB0 ~ PB15
…
- 실제 코드에서
dp.RCC.ahb1enr.modify(|, w| w.gpioaen().set_bit()); // GPIOA 클럭 켜기
dp.GPIOA.moder.modify(|, w| w.moder5().output()); // A포트 5번핀을 출력 모드로
dp.GPIOA.bsrr.write(|w| w.bs5().set_bit()); // A포트 5번핀을 1로 (LED 켜기)여기서:
- RCC.ahb1enr.gpioaen() → GPIOA 포트 자체에 전원(클럭) 공급
- GPIOA.moder5() → GPIOA 포트의 핀5 모드를 설정
- GPIOA.bs5() → GPIOA 포트의 핀5 값을 제어 (Set/Reset)
✅ 정리
GPIOA = STM32 MCU의 A번 포트 (PA0~PA15)
PA5 = GPIOA 포트의 5번 핀, F446RE 보드 LED가 연결된 곳
따라서 “GPIOA”라고 부르면, 그 그룹(레지스터 세트 전체)을 의미하는 거고, “PAx”라고 부르면 그 포트 안의 특정 핀을 가리키는 거야.
우리가 지금 한 것처럼 write_volatile(0x40020000, 1) → 매직 넘버라서 읽기도 어렵고 버그 찾기도 힘듦.
PAC은:
예시
// Cargo.toml
stm32f4 = { version = "0.14.0", features = ["stm32f446"] }
use stm32f4::stm32f446;
fn main() {
let dp = stm32f446::Peripherals::take().unwrap();
// GPIOA 클럭 켜기
dp.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
// PA5를 Output으로
dp.GPIOA.moder.modify(|_, w| w.moder5().output());
// LED On
dp.GPIOA.bsrr.write(|w| w.bs5().set_bit());
}
✅ 정리:
PAC은 칩의 데이터시트를 안전하게 Rust 코드로 옮긴 자동 생성 라이브러리.
→ 덕분에 우리가 “매직 넘버” 없이, IDE 자동완성 도움받아 레지스터를 조작할 수 있음.
→ 보통 직접 PAC만 쓰기보다, 그 위에 얹은 HAL을 같이 씀.
PAC: 하드웨어 레벨 그대로. “레지스터 안전 래퍼”
모든 제어 가능 (풀 컨트롤), 하지만 저수준.
HAL (Hardware Abstraction Layer): PAC을 기반으로 만든 상위 추상화. gpioa.pa5.into_push_pull_output(); 처럼 훨씬 간단.
내부적으로는 PAC 호출.
즉:
PAC = 나사/볼트
HAL = 완성품 드라이버