为啥 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-&gt;CR &amp;= ~(RCC_CR_PLLON_Msk); 禁用PLL 后等到PLLRDY 被清除

您的代码执行相反的操作,等到设置了PLLRDY,这意味着它已被锁定。但是你刚刚禁用了它,所以它不会锁定。

设置PLLCFGR 后,将其重新打开,并等待PLLRDY 设置完毕。这部分在代码中看起来没问题。


当 PLL 以所需的速度运行时,您应该将 系统时钟开关 (RCC_CFGR_SW) 设置为 PLL 而不是微控制器时钟输出,以使您的系统在 PLL 时钟上运行。

微控制器时钟输出做其他事情。它可以连接到外部引脚,以输出时钟信号以在 MCU 外部使用它,例如同步多个 MCU。

【讨论】:

非常感谢,代码不再粘在那里。但是,代码没有通过第二次检查。【参考方案3】:

我总是使用 Cube 来查看时钟树。我也使用寄存器 - 但该工具非常方便,它可以防止许多愚蠢的错误,因为它会让您知道值是否超出推荐值。

PS 这应该是评论,但我想放图片。所以请不要UV或接受

【讨论】:

是的,谢谢,这是我通常使用的,但我正在尝试学习如何在没有它的情况下进行配置。 我并不是说要使用 HAL 来初始化 - 只是为了查看值 :)

以上是关于为啥 PLL 不锁定?我的时钟配置是不是正确?的主要内容,如果未能解决你的问题,请参考以下文章

vivado pll 中locked的输出原理

SylixOS 基于ZYNQ的时钟频率修改详解

总结:使用pll来进行“异步复位,同步释放”

(转)频谱仪测试pll锁定时间

为啥我的stm32 的tim3 1ms中断时间不准

FPGA中为啥要用分频器进行分频