多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

RIOT STM32 时钟树配置详解:从 SYSCLK 源选择到 PLL、APB 与 MCO 参数的完整实践指南

RIOT STM32 时钟树配置详解:从 SYSCLK 源选择到 PLL、APB 与 MCO 参数的完整实践指南 RIOT STM32 时钟树配置详解从 SYSCLK 源选择到 PLL、APB 与 MCO 参数的完整实践指南【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT本文以 RIOT 仓库中 STM32 CPU 模块的官方文档 cpu/stm32/doc.md 为主体系统讲解 RIOT 在 STM32 系列上配置系统时钟的方法如何选择 SYSCLK 时钟源HSE/HSI/MSI/PLL、如何按芯片家族设置 PLL 的 M/N/P/Q/R 或预分频/倍频参数、如何调整 APB1/APB2 分频以及如何配置 MCO 时钟输出。读完本文后你将能够对照芯片参考手册为任意受支持的 STM32 家族设定精确时钟并理解这些配置常量在 RIOT 源码中的实际作用位置stmclk_*初始化链路与 Kconfig 默认值。1. 适用范围RIOT 支持的 STM32 家族RIOT 的 STM32 CPU 模块包含 STM32 各芯片家族的代码与定义文档明确列出支持的家族为F0、F1、F2、F3、F4、F7、G0、G4、L0、L1、L4、L5 和 WB。所有下文描述的时钟常量都可以通过CFLAGS从命令行或应用 Makefile 中配置见 cpu/stm32/doc.md。从源码结构看仓库中的时钟实现覆盖面实际上更广时钟配置文件目录 cpu/stm32/kconfigs 下按家族划分了c0、f0、f1、f2、f3、f4、f7、g0、g4、h7、l0、l1、l4、l5、mp1、u3、u5、wb、wl等子目录其中还存在f0f1f3g0g4l0l1l4wbwl、f2f4f7mp1、g4l4l5、l4l5wx等跨家族共享目录时钟实现代码目录 cpu/stm32/stmclk 提供了每个家族组的stmclk_*.c源文件见下文第 2.2 节。可以推断这些c0、h7、mp1、u3、u5、wl家族是后续补充进时钟框架的文档列出的 13 个家族是核心支持范围。配置时钟前文档给出的首要建议是先阅读目标 CPU 的参考手册了解其时钟树结构与可配置项再对照下文的常量进行设置。2. 时钟配置机制与初始化链路2.1 统一入口stmclk_init_sysclk()对外接口定义在 cpu/stm32/include/stmclk.h核心函数是stmclk_init_sysclk()。头文件注释描述了它的标准动作序列使能 HSI使用 HSI 作为系统时钟确保进入一个确定的状态配置 Flash 等待状态wait states与 AHB/APB 总线分频可选使能 HSE / MSI配置 PLL将系统时钟切换到 PLL若 HSI 未被使用则将其关闭。调用时机可以从 cpu/stm32/cpu_init.c#L376 确认CPU 初始化流程cpu_init()中直接调用stmclk_init_sysclk()也就是说时钟树在系统启动早期即按配置常量建立完成。同一头文件还定义了若干配套接口函数作用备注stmclk_enable_hsi()/stmclk_disable_hsi()使能/禁用 HSI禁用前会检查 HSI 是否正在驱动 SYSCLK 或 PLL避免误关stmclk_enable_lfclk()/stmclk_disable_lfclk()配置并启用/禁用低速时钟域低速时钟输入可为 LSE 或 LSI在板级periph_conf.h中配置stmclk_dbp_unlock()/stmclk_dbp_lock()/stmclk_dbp_is_locked()解锁/锁定/查询备份域写访问操作 RTC、备份寄存器等备份域资源前需要解锁这些常量由板级periph_conf.h配置的说法与头文件注释一致而本文第 36 节重点介绍的是作用于时钟树本身的家族级常量。2.2 按家族分治的时钟实现cpu/stm32/stmclk 目录下的源文件按时钟架构差异分族实现stmclk_f2f4f7.cF2/F4/F7 家族M/N/P/Q/R 型 PLLstmclk_f0f1f3.cF0/F1/F3 家族预分频倍频型 PLLstmclk_l0l1.cL0/L1 家族stmclk_l4wx.c 与 stmclk_l5.cL4、L5 家族stmclk_gx.cG0/G4 家族以及 stmclk_c0.c、stmclk_h7.c、stmclk_mp1.c、stmclk_u3.c、stmclk_u5.c、stmclk_common.c 等对应 C0、H7、MP1、U3、U5 家族与公共逻辑。这种一个时钟架构一个源文件的组织方式意味着不同家族的常量命名虽有差异如 L0/L1 用CONFIG_CLOCK_PLL_DIVF0/F1/F3 用CONFIG_CLOCK_PLL_PREDIV但都汇入同一条stmclk_init_sysclk()初始化链路。3. SYSCLK 系统时钟源选择文档指出所有 STM32 CPU 都带有时钟配置代码和宏。虽然 SYSCLK 可用的输入时钟源有多种但同一时刻只能使用一种。RIOT 提供的四大时钟源如下HSEHigh Speed External高速外部晶振是否存在取决于板级硬件由板级常量CONFIG_BOARD_HAS_HSE指明外部晶振频率Hz由CONFIG_CLOCK_HSE指定要直接以 HSE 作为系统时钟将CONFIG_USE_CLOCK_HSE置 1。HSIHigh Speed Internal高速内部振荡器频率按家族为 8MHz 或 16MHz要直接以 HSI 作为系统时钟将CONFIG_USE_CLOCK_HSI置 1。MSIMulti-Speed Internal多速内部振荡器仅 L0、L1、L4、L5、WB 家族可用要直接以 MSI 作为系统时钟将CONFIG_USE_CLOCK_MSI置 1MSI 频率Hz由CONFIG_CLOCK_MSI指定。PLL锁相环提供精细可配、可达到精确且高主频的时钟源在 RIOT 中PLL 是 SYSCLK 的默认时钟源将CONFIG_USE_CLOCK_PLL置 1 即选择 PLL默认值。3.1 Kconfig 中的默认值与依赖文档中所述常量在现仓库中由 Kconfig 承载核心定义在 cpu/stm32/kconfigs/Kconfig.clk可以看到时钟源选择是一个choice块default USE_CLOCK_PLL印证了PLL 为默认 SYSCLK 源USE_CLOCK_HSE带有depends on BOARD_HAS_HSE——即没有外部晶振的板子根本无法选择 HSE与文档中CONFIG_BOARD_HAS_HSE的板级约束完全对应CLOCK_HSE的默认频率按家族区分G0、G4、L0、L1、MP1 家族默认 24000000 Hz其余默认 8000000 Hz。3.2 PLL 输入源的选择规则文档给出的 PLL 输入源规则是时钟配置中最容易踩坑的点通用规则若板子提供 HSEHSE 自动被选为 PLL 的输入源否则选用 HSI。L4 与 WB 的特殊规则PLL 输入源可以在 HSE、HSI、MSI 三者中显式选择默认 MSI。通过以下常量之一置 1 来配置CONFIG_CLOCK_PLL_SRC_HSICONFIG_CLOCK_PLL_SRC_HSECONFIG_CLOCK_PLL_SRC_MSI4. PLL 参数配置两种体系文档将 STM32 的 PLL 划分为两种参数体系这是理解各家族 Kconfig 文件差异的钥匙。4.1 M/N/P/Q/R 参数体系F2/F4/F7、G0/G4、L4/L5/WB对stm32f[2|4|7]、stm32g[0|4]、stm32l[4|5|wb]PLL 可配置参数为M输入分频器、N倍频器、P/Q/R输出分频器R 可选在F2/F4/F7上P 输出分频得到的时钟用作 SYSCLK 输入Q 输出分频得到的时钟可用作 48MHz如 USB/SDIO在G0/G4 与 L4/L5/WB上R 输出分频得到的时钟用作 SYSCLK 输入对应配置常量为CONFIG_CLOCK_PLL_M、CONFIG_CLOCK_PLL_N、CONFIG_CLOCK_PLL_P、CONFIG_CLOCK_PLL_Q、CONFIG_CLOCK_PLL_R。这些常量如何落地到寄存器查看 cpu/stm32/stmclk/stmclk_f2f4f7.c 可以看到Kconfig 值被直接拼装进RCC_PLLCFGR的位段#define PLL_M (CONFIG_CLOCK_PLL_M RCC_PLLCFGR_PLLM_Pos) #define PLL_N (CONFIG_CLOCK_PLL_N RCC_PLLCFGR_PLLN_Pos) #define PLL_P (((CONFIG_CLOCK_PLL_P / 2) - 1) RCC_PLLCFGR_PLLP_Pos) #define PLL_Q (CONFIG_CLOCK_PLL_Q RCC_PLLCFGR_PLLQ_Pos) #define PLL_R (CONFIG_CLOCK_PLL_R RCC_PLLCFGR_PLLR_Pos)注意PLL_P宏中的(P/2) - 1编码——寄存器值与逻辑分频比 2/4/6/8 的映射并非线性直接写入修改CLOCK_PLL_P时只需按分频比填写寄存器编码由stmclk层完成。同文件还显示F2/F4/F7 家族额外支持PLLI2S 与 PLLSAI两套独立 PLL 参数CONFIG_CLOCK_PLLI2S_M/N/P/Q/R、CONFIG_CLOCK_PLLSAI_M/N/P/Q/R在未显式配置时有默认值例如 PLLI2S 的 P/Q/R 默认 8注释标明其用途分别为 SPDIF-Rx 时钟 48MHz、USB/SDIO/SDMMC 备用 48MHz 时钟、I2S 时钟 48MHz。如果你的应用需要精确 48MHz 的 USB/I2S/SAI 时钟这一层也是可配置面。4.2 预分频 倍频参数体系F0/F1/F3、L0/L1对stm32f[0|1|3]与stm32l[0|1]PLL 只由一个预分频参数和一个倍频参数构成CONFIG_CLOCK_PLL_DIVL0、L1或CONFIG_CLOCK_PLL_PREDIVF0、F1、F3——输入预分频CONFIG_CLOCK_PLL_MUL——倍频。对应实现分别在 cpu/stm32/stmclk/stmclk_f0f1f3.c 与 cpu/stm32/stmclk/stmclk_l0l1.c。4.3 以 F4 家族为例查看 Kconfig 中的 PLL 默认参数家族级 PLL 参数在 cpu/stm32/kconfigs/f4/Kconfig.clk 中定义需打开CUSTOM_PLL_PARAMS选项Configure PLL parameters后才会暴露可配置界面。以 F4 为例仓库给出了大量按HSE 频率 × 目标主频档组合的默认值可直接作为选型参考CLOCK_PLL_MCLOCK_MAX_84MHZ或100MHZ档且 HSE25MHz 时默认 25CLOCK_MAX_180MHZ档且 HSE16MHz 或 12MHz 时默认 12兜底默认 4CLOCK_PLL_N合法范围range 50 432。默认值随 HSE 频率与主频档变化例如 HSE8MHz 且 180MHz 档默认 180即 8MHz/8? 不此处 M 由 Kconfig 另行决定当启用periph_usbdev_clk且芯片无备用 48MHz 时钟源!HAVE_CLOCK_ALT_48MHZ时默认值会自动收敛到能产生精确 48MHz 的组合如 180MHz 档下 HSE16MHz 取 336 而非 360。这说明 RIOT 的默认 PLL 参数并非拍脑袋给定而是围绕板级 HSE 实际频率 目标 SYSCLK USB 48MHz 需求三个约束推导的。自定义 M/N/P/Q/R 时应遵循同样的推理路径并以芯片参考手册中的 PLL 输入/输出频率上下限为边界。F2/F4/F7/MP1 共享的输出分频定义在 cpu/stm32/kconfigs/f2f4f7mp1/Kconfig.clkCLOCK_PLL_Pchoice 提供 2/4/6/8 四档MP1 固定 3F4 84MHz 档默认 4其余默认 2CLOCK_PLL_Q注释标明其用于USB OTG FS 与 SDIO 时钟合法范围range 2 15默认值按家族与主频档取值F2 默认 5、F4 100MHz 档默认 4、F7 默认 9 等。5. APB1/APB2 总线分频文档说明APB 分频器用于计算 PCLK1 与 PCLK2 的时钟值配置方法CONFIG_CLOCK_APB1_DIV与CONFIG_CLOCK_APB2_DIV——直接填入频率分频系数即可F0 与 G0 家族没有 APB2在这些家族上设置CONFIG_CLOCK_APB2_DIV不产生任何效果。Kconfig 层cpu/stm32/kconfigs/Kconfig.clk将这两个分频器组织为 1/2/4/8/16 五档的 choice 选项并给出了按家族区分的工程默认值APB1F2、F4180MHz 档、F7、L4、L5、U5、WB、WL 默认/4F1、F3、F4其余档位、MP1 默认/2其余家族默认/1APB2depends on !CPU_FAM_G0 !CPU_FAM_F0从配置层面直接禁用了 F0/G0与文档APB2 不可用的说明一致F2、F4180MHz 档、F7、L4、L5、U5、WB、WL、MP1 默认/2其余默认/1。这些默认值体现的通用原则是高频家族把 APB 域分得低一些以释放外设带宽与主频空间低频/简单家族则保持 1:1。调整CLOCK_APB1_DIV/CLOCK_APB2_DIV前请核对目标外设定时器、USART、SPI 等允许的最高 PCLK 频率。6. MCOMicrocontroller Clock Output配置MCO 将芯片内部时钟引出到指定引脚常用于用示波器/逻辑分析仪验证时钟配置结果。文档给出的配置方法如下MCO1PA8置 1CONFIG_CLOCK_ENABLE_MCO1使能 MCO1CONFIG_CLOCK_MCO1_PRE指定 MCO1 预分频默认 1可选时钟源为 HSE、HSI、PLL默认。分别置 1 以下常量来选择源CONFIG_CLOCK_MCO1_USE_HSECONFIG_CLOCK_MCO1_USE_HSICONFIG_CLOCK_MCO1_USE_PLLMCO2PC9置 1CONFIG_CLOCK_ENABLE_MCO2使能 MCO2CONFIG_CLOCK_MCO2_PRE指定 MCO2 预分频默认 1可选时钟源为 HSE、SYSCLK、PLLI2S、PLL默认文档列出的源选择常量写作CONFIG_CLOCK_MCO1_USE_HSE、CONFIG_CLOCK_MCO1_USE_SYSCLK、CONFIG_CLOCK_MCO1_USE_PLLI2S、CONFIG_CLOCK_MCO1_USE_PLL此处沿用原文档的命名实际配置时请以对应家族 Kconfig 中的实际符号为准。从源码结构看MCO 的 Kconfig 定义位于 cpu/stm32/kconfigs/f0f1f3g0g4l0l1l4wbwl/Kconfig.clk覆盖 F0/F1/F3/G0/G4/L0/L4/WB/WL 家族PA8 引脚CLOCK_ENABLE_MCO打开后源选择 choice 提供PLLCLK默认、HSE、HSI、SYSCLK以及按家族条件启用的LSEG0/G4/L0/L1/L4/WB/WL、LSI同上、MSIL0/L1/L4/WB/WL预分频 choice 提供 1/2/4/8/16 五档且 F0/F1/F3/G0 额外支持 32/64/128 三档这些家族的CLOCK_MCO_PRE可低至 128 分频。这与文档对 MCO1 的描述互为印证低档位家族的 MCO 预分频范围明显更宽方便把高速时钟降到示波器可测频段。7. 实操路径小结结合本文与仓库内容为某块 STM32 板卡定制时钟的推荐步骤查阅芯片参考手册确定目标 SYSCLK 频率与可用的 HSE 晶振频率确认板级periph_conf.h与 Kconfig 中的BOARD_HAS_HSE、CLOCK_HSE见 cpu/stm32/kconfigs/Kconfig.clk与硬件一致默认使用 PLLUSE_CLOCK_PLL若 L4/WB 需要从 HSI/HSE/MSI 中显式指定 PLL 输入源则按文档第 3.2 节设置CONFIG_CLOCK_PLL_SRC_*需要自定义 PLL 时打开CUSTOM_PLL_PARAMS在家族目录如 cpu/stm32/kconfigs/f4/Kconfig.clk、cpu/stm32/kconfigs/f2f4f7mp1/Kconfig.clk对应的 Kconfig 中按第 4 节的参数体系填写 M/N/P/Q/R 或 PREDIV/MUL并注意 USB 48MHzQ 分频或periph_usbdev_clk约束按目标外设带宽需求选择CLOCK_APB1_DIV/CLOCK_APB2_DIVF0/G0 无 APB2若需验证实际输出频率按第 6 节使能 MCO1/MCO2 并用外设测量。所有常量最终都由 cpu/stm32/stmclk 中对应家族的stmclk源文件在cpu_init()→stmclk_init_sysclk()阶段写入 RCC 寄存器任何配置偏离参考手册允许范围的行为都应在该层暴露这也是排查时钟配置不生效问题时的第一现场。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表