c - 为什么 PLL 不锁定?我的时钟配置是否正确?
问题描述
我正在使用 stm32l412kb 进行 UART 通信。我正在尝试将 USART2 外设时钟配置为 72MHz 频率。stm32 复位后使用 4MHz 的 MSI,然后我使用 PLL 在到达外围设备时将其扩展到 72MHz。
该代码在第一次 PLLRDY 检查时保持不变,因为我假设的 PLL 没有锁定。这可能是由于频率输出太高吗?我是否正确配置了所有内容?我怎么知道使用的是 PLL 而不是 4MHz MSI 或 24MHz HSE?
'''
void configureClocks(){
/*Clock Configuration
* The MSI (at 4MHz) is used as system clock source after startup from Reset.
* */
/*Turning on the medium speed internal clock (making sure it's on)*/
RCC->CR |= RCC_CR_MSION;
RCC->CR |= RCC_CR_MSIPLLEN;
/*Waiting until clock is ready*/
while(!(RCC->CR & RCC_CR_MSIRDY));
/*Selecting the MSI (0010) as the MCU clock output*/
RCC->CFGR &= RCC_CFGR_MCOSEL_Msk;
RCC->CFGR |= (0b0010<<RCC_CFGR_MCOSEL_Pos);
/*Turn off PLL to allow to make changes*/
RCC->CR &= ~(RCC_CR_PLLON_Msk);
/*Make sure PLL is locked*/
while(!(RCC->CR & RCC_CR_PLLRDY));
/*At 4Mhz, (4*36/2 = 72Mhz)*/
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN_Msk | RCC_PLLCFGR_PLLM_Msk);
RCC->PLLCFGR |= (2 << RCC_PLLCFGR_PLLM_Pos) | (36 << RCC_PLLCFGR_PLLN_Pos);
/*Turning back on the PLL clock*/
RCC->CR |= RCC_CR_PLLON;
/*Waiting until clock is ready*/
while(!(RCC->CR & RCC_CR_PLLRDY));
/*Selecting the PLL (0101) as the microcontroller clock output*/
RCC->CFGR &= RCC_CFGR_MCOSEL_Msk;
RCC->CFGR |= (0b0101<<RCC_CFGR_MCOSEL_Pos);
/*Enabling the USART2 peripheral clock.*/
RCC->APB1ENR1 &= ~(RCC_APB1ENR1_USART2EN_Msk);
RCC->APB1ENR1 |= (0b1 << RCC_APB1ENR1_USART2EN_Pos);
/*Enabling the GPIOA port peripheral clock*/
RCC->AHB2ENR &= ~(RCC_AHB2ENR_GPIOAEN_Msk);
RCC->AHB2ENR |= (0b1 << RCC_AHB2ENR_GPIOAEN_Pos);
return;
}
'''
您的回复总是非常感谢,
非常感谢,
哈利
更新,感谢评论:第一个 PLL 检查已更改为:
while(!(RCC->CR & RCC_CR_MSIRDY));
到:
while(RCC->CR & RCC_CR_MSIRDY);
但是,PLL 检查仍然卡在第二个。
解决方案
请参阅参考手册(pdf) 第 6.2.3 节“MSI 时钟”、“使用 LSE(PLL 模式)进行硬件自动校准”和第 6.4.1 节“时钟控制寄存器(RCC_CR)”
您的代码中有:
RCC->CR |= RCC_CR_MSIPLLEN;
但在 MSI 时钟上启用 PLL 模式之前,您需要做两件事:
- 应安装外部低频谐振器或振荡器(例如 32768Hz 时钟石英)
- 正如Bit 2 MSIPLLEN描述中所说:MSIPLLEN 必须在LSE 启用(启用LSEON)并准备好(LSERDY 由硬件设置)后启用。如果LSE 未准备好,有硬件保护可以避免启用MSIPLLEN。
所以,如果你安装了 LSE,首先你必须打开它,然后等待它准备好:
RCC->BDCR |= (RCC_BDCR_LSEON);
/*Make sure LSE is ready*/
while(!(RCC->BDCR & RCC_BDCR_LSERDY));
但可能您不必使用 MSI 的 PLL 功能,因为 USART 对频率偏差的容忍度更高。然后应保持禁用 MSI-PLL 模式。
STM32 MCU 有一些保护机制来避免错误地切换时钟源。某些位在时钟源准备好之前无法设置,或者在时钟源正在使用时无法清除。它们在参考手册的位描述中进行了描述。
因此,请仔细比较您正在执行的所有步骤与手册。
UPD 正如在另一个答案中指出的那样
/*Turn off PLL to allow to make changes*/
RCC->CR &= ~(RCC_CR_PLLON_Msk);
/*Make sure PLL is locked*/
while(!(RCC->CR & RCC_CR_PLLRDY));
禁用时不能锁定 PLL。因此,while 循环将永远运行。
UPD2
在启用 PLL 之前,您忘记设置它的源(PLLCFGR 中的 PLLSRC 位)。IE:
// set MSI as the source for PLL
RCC->PLLCFGR = (RCC->PLLCFGR & ~RCC_PLLCFGR_PLLSRC_Msk) | RCC_PLLCFGR_PLLSRC_MSI;
推荐阅读
- sql-server - 使用关键字约束分配多个外键的快捷方式
- python - 将带有分隔符的数据框展平为变量
- excel - Debug.Print 未打印变量的正确值
- ios - 在 iPhone Xs 上使用更多内存的样式传输模型
- python - 如何在不使用 ram 的情况下对 pynput 中的代码进行循环,这是无限的
- javascript - 显示来自 CDN 的视频
- google-chrome - 无法在 chrome 中看到服务器响应的 cookie
- vb.net - 如何将结构的实例显示为字符串 vb.net?
- java - Maven:模块依赖未解决
- dyld - Mojave 升级后不支持 dyld 部分