为啥 PLL 不锁定?我的时钟配置是不是正确?
Posted
技术标签:
【中文标题】为啥 PLL 不锁定?我的时钟配置是不是正确?【英文标题】:Why is the PLL not locking? Is my clock configuration correct?为什么 PLL 不锁定?我的时钟配置是否正确? 【发布时间】:2019-11-19 22:34:10 【问题描述】:我正在使用 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;
'''
非常感谢您的回复,
非常感谢,
哈利
更新,感谢 cmets: 第一个 PLL 检查已更改为:
while(!(RCC->CR & RCC_CR_MSIRDY));
到:
while(RCC->CR & RCC_CR_MSIRDY);
但是,PLL 检查仍然卡在第二个。
【问题讨论】:
您没有选择 PLL 源。请查看我的答案的更新 【参考方案1】:请参阅Reference Manual (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 位)。即:
// set MSI as the source for PLL
RCC->PLLCFGR = (RCC->PLLCFGR & ~RCC_PLLCFGR_PLLSRC_Msk) | RCC_PLLCFGR_PLLSRC_MSI;
【讨论】:
非常感谢您的帮助。我当然错过了将 MSI 设置为 PLLSRC。现在代码运行良好!【参考方案2】:使用RCC->CR &= ~(RCC_CR_PLLON_Msk);
禁用PLL 后等到PLLRDY
被清除。
您的代码执行相反的操作,等到设置了PLLRDY
,这意味着它已被锁定。但是你刚刚禁用了它,所以它不会锁定。
设置PLLCFGR
后,将其重新打开,并等待PLLRDY
设置完毕。这部分在代码中看起来没问题。
当 PLL 以所需的速度运行时,您应该将 系统时钟开关 (RCC_CFGR_SW
) 设置为 PLL 而不是微控制器时钟输出,以使您的系统在 PLL 时钟上运行。
微控制器时钟输出做其他事情。它可以连接到外部引脚,以输出时钟信号以在 MCU 外部使用它,例如同步多个 MCU。
【讨论】:
非常感谢,代码不再粘在那里。但是,代码没有通过第二次检查。【参考方案3】:我总是使用 Cube 来查看时钟树。我也使用寄存器 - 但该工具非常方便,它可以防止许多愚蠢的错误,因为它会让您知道值是否超出推荐值。
PS 这应该是评论,但我想放图片。所以请不要UV或接受
【讨论】:
是的,谢谢,这是我通常使用的,但我正在尝试学习如何在没有它的情况下进行配置。 我并不是说要使用 HAL 来初始化 - 只是为了查看值 :)以上是关于为啥 PLL 不锁定?我的时钟配置是不是正确?的主要内容,如果未能解决你的问题,请参考以下文章