13. Cortex-M·CMSIS·클럭 트리
8051을 졸업하고 32비트 Arm Cortex-M(STM32F103)으로 무대를 옮깁니다. CMSIS 표준 덕분에 어느 Cortex-M이든 비슷한 방식으로 레지스터에 접근합니다. 이 트랙은 HAL/SPL 없이 레지스터를 직접 제어합니다. 앞으로 7편을 떠받칠 세 토대 — Cortex-M 구조, CMSIS 헤더(stm32f10x.h), 클럭 트리(HSE→PLL→SYSCLK→AHB/APB) — 를 잡고, "주변장치를 쓰기 전에 RCC로 클럭부터 켠다"는 철칙을 익힙니다.
이 강의에서 배우는 것
- 1Cortex-M(STM32)과 8051의 구조 차이(폭·주소·버스)를 설명한다
- 2CMSIS와 stm32f10x.h가 제공하는 심볼을 안다
- 3"주변장치를 쓰기 전에 클럭부터 켠다"는 RCC 규칙을 적용한다
- 4HSE/HSI·PLL·AHB/APB 프리스케일러로 이어지는 클럭 트리를 따라간다
- 5설정값으로부터 SYSCLK/HCLK/PCLK1/PCLK2를 계산한다
소개
8비트 8051과 비교하면 레지스터 폭·주소 공간·주변장치 수가 한 단계 넓어집니다. 이 편은 코드를 많이 쓰기보다 14~20편을 떠받칠 토대(구조·CMSIS·클럭 트리)를 잡는 데 집중합니다. CMSIS 표준 심볼(RCC->APB2ENR, GPIOC->ODR, SystemCoreClock)로 가독성·이식성을 지킵니다.
핵심 개념
1) 8051 vs Cortex-M
| 항목 | 8051 | Cortex-M3(F103) |
|---|---|---|
| 폭 | 8비트 | 32비트 |
| 클럭 | ~12MHz | 최대 72MHz |
| 레지스터 | SFR(P1·TMOD) | 구조체(GPIOC->ODR) |
| 주변장치 클럭 | 항상 켜짐 | RCC로 개별 인에이블 필요 |
가장 중요한 새 습관은 클럭 게이팅입니다. STM32는 전력 절약을 위해 각 주변장치 클럭이 기본 꺼져 있어, 쓰기 전에 RCC로 켜야 합니다.
2) RCC — 클럭을 켜는 관문
| 버스 | 인에이블 레지스터 | 대표 주변장치 |
|---|---|---|
| APB2(고속) | RCC->APB2ENR | GPIOA~E·ADC·USART1·TIM1·AFIO |
| APB1(저속) | RCC->APB1ENR | TIM2~4·USART2/3·I2C·SPI2 |
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN; /* GPIOA·GPIOC 켜기 */3) 클럭 트리와 버스 한계
HSE(8MHz) → PLL(×9) → SYSCLK(72MHz) → AHB(/1) → HCLK(72MHz)
→ APB1(/2) → PCLK1(36MHz)
→ APB2(/1) → PCLK2(72MHz)F103 한계: SYSCLK/HCLK ≤ 72MHz, PCLK1(APB1) ≤ 36MHz, PCLK2(APB2) ≤ 72MHz. 그래서 표준 설정에서 APB1은 /2, APB2는 /1.
핵심 예제
#include "stm32f10x.h"
int main(void) {
/* STM32 철칙: 주변장치를 쓰기 전에 클럭부터 켠다 */
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;
/* SystemCoreClock(CMSIS 전역)에 코어 클럭(보통 72000000)이 들어 있다 */
volatile uint32_t heartbeat = 0;
while (1) { heartbeat++; }
}클럭 트리 계산 검산: HSE 8MHz×9=72MHz → SYSCLK 72M, HCLK 72M, PCLK1 36M, PCLK2 72M. 시뮬레이터 RCC->APB2ENR 에서 IOPAEN(비트2)·IOPCEN(비트4)이 1이 되어 0x14가 됨을 확인합니다.
자주 하는 실수
Q. GPIO 레지스터에 값을 썼는데 아무 일도 안 일어나요.
A. 십중팔구 클럭을 안 켰습니다. RCC->APB2ENR |= RCC_APB2ENR_IOPxEN; 을 먼저 해야 레지스터가 살아납니다. 8051과 가장 다른 점입니다.
Q. stm32f10x.h 를 못 찾거나 RCC가 정의 안 됐대요.
A. Manage Run-Time Environment에서 CMSIS:CORE와 Device:Startup을 체크하고, C/C++ Define에 STM32F10X_MD 같은 밀도 매크로를 넣었는지 확인하세요.
Q. HSI가 8MHz인데 어떻게 72MHz가 되나요?
A. PLL이 체배합니다. HSE를 입력으로 ×9 하면 72MHz입니다. system_stm32f10x.c의 SystemInit()이 startup에서 적용하고 SystemCoreClock에 기록합니다.
정리
- STM32는 32비트 Cortex-M으로 주변장치마다 RCC로 클럭을 켜야 동작한다
- CMSIS stm32f10x.h가 레지스터를 구조체·비트 매크로로 제공한다
- 클럭 트리: HSI/HSE → PLL → SYSCLK → AHB/APB 프리스케일러 → 각 버스
- F103 한계로 APB1은 /2(36MHz), APB2는 /1(72MHz)이 표준
- HAL/SPL 없이 레지스터 직접 제어, CMSIS 표준 심볼로 가독성 유지
과제
- HSE 8MHz × 6 설정에서 SYSCLK/HCLK/PCLK1/PCLK2 를 계산(APB1 한계 위반 여부도 판단)
- GPIOB·USART1 클럭을 한 줄로 켜는 RCC 코드 작성(각각 어느 버스인지 명시)
- SystemCoreClock 을 Watch에 올려 startup 후 값이 72000000인지 확인