跳转至

5.1 STM32驱动开发-系统时钟树

前言

这里主要讲解 Breeze Mini 的主时钟系统设置,完整代码在工程目录下的 Drivers 子目录下的 stm32f10x_driver_clock.cstm32f10x_driver_clock.h 中。

相关知识

时钟树简介

时钟系统在整个芯片系统中占据着十分重要的地位,因为时钟系统要产生数字电路工作所必须的时序信号,换句话来说就是 各个工作逻辑都是在时钟所产生的时序脉冲下顺序执行,就像人的心跳一样。STM32的内部时钟信号非常多,从几十k到几十M的都有,存在多种频率的时钟信号是因为STM32本身支持非常多的外设,但并不是所有的外设都需要系统时钟这么高的频率,比如看门狗和RTC功能只需要几十k的时钟即可,时钟频率越高功耗越大,同时抗电磁干扰能力越弱,因此许多具有丰富外设的MCU都是采用这种多时钟系统以提高工作效率。

接下来具体介绍STM32的时钟系统,其系统图如下所示:

在STM32中共有5个时钟源,分别为 HSI、HSE、LSI、LSEPLL

  1. HSI 是高速内部时钟,由内部RC振荡器提供,频率为8MHz。

  2. HSE 是高速外部时钟,可外接石英晶振或时钟源,其外接的频率范围为4MHz~16MHz。

  3. LSI 是低速内部时钟,由内部RC振荡器提供,频率为40KHz,独立看门狗的时钟源只能是LSI,同时LSI还可以作为RTC的时钟源。

  4. LSE 是低速外部时钟,要接32.768KHz的石英晶振,主要用于RTC的时钟源。

  5. PLL 是锁相环倍频输出,其输入时钟源可以选择 HSI/2HSEHSE/2,倍频可选择2~16倍,但是最好不要超过 72MHz

上面简单概括了STM32的5个时钟源,现在将会一一讲解这些时钟源是如何给外设提供指定频率时序信号的,具体内容见下图:

A. MCO是STM32的一个时钟输出IO(PA8),它可以选择一个时钟信号输出,可以选择PLL输出的2分频、HSI、HSE或者系统时钟。

B. 这个是RTC时钟源,从图中可以看出RTC的时钟源可以选择LSI、LSE或者HSE的128分频。

C. 从图中可以看出USB的时钟来自于PLL时钟源,STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获得,可以选择1.5分频或者1分频,也就是说当需要使用USB模块时,PLL必须使能并且时钟频率要配置为48MHz或72MHz。

D. 这个是STM32的系统时钟SYSCLK,它提供了STM32大部分部件工作时所需的时钟信号,系统时钟可选择为PLL输出、HSI或HSE。系统时钟最大频率为72MHz,也可以超频,但是可能会导致系统工作不稳定。

E. 这里是指所有外设的时钟,所有外设的时钟最终都来源于SYSCLK,SYSCLK通过AHB分频器分频后送给各外设使用。这些外设包括:

  1. AHB总线、内核、内存和DMA使用的HCLK时钟。

  2. 8分频后送给Cortex的系统定时器时钟。

  3. 送给Cortex的空闲运行时钟FCLK。

  4. 送给APB1分频器,一路供APB1外设使用(PCLK1,最大频率36MHz),一路供定时器2、3和4倍频使用。

  5. 送给APB2分频器,一路供APB2外设使用(PCLK2,最大频率72MHz),一路供定时器1倍频使用。

在以上的时钟输出中,有很多是需要使能控制的,比如AHB总线时钟、内核时钟、各APB1和APB2外设等,当需要使用某个模块时,要先使能对应的时钟

STM32时钟

STM32时钟系统的配置代码分为两部分,一部分在 CMSIS 目录下的 system_stm32f10x.c 中的 SystemInit()函数中,用于初始化,另一部分在 FWLib 目录下的 stm32f10x_rcc.c 中,用于操作时钟系统。对于系统时钟来说,默认情况下是在SystemInit函数的SetSysClock函数中判断的,SetSysClock 函数的定义如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
    SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
    SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
    SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
    SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
    SetSysClockTo72();
#endif
}

这段代码设置系统时钟的频率为72MHz,其宏定义为:

1
#define SYSCLK_FREQ_72MHz  72000000

如果想设置系统时钟频率为36MHz,只需注释掉上面的宏定义,并加入如下定义即可:

1
#define SYSCLK_FREQ_36MHz  36000000

设置完系统时钟后可以通过变量 SystemCoreClock 获得系统时钟的值,在 system_stm32f10x.c 中该变量的定义为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#ifdef SYSCLK_FREQ_HSE
    uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;
#elif defined SYSCLK_FREQ_24MHz
    uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;
#elif defined SYSCLK_FREQ_36MHz
    uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;
#elif defined SYSCLK_FREQ_48MHz
    uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;
#elif defined SYSCLK_FREQ_56MHz
    uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;
#elif defined SYSCLK_FREQ_72MHz
    uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;
#else /*!< HSI Selected as System Clock source */
    uint32_t SystemCoreClock         = HSI_VALUE;
#endif

总结来说,当系统时钟频率设置为72MHz大小时:

  1. SYSCLK时钟:72MHz

  2. AHB总线时钟(使用SYSCLK为时钟源):72MHz

  3. APB1总线时钟:36MHz

  4. APB2总线时钟:72MHz

  5. PLL时钟:72MHz

硬件连接

软件设计

参考