13. Cortex-M · CMSIS · Clock Tree
We graduate from the 8051 to the 32-bit Arm Cortex-M (STM32F103). Thanks to the CMSIS standard, any Cortex-M is accessed similarly at the register level. This track controls registers directly, without HAL/SPL. We lay three foundations for the next seven lessons — Cortex-M structure, the CMSIS header (stm32f10x.h), and the clock tree (HSE→PLL→SYSCLK→AHB/APB) — and adopt the iron rule "enable the peripheral clock via RCC before using it".
What you'll learn
- 1Explain Cortex-M (STM32) vs 8051 differences (width·address·buses)
- 2Know what CMSIS and stm32f10x.h provide
- 3Apply the RCC rule "enable the clock before using a peripheral"
- 4Follow the clock tree (HSE/HSI·PLL·AHB/APB prescalers)
- 5Compute SYSCLK/HCLK/PCLK1/PCLK2 from configuration
Introduction
Versus the 8-bit 8051, register width·address space·peripheral count all widen. This lesson focuses on the foundations (structure·CMSIS·clock tree) for lessons 14–20, using CMSIS standard symbols (RCC->APB2ENR, GPIOC->ODR, SystemCoreClock) for readability·portability.
Key concepts
1) 8051 vs Cortex-M
| Aspect | 8051 | Cortex-M3 (F103) |
|---|---|---|
| Width | 8-bit | 32-bit |
| Clock | ~12MHz | up to 72MHz |
| Registers | SFR (P1·TMOD) | structs (GPIOC->ODR) |
| Peripheral clock | always on | individually enabled via RCC |
The most important new habit is clock gating. STM32 leaves each peripheral clock off by default to save power, so enable it via RCC before writing.
2) RCC — the gateway to clocks
| Bus | Enable register | Peripherals |
|---|---|---|
| APB2 (fast) | RCC->APB2ENR | GPIOA~E·ADC·USART1·TIM1·AFIO |
| APB1 (slow) | RCC->APB1ENR | TIM2~4·USART2/3·I2C·SPI2 |
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN; /* enable GPIOA·GPIOC */3) Clock tree and bus limits
HSE(8MHz) → PLL(×9) → SYSCLK(72MHz) → AHB(/1) → HCLK(72MHz)
→ APB1(/2) → PCLK1(36MHz)
→ APB2(/1) → PCLK2(72MHz)F103 limits: SYSCLK/HCLK ≤ 72MHz, PCLK1(APB1) ≤ 36MHz, PCLK2(APB2) ≤ 72MHz. So the standard config uses APB1 /2 and APB2 /1.
Core example
#include "stm32f10x.h"
int main(void) {
/* STM32 rule: enable the clock before using a peripheral */
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;
/* SystemCoreClock (CMSIS global) holds the core clock (usually 72000000) */
volatile uint32_t heartbeat = 0;
while (1) { heartbeat++; }
}Clock-tree check: HSE 8MHz×9=72MHz → SYSCLK 72M, HCLK 72M, PCLK1 36M, PCLK2 72M. In the simulator, RCC->APB2ENR shows IOPAEN(bit2)·IOPCEN(bit4) set to 0x14.
Common mistakes
Q. I wrote a GPIO register but nothing happens.
A. Most likely the clock is off. Do RCC->APB2ENR |= RCC_APB2ENR_IOPxEN; first to bring the register to life. This is the biggest difference from 8051.
Q. stm32f10x.h isn't found or RCC is undefined.
A. Check CMSIS:CORE and Device:Startup in Manage Run-Time Environment, and that a density macro like STM32F10X_MD is in C/C++ Define.
Q. HSI is 8MHz — how do we get 72MHz?
A. The PLL multiplies. HSE ×9 = 72MHz. system_stm32f10x.c's SystemInit() applies this at startup and records it in SystemCoreClock.
Summary
- STM32 is a 32-bit Cortex-M; enable each peripheral's clock via RCC
- CMSIS stm32f10x.h provides registers as structs and bit macros
- Clock tree: HSI/HSE → PLL → SYSCLK → AHB/APB prescalers → each bus
- F103 limits make APB1 /2 (36MHz), APB2 /1 (72MHz) standard
- Direct register control without HAL/SPL, with CMSIS symbols for readability
Exercises
- For HSE 8MHz × 6, compute SYSCLK/HCLK/PCLK1/PCLK2 (and judge any APB1 limit violation)
- Write RCC code enabling GPIOB·USART1 clocks in one line (name each bus)
- Watch SystemCoreClock to confirm it's 72000000 after startup
All lecture materials and example code (with homework and answers) are openly available on GitHub.
View on GitHub ↗