STM32在外部32Mhz晶振下的时钟配置方法
1. 硬件平台
本例程使用的是 STM32F302RDT6 芯片,其时钟配置方法在其它ST单片机中也类似。
2. 实验目的
使用外部 32Mhz 晶振配置系统时钟为 72Mhz。
3. 配置原理
根据STM32F302RD芯片的参考手册,可以查看该芯片的时钟树结构,这里我们配置系统时钟 SYSCLK 为72Mhz,所以这里只需要修改 PREDIV 的分频值为4分频,其它 PLL 倍频等配置和使用8Mhz外部晶振时配置相同。
4. 修改配置
(1)打开工程里的 system_stm32f30x.c 文件,找到 SetSysClock() 函数,进行时钟配置修改。这里我们只需要将外部时钟四分频后得到8Mhz的时钟,所示我们只需要添加 RCC->CFGR2 |= (uint32_t)RCC_CFGR2_PREDIV1_DIV4;来实现时钟的分频。
static void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | (uint32_t)FLASH_ACR_LATENCY_1;
/* HCLK = SYSCLK / 1 */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 1 */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK / 2 */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
/* PLL configuration */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL9);
/*!< PREDIV1 input clock divided by 4 */
RCC->CFGR2 |= (uint32_t)RCC_CFGR2_PREDIV1_DIV4; // add. by zhixiaoxing
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
(2)全局搜索 HSE_VALUE 空定义,在 stm32f30x.h 文件中,这里我们将外部晶振时钟修改为 32000000 Hz
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)32000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
5. 查看总线时钟
在对STM32时钟进行配置后,为了进一步验证配置的正确性,我们可以使用仿真来查看系统各总线的时钟频率。首先在主函数中添加如下代码:
int main(void)
{
RCC_ClocksTypeDef get_rcc_clock;
RCC_GetClocksFreq(&get_rcc_clock); // 获取系统时钟配置
}
通过仿真可以查看各总线时钟的配置频率,如下图所示:
Note:注意一定要修改宏 #define HSE_VALUE ((uint32_t)32000000) /!< Value of the External oscillator in Hz /的值,因为时钟使用该宏定义进行计算。
5. 慎入此坑
在时钟配置时,需要注意的一些问题:
(1)在时钟树任何一个倍频的环节都不能超频,即使后面分频系数较大,还是会导致时钟配置失败;
(2)在配置外部晶振四分频时,发现了一个诡异的问题,CFGR2寄存器一定要在CFGR寄存器之后,否则会导致CGFR2寄存器的值与配置的不符,至今不明其诡异之处?
/* PLL configuration */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL9);
/*!< PREDIV1 input clock divided by 4 */
RCC->CFGR2 |= (uint32_t)RCC_CFGR2_PREDIV1_DIV4; // add. by zhixiaoxing