08-时钟树.md 8.4 KB

08 时钟树配置(HAL)

目标:理解时钟源结构,配置 SYSCLK = 72MHz(最大频率)

单片机内部结构

MCU 内部结构

STM32 内部包含三大核心部件:CPU 核心(Cortex-M3)、存储器(Flash + SRAM)、外设总线(AHB + APB1 + APB2)。时钟树的任务就是把外部/内部时钟源通过 PLL 倍频、分频器分频后,分配到每个部件。

时钟源

STM32 有 4 个独立的时钟源:

时钟源 符号 典型频率 精度 用途
高速内部振荡器 HSI 8MHz 较差 (±1%) 上电默认时钟,可作 PLL 输入
高速外部晶振 HSE 4~16MHz 精确 (±0.01%) 常用 8MHz 作为 PLL 输入源
低速内部振荡器 LSI 40kHz 较差 独立看门狗 (IWDG)、RTC 备用
低速外部晶振 LSE 32.768kHz 精确 RTC 专用时钟

详细工作原理

PLL 锁相环工作原理

PLL(Phase-Locked Loop,锁相环)通过反馈控制回路,将输入时钟倍频到目标频率:

          ┌──────┐     ┌──────────────┐     ┌──────┐
  f_osc ─→│ /M   │────→│ 相位检测器   │────→│ /P   │──→ f_PLL_out
          └──────┘     │ ┌─ VCO ──┐   │     └──────┘
                       │ │ f_VCO  │   │
                       │ └────────┘   │
                       │ ┌── 反馈分频 ─┐ │
                       │ │    /N      │ │
                       │ └────────────┘ │
                       └────────────────┘

核心公式:

f_VCO = f_osc × N / M
f_PLL_out = f_VCO / P

在 STM32F1 系列中,PLL 的配置参数由 RCC_CFGR 寄存器直接控制:

  • PLL 输入分频 (M):由 PLLXTPRE 位控制,对 HSE 做 /1 或 /2
  • PLL 倍频 (N)PLLMUL[3:0] 位编码,实际乘法系数 = (PLLMUL + 2),范围 ×4 ~ ×16(STM32F103 常用 ×9:8MHz × 9 = 72MHz)
  • PLL 输出分频 (P):F1 系列中输出直接为 SYSCLK(不分频)

典型配置路径:HSE(8MHz) → PLLMUL(×9) → SYSCLK(72MHz)

实际 VCO 频率计算公式(以 STM32F103 为例):

f_VCO = f_HSE × (PLLMUL)  (其中 PLLMUL 为实际倍率值)
  72MHz = 8MHz × 9

寄存器编码公式:
  f_VCO = f_HSE × (PLLMUL_编码值 + 2) / (PLLXTPRE + 1)

其中 PLLMUL_编码值 = 2~15(对应 ×4 ~ ×16)
     PLLXTPRE      = 0~1(对应 /1 ~ /2)

⚠️ VCO 频率有范围限制:STM32F103 的 VCO 要求工作于 48~72MHz 之间。

HSI vs HSE 启动时间

时钟源 启动时间 特点
HSI (8MHz RC) 8µs 上电即就绪,无需等待晶体起振
HSE (晶振) 2ms 需要晶体起振稳定时间,取决于晶振负载电容和质量

HSI 在上电后几乎瞬间可用,因此被选为系统默认时钟源。但 HSI 精度较差(±1%),在需要精确通信(如 USART、USB)时必须切换到 HSE 或 PLL。

CSS 时钟安全系统 (Clock Security System)

CSS 是 STM32 的一个硬件安全机制,监控 HSE 是否正常振荡:

正常状态: HSE 稳定振荡 → CSS 不动作
故障状态: HSE 停振    → CSS 自动切换系统时钟到 HSI
                     → 产生 NMI (不可屏蔽中断)
                     → 用户可在 NMI_Handler 中做紧急处理

CSS 使能后,如果 HSE 因晶振损坏、接触不良或外部干扰停振,硬件自动完成以下操作:

  1. 将系统时钟源(SYSCLK)切换回 HSI(8MHz)
  2. 禁能 HSE
  3. 触发 NMI 中断(即使全局中断已关闭)

在 NMI 中断服务函数中,用户可以:

  • 记录故障日志
  • 尝试重新启动 HSE
  • 切换到备用时钟方案

⚠️ CSS 只能在 HSE 正常工作时使能,如果 HSE 本身未就绪就使能 CSS,会立即触发 NMI。

AHB/APB 桥接与时钟域同步

STM32 内部采用 AHB (高速总线)APB (低速外设总线) 两级总线结构,两者之间通过 AHB/APB 桥 连接:

CPU ──→ AHB ──→ AHB/APB1 桥 ──→ APB1 (≤36MHz)
                 AHB/APB2 桥 ──→ APB2 (≤72MHz)

