我正在使用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检查仍然卡在第二个检查上。
答案 0 :(得分:3)
请参考Reference Manual(pdf)第6.2.3节“ MSI时钟”,“使用LSE(PLL模式)进行硬件自动校准”和第6.4.1节“时钟控制寄存器(RCC_CR)” < / p>
您的代码中有
RCC->CR |= RCC_CR_MSIPLLEN;
但是在MSI时钟上启用PLL模式之前,您有两件事要做:
因此,如果您已安装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)