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

时间:2019-07-10 10:03:11

标签: c configuration stm32 clock

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

3 个答案:

答案 0 :(得分:3)

请参考Reference Manual(pdf)第6.2.3节“ MSI时钟”,“使用LSE(PLL模式)进行硬件自动校准”和第6.4.1节“时钟控制寄存器(RCC_CR)” < / p>

您的代码中有

RCC->CR |= RCC_CR_MSIPLLEN;

但是在MSI时钟上启用PLL模式之前,您有两件事要做:

  1. 应安装外部低频谐振器或振荡器(例如32768Hz时钟石英)
  2. 第2位MSIPLLEN 说明中所述:必须在启用LSE(启用LSEON)并准备好(设置LSERDY)之后启用MSIPLLEN 如果没有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; 

答案 1 :(得分:2)

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

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

设置PLLCFGR后,将其重新打开,然后等待直到设置PLLRDY。这部分在代码中看起来还可以。


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

微控制器时钟输出还有其他作用。可以将其连接到外部引脚,以输出时钟信号,以便在MCU外部使用该信号,例如同步多个MCU。

答案 2 :(得分:0)

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

enter image description here

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