为什么 PLL 没有锁定?我的时钟配置是否正确?

Why is the PLL not locking? Is my clock configuration correct?

我正在使用 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 检查仍然卡在第二个上。

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

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

使用 RCC->CR &= ~(RCC_CR_PLLON_Msk); 禁用 PLL 后 等待 PLLRDY 被清除

你的代码做相反的事情,等到 PLLRDY 被设置,这意味着它被锁定。但是你刚刚禁用了它,所以它不会锁定。

设置好PLLCFGR后,重新开机,等到PLLRDY设置好。这部分在代码中看起来没问题。


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

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

请参阅 Reference Manual (pdf) 第 6.2.3 节 "MSI clock"、"Hardware auto calibration with LSE (PLL-mode)" 和第 6.4.1 节 "Clock control register (RCC_CR)"

你的代码中有:

RCC->CR |= RCC_CR_MSIPLLEN;

但在 MSI 时钟上启用 PLL 模式之前,您需要完成两件事:

  1. 应安装外部 low-frequency 谐振器或振荡器(例如 32768Hz 时钟石英)
  2. 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-loop 将永远 运行。

UPD2

在启用 PLL 之前,您忘记设置它的源(PLLCFGR 中的位 PLLSRC)。即:

// set MSI as the source for PLL
RCC->PLLCFGR = (RCC->PLLCFGR & ~RCC_PLLCFGR_PLLSRC_Msk) | RCC_PLLCFGR_PLLSRC_MSI;