STM32F427xx系列芯片系统时钟讲解
STM32F427xx系列芯片系统时钟讲解
——写代码的Tobem 为了进行通用定时器的设置,有必要先了解STM32F427xx系列芯片的时钟系统。为了实现低功耗(对于每个时钟源来说,在未使用时都可单独打开或者关闭,以降低功耗),STM32F427xx设计了功能完善但却有点复杂的时钟系统,见下图:
图2 STM32F427xx系统时钟树
从图中可以看出,STM32F427xx具有4个时钟源,分别为2个内部时钟源和2个外部时钟源,也可以分为2个高速时钟源和2个低速时钟源,具体为:
1、HSE(高速外部时钟):以外部晶振作时钟源,晶振频率可取范围为4~26MHz,实际电路图中我们采用12MHz的晶振。
2、HSI(高速内部时钟):由内部RC振荡器产生,频率为16MHz。其特点是起振快,在芯片刚上电的时候,就是使用高速内部时钟,但其精度不高,因此,上电之后我们再通过软件配置(SystemInit()函数),转而采用高速外部时钟信号。
3、LSE(低速外部时钟):以外部晶振作时钟源,主要提供给实时时钟模块(RTC),一般采用32.768KHz。
4、LSI(低速内部时钟):由内部RC振荡器产生,频率为32KHz,主要用于驱动独立看门狗,也可选择提供给RTC 用于停机/待机模式下的自动唤醒。
程序在执行主函数main()之前,要先进行堆栈指针SP、程序计数器PC的初始化、设置异常中断向量地址等工作,最后才进入到主函数main()中去执行,这其中包括系统时钟的配置(在startup_stm32f4xx.s启动文件中)。系统时钟的配置由system_stm32f4xx.c文件中的SystemInit()函数完成,配置结果如下:
图3 系统时钟配置情况
从时钟树中可以看到,系统时钟SYSCLK是大部分器件的时钟来源,因此SYSCLK的配置就显得十分重要。SYSCLK可以从三个时钟源中进行选择,分别为HSI、HSE和PLLCLK。HSI 不稳定,而HSE速率太低(4~26MHz),为了使系统获得较快的运行速率和稳定性,我们选
择PLLCLK来作为SYSCLK(见备注1),而PLLCLK又可以选择HSI或者HSE作为时钟源,我们选择HSE作为时钟源(见备注2)
根据时钟树的走向,SYSCLK(即PLLCLK)计算过程为:
PLL_VCO = (HSE_VALUE / PLL_M) * PLL_N
SYSCLK = PLL_VCO / PLL_P
而宏定义有
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#define PLL_M 12
#define PLL_Q 7
#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
#define PLL_N 360
#define PLL_P 2
故SYSCLK最终为180MHz。
注意:HSE_VALUE、PLL_M要根据实际使用的外部晶振来确定取值。
备注1:SYSCLK时钟源的选择:
系统时钟源的选择由RCC时钟配置寄存器的SW(位1:0)来决定:
在程序中,通过(RCC->CFGR & RCC_CFGR_SWS)进行选择判断,当(RCC->CFGR & RCC_CFGR_SWS)为0x08时,则选择PLLSCK作为系统时钟源。stm32f4xx_rcc.c文件中的void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)函数可完成对RCC->CFGR 的低二位进行设置。
#define RCC_CFGR_SW ((uint32_t)0x00000003)
#define RCC_CFGR_SWS ((uint32_t)0x0000000C)
#define RCC_CFGR_SWS_PLL ((uint32_t)0x00000008)
#define RCC_SYSCLKSource_PLLCLK ((uint32_t)0x00000002)
#define IS_RCC_SYSCLK_SOURCE(SOURCE) (((SOURCE) == RCC_SYSCLKSource_HSI) || \
((SOURCE) == RCC_SYSCLKSource_HSE) || \
((SOURCE) == RCC_SYSCLKSource_PLLCLK)) assert_param(IS_RCC_SYSCLK_SOURCE(RCC_SYSCLKSource));
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
RCC->CFGR上电之后初始值为0x00000000,因此经过上述运算后,
RCC->CFGR=0x0000000A,故(RCC->CFGR & RCC_CFGR_SWS)为0x00000008。
详见system_stm32f4xx.c文件中的void SystemCoreClockUpdate(void)函数。
备注2:PLLSCK时钟源的选择:
程序中,PLLSCK的时钟源由pllsource来进行判断选择,当pllsource不为0时,则选择HSE 作为PLL的时钟源;否则,选择HSI作为PLL的时钟源:
#define PLL_M 12
#define PLL_Q 7
#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
#define PLL_N 360
#define PLL_P 2
#endif /* STM32F427_437x || STM32F429_439xx */
#define RCC_PLLCFGR_PLLSRC ((uint32_t)0x00400000)
#define RCC_PLLCFGR_PLLSRC_HSE ((uint32_t)0x00400000)
#define RCC_PLLCFGR_PLLSRC_HSI ((uint32_t)0x00000000)
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
经过上述计算,pllsource=1,不为0,因此选择HSE作为PLL的时钟源。
详见system_stm32f4xx.c文件中的void SystemCoreClockUpdate(void)函数。