STM32F429xx启动时如何初始化PLLI2S输出50MHz至MCO2作ETH参考时钟?
解决STM32F429在Zephyr下通过PLLI2S输出50MHz到MCO2作为ETH参考时钟的问题
核心思路
Zephyr的时钟初始化有严格的阶段顺序,直接自定义SYS_INIT容易和ETH初始化的时钟依赖冲突,得利用Zephyr的STM32时钟配置逻辑,或者调整初始化阶段,确保PLLI2S在ETH启动前完成配置并输出时钟。
可行方案
方案1:修改STM32时钟配置文件(推荐)
Zephyr针对STM32的时钟配置文件位于boards/arm/<你的板子型号>/stm32f429xx_clock_config.c(自定义板卡则在对应板目录下),直接修改这里的时钟初始化逻辑,在系统时钟切换到180MHz后,手动配置PLLI2S和MCO2:
- 先算好PLLI2S参数:假设外部晶振是25MHz(常见配置),要输出50MHz的话,设置
PLLI2SM=5、PLLI2SN=40、PLLI2SR=4,这样VCO频率为25/5*40=200MHz,分频后正好是50MHz,符合STM32F4的VCO频率范围(192~432MHz)。 - 在
stm32_clock_init函数中,系统时钟切换到180MHz的代码之后,添加以下HAL库代码:
// 配置并使能PLLI2S __HAL_RCC_PLLI2S_CONFIG(RCC_PLLI2SM_DIV5, RCC_PLLI2SN_MUL40, RCC_PLLI2SR_DIV4); __HAL_RCC_PLLI2S_ENABLE(); // 等待PLLI2S锁定 while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET); // 配置MCO2为PLLI2S输出,不分频 HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_PLLI2S, RCC_MCODIV_1);
- 这种方式直接在系统时钟初始化阶段完成配置,ETH启动时参考时钟已经就绪,不会出现冲突。
方案2:调整SYS_INIT的执行阶段
如果不想修改板级时钟配置文件,可以调整自定义初始化函数的执行阶段和优先级,确保它在ETH初始化之前运行:
- 定义初始化函数时指定
PRE_KERNEL_1阶段,并且优先级比默认内核初始化高(比如减10):
static void plli2s_mco2_init(void) { // 这里放和方案1一样的PLLI2S、MCO2配置代码 } SYS_INIT(plli2s_mco2_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT - 10);
- 注意:要确认ETH驱动的初始化阶段(一般是
PRE_KERNEL_2或之后),保证你的初始化函数先执行,避免ETH启动时无参考时钟。
方案3:手动控制ETH初始化
如果上述方案有冲突,可以禁用Zephyr的ETH自动配置,手动控制初始化顺序:
- 在设备树的ETH节点添加
zephyr,disable-autoconfig;,或者设status = "disabled"; - 在
main函数中先执行PLLI2S和MCO2的配置代码,再通过device_get_binding("ETH_0")获取设备句柄,调用eth_init手动初始化ETH驱动。
注意事项
- 计算PLLI2S参数时必须符合STM32F4的时钟规范,VCO频率不能超出192~432MHz的范围。
- 修改配置后要重新编译应用,确保新的时钟逻辑生效。
- 调试时先用示波器确认MCO2输出的是50MHz,再启动ETH模块排查问题。
内容的提问来源于stack exchange,提问作者Fredrik
相关产品推荐
相关产品推荐

