← Embedded C 강의 목록으로
🔌
STM32
STM32 · 선수: 12강

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로 클럭부터 켠다"는 철칙을 익힙니다.

STM32Cortex-MCMSISRCC클럭트리PLL
소요 시간
약 1.5~2시간
난이도
📊 중급
선수 조건
🎯 12강
결과물
CMSIS stm32f10x.h로 레지스터를 다루고, RCC로 주변장치 클럭을 켜며, HSE·PLL·프리스케일러로부터 SYSCLK/HCLK/PCLK1/PCLK2를 계산할 수 있습니다.

이 강의에서 배우는 것

  • 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

항목8051Cortex-M3(F103)
8비트32비트
클럭~12MHz최대 72MHz
레지스터SFR(P1·TMOD)구조체(GPIOC->ODR)
주변장치 클럭항상 켜짐RCC로 개별 인에이블 필요
⚠️

가장 중요한 새 습관은 클럭 게이팅입니다. STM32는 전력 절약을 위해 각 주변장치 클럭이 기본 꺼져 있어, 쓰기 전에 RCC로 켜야 합니다.

2) RCC — 클럭을 켜는 관문

버스인에이블 레지스터대표 주변장치
APB2(고속)RCC->APB2ENRGPIOA~E·ADC·USART1·TIM1·AFIO
APB1(저속)RCC->APB1ENRTIM2~4·USART2/3·I2C·SPI2
c
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;  /* GPIOA·GPIOC 켜기 */

3) 클럭 트리와 버스 한계

c
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.

핵심 예제

c
#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 표준 심볼로 가독성 유지

과제

  1. HSE 8MHz × 6 설정에서 SYSCLK/HCLK/PCLK1/PCLK2 를 계산(APB1 한계 위반 여부도 판단)
  2. GPIOB·USART1 클럭을 한 줄로 켜는 RCC 코드 작성(각각 어느 버스인지 명시)
  3. SystemCoreClock 을 Watch에 올려 startup 후 값이 72000000인지 확인
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드(과제·정답 포함)는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