APB 桥内部包含 FIFO(先入先出缓冲),用于跨时钟域的数据同步:

  • AHB 时钟(HCLK)与 APB 时钟(PCLK)不同步时,桥接器通过 FIFO 缓冲数据
  • 写操作:CPU 将数据写入桥的写缓冲,然后继续执行(不需要等 APB 侧完成)
  • 读操作:桥自动插入等待周期,直到数据从 APB 时钟域同步到 AHB 时钟域

APB 预分频器隐藏规则(定时器 2× 时钟)

APB 预分频器 = 1   →  TIM 时钟 = PCLK(不分频,无加倍)
APB 预分频器 ≠ 1   →  TIM 时钟 = 2 × PCLK(硬件自动加倍)

例:
  APB1 = /2 → PCLK1 = 36MHz → TIM2/3/4/5 时钟 = 2 × 36 = 72MHz
  APB2 = /1 → PCLK2 = 72MHz → TIM1/TIM8 时钟 = 72MHz(无加倍)

MCU内部结构

时钟树

时钟树结构

STM32 时钟树

时钟树的本质是多路选择器 (MUX) + 锁相环 (PLL) + 分频器 (Divider) 组成的时钟分配网络:

HSI (8MHz) ──┐
              ├──→ MUX ──→ SYSCLK ──→ AHB Div ──→ HCLK (CPU, Flash, SRAM)
HSE (8MHz) ──┘                              │
                  ↑                           ├──→ APB1 Div ──→ PCLK1 (≤36MHz)
                PLL x9                        │    外设: TIM2~4, I2C1~2, USART2, etc.
              (8×9=72MHz)                     └──→ APB2 Div ──→ PCLK2 (≤72MHz)
                                                   外设: GPIO, USART1, SPI1, ADC1, TIM1
  • SYSCLK:系统时钟,CPU 运行的主时钟
  • HCLK:AHB 总线时钟,CPU、Flash、SRAM、DMA 共享
  • PCLK1:APB1 总线时钟,低速外设(≤36MHz)
  • PCLK2:APB2 总线时钟,高速外设(≤72MHz)

⚠️ 定时器时钟 = 2× 总线时钟

APB 预分频器有一个隐藏行为:

APB1 预分频 = 1  → TIM 时钟 = PCLK1(36MHz → 定时器 36MHz)  ❌ 本配置
APB1 预分频 ≠ 1  → TIM 时钟 = 2 × PCLK1(36MHz → 定时器 72MHz) ✅ 配 /2 时

当 APB1 分频为 /2 时(72MHz 配置),虽然 PCLK1 = 36MHz,但挂载在 APB1 上的定时器(TIM2/3/4/5/6/7)实际时钟为 2 × 36 = 72MHz。配置定时器时分频要按 72MHz 计算。

同理 APB2 分频 ≠ 1 时(如/2),TIM1/TIM8 也得到 2× 时钟。72MHz 配置下 APB2=/1,所以 TIM1/TIM8 时钟就是 72MHz。

CubeMX 配置(8MHz HSE → 72MHz)

  1. RCC → HSE:Crystal/Ceramic Resonator
  2. 切到 Clock Configuration 页面
  3. 配置路径:
    • HSE:8MHz
    • PLL Source:HSE
    • PLL Mul:x9(8 × 9 = 72MHz)
    • System Clock Mux:PLLCLK
    • AHB Prescaler:/1 → HCLK = 72MHz
    • APB1 Prescaler:/2 → PCLK1 = 36MHz(≤36MHz ✓)
    • APB2 Prescaler:/1 → PCLK2 = 72MHz(≤72MHz ✓)
  4. CubeMX 中红色数字表示超限,需调分频

Flash 等待周期

HCLK 频率与 Flash 等待周期的关系:

HCLK 等待周期
0~24MHz 0 wait (WS=0)
24~48MHz 1 wait (WS=1)
48~72MHz 2 wait (WS=2)

CubeMX 会自动计算并配置 FLASH_ACR 寄存器,不需要手动设置。

验证方法

while (1)
{
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    for (volatile uint32_t i = 0; i < 1000000; i++);  // 软件延时
}

对比默认 8MHz 和配置后 72MHz:

  • 8MHz:LED 闪烁较慢
  • 72MHz:LED 闪烁快约 9 倍

CubeMX ↔ Keil 同步更新

CubeMX 修改时钟后,Keil 需同步:

  1. CubeMX GENERATE CODE → 点 Close
  2. Keil 弹出提示文件已修改 → (全部重新加载)
  3. 重新编译烧录

常见坑点

  • ⚠️ APB1 最高 36MHz,APB2 最高 72MHz,不能超限
  • ⚠️ HSE 若不起振(晶振/电容问题),硬件自动回退到 HSI 8MHz(但 CubeMX 配置可能不生效)
  • ⚠️ 外设时钟来自 APB1/APB2,配置前确认外设挂在哪条总线上
  • ⚠️ 修改时钟后 SysTick 的计数值也被改变,HAL_Delay 仍正常工作