时钟是处理器运行的基础,​时钟信号推动处理器内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定CPU速率​,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。

为什么 STM32 要有多个时钟源呢?

我们在学习51单片机时,其最小系统必有晶振电路,这块电路就是单片机的时钟来源,晶振的振荡频率直接影响单片机的处理速度。STM32相比51单片机就复杂得多,不仅是外设非常多,就连时钟来源就有四个。但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费,而且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题,因此便有了STM32的时钟系统和时钟树。




《嵌入式 - 深入剖析STM32》详解STM32时钟系统_时钟系统

1 STM32时钟硬件电路

STM32三个不同的时钟源可以用来驱动系统时钟(SYSCLK):


● HSI晶振时钟(高速内部时钟信号)
● HSE晶振时钟(高速外部时钟信号)
● PLL时钟


STM32有两个二级时钟源:


● 40kHz的低速内部RC,它可以驱动独立看门狗,还可选择地通过程序选择驱动RTC。 RTC用于从停机/待机模式下自动唤醒系统。
● 32.768kHz的低速外部晶振,可选择它用来驱动RTC(RTCCLK)。
每个时钟源在不使用时都可以单独被打开或关闭,这样就可以优化系统功耗。


《嵌入式 - 深入剖析STM32》详解STM32时钟系统_STM32_02

图1时钟树

当使用HSI作为PLL时钟的输入时,所能达到的最大系统时钟为64MHz。

1.1 HSE时钟

高速外部时钟信号(HSE)由以下两种时钟源产生:

● HSE外部晶体 / 陶瓷 谐振器(见图2(a))

● HSE用户外部时钟(见图2(b))

《嵌入式 - 深入剖析STM32》详解STM32时钟系统_时钟系统_03

(a)外部时钟 (b)晶振时钟

图2 HSE时钟

1.外部时钟源(HSE旁路)

在这种模式下,必须提供一个外部时钟源。它的频率可高达25MHz。外部时钟信号(占空比为50%的方波、 正弦波或三角波)必须连到OSC_IN引脚,同时保证OSC_OUT引脚悬空,见图2(a)。这个外部时钟源是指从其他处理器等引入的时钟源,​STM32的demo板就是使用的这种方式,主控器MCU的外部时钟源来自ST Link处理器提供的时钟信号。

2.外部晶体 / 陶瓷谐振器(HSE晶体)

这个4~16MHz的外部晶振的优点在于能产生非常精确的主时钟。 图3显示了它需要的相关硬件配置。谐振器和负载电容需要尽可能近地靠近振荡器的引脚,以减小输出失真和启动稳定时间。负载电容值必须根据选定的晶振进行调节。这种方式也是我们常用的方式,具体电路如下所示。

《嵌入式 - 深入剖析STM32》详解STM32时钟系统_引脚_04

图3外部晶体电路图

1.2 LSE时钟

低速外部时钟源(LSE)可以由两个可能的时钟源来产生:


● LSE外部晶体 / 陶瓷谐振器(见图4(a))
● LSE用户外部时钟(见图4(b))


1.外部源(LSE 旁路)

在这种模式下,必须提供一个外部时钟源。它的频率必须为32.768kHz。外部信号(占空比为50%的方波、 正弦波或三角波)必须连到OSC32_IN引脚,同时保证OSC_OUT引脚悬空。

2.外部晶体 / 陶瓷谐振器(LSE晶体)

这个LSE晶体是一个32.768kHz的低速外部晶体或陶瓷谐振器。它的优点在于能为实时时钟部件(RTC)提供一个低速的,但高精确的时钟源。 RTC可以用于时钟/日历或其它需要计时的场合。谐振器和加载电容需要尽可能近地靠近晶振引脚,这样能使输出失真和启动稳定时间减到最小。负载电容值必须根据选定的晶振进行调节。外部晶体时钟如图5所示。

《嵌入式 - 深入剖析STM32》详解STM32时钟系统_引脚_05

(a)外部时钟 (b)晶振时钟

图4 LSE时钟

《嵌入式 - 深入剖析STM32》详解STM32时钟系统_引脚_06

图5外部RTC时钟源

HSE和LSE外部晶体两时钟电路的两个电容式为了抗干扰​。对抗自然界中的一些干扰,如雷击。

2 STM32 的时钟系统

STM32 芯片为了实现低功耗,设计了一个功能完善但却非常复杂的时钟系统。普通的MCU 一般只要配置好 GPIO 的寄存器就可以使用了,但 STM32 还有一个步骤,就是开启外设时钟。

《嵌入式 - 深入剖析STM32》详解STM32时钟系统_系统时钟_07

图6 STM32的时钟树

在 STM32 中,可分为五种时钟源,为 ​HSI、 HSE、 LSI、 LSE、 PLL​。 从时钟频率来分可以分为高速时钟源和低速时钟源,其中 HIS, HSE 以及 PLL 是高速时钟, LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源,其他的是内部时钟源。下面我们看看 STM32 的 5 个时钟源,我们讲解顺序是按图中红圈标示的顺序:

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

2.HSE 是高速外部时钟,可接石英 /陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。 我们的开发板接的是 8M 的晶振。当使用有源晶振时,时钟从 OSC_IN 引脚进入, OSC_OUT 引脚悬空,当选用无源晶振时,时钟从 OSC_IN 和 OSC_OUT 进入,并且要配谐振电容。HSE 最常使用的就是 8M 的无源晶振。当确定 PLL 时钟来源的时候, HSE 可以不分频或者 2 分频,这个由时钟配置寄存器 CFGR 的位 17。

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

4.LSE 是低速外部时钟,接频率为 32.768kHz 的石英晶体。这个主要是 RTC 的时钟源。

5.PLL 为锁相环倍频输出,其时钟输入源可选择为 HSI/2、HSE 或者 HSE/2。倍频可选择为2~16 倍,但是其输出频率最大不得超过 72MHz。

图中我们用 A~E 标示我们要讲解的地方。


A. MCO 是 STM32 的一个时钟输出 IO(PA8),它可以选择一个时钟信号输出, 可以选择为 PLL 输出的 2 分频、 HSI、 HSE、或者系统时钟。这个时钟可以用来给外部其他系统提供时钟源。



B. 这里是 RTC 时钟源,从图上可以看出, RTC 的时钟源可以选择 LSI, LSE,以及HSE 的 128 分频。



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



D. D 处就是 STM32 的系统时钟 SYSCLK,它是供 STM32 中绝大部分部件工作的时钟源。系统时钟可选择为 PLL 输出、 HSI 或者 HSE。系统时钟最大频率为 72MHz,当然你也可以超频,不过一般情况为了系统稳定性是没有必要冒风险去超频的。



E. 这里的 E 处是指其他所有外设了。从时钟图上可以看出,其他所有外设的时钟最终来源都是 SYSCLK。 SYSCLK 通过 AHB 分频器分频后送给各模块使用。这些模块包括:
①AHB 总线、内核、内存和 DMA 使用的 HCLK 时钟。
②通过 8 分频后送给 Cortex 的系统定时器时钟,也就是 systick 了。
③直接送给 Cortex 的空闲运行时钟 FCLK。
④送给 APB1 分频器。 APB1 分频器输出一路供 APB1 外设使用(PCLK1,最大频率 36MHz),另一路送给定时器(Timer)2、 3、 4 倍频器使用。
⑤送给 APB2 分频器。 APB2 分频器分频输出一路供 APB2 外设使用(PCLK2,最大频率 72MHz),另一路送给定时器(Timer)1 倍频器使用。
其中需要理解的是 APB1 和 APB2 的区别, APB1 上面连接的是低速外设,包括电源接口、备份接口、 CAN、 USB、 I2C1、 I2C2、 UART2、 UART3 等等, APB2 上面连接的是高速外设包括 UART1、 SPI1、 Timer1、 ADC1、 ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口等。


不同的总线有不同的频率,不同的外设挂在不同的总线下,为了更适合初学者查阅,笔者把常用的外设与总线的对应关系总结如下:

《嵌入式 - 深入剖析STM32》详解STM32时钟系统_系统时钟_08

图7 STM32F1总线与外设对应关系

SystemInit()函数中设置的系统时钟大小:


 SYSCLK(系统时钟) =72MHz
 AHB 总线时钟(使用 SYSCLK) =72MHz
 APB1 总线时钟(PCLK1) =36MHz
 APB2 总线时钟(PCLK2) =72MHz
 PLL 时钟 =72MHz


具体代码请读者查看工程文件的system_stm32f10x.c文件。

举个例子:Keil编写程序是默认的时钟为72Mhz,其实是这么来的:外部晶振(HSE)提供的8MHz(与电路板上的晶振的相关)通过PLLXTPRE分频器后,进入PLLSRC选择开关,进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK)。之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。

或者内部RC振荡器(HSI) 为8MHz /2 为4MHz 进入PLLSRC选择开关,通过PLLMUL锁相环进行倍频(x18)后 为72MHz。

PS: 网上有很多人说是5个时钟源,这种说法有点问题,学习之后就会发现PLL并不是自己产生的时钟源,而是通过其他三个时钟源倍频得到的时钟​,这点在前文已近讲解得很清楚了。

3 Systick系统定时器工作原理分析

SysTick 定时器被捆绑在 NVIC 中,用于产生 SysTick 异常(异常号 :15)。在以前,操作系统和所有使用了时基的系统都必须有一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务分配不同数目的时间片,确保没有一个任务能霸占系统 ;或者将每个定时器周期的某个时间范围赐予特定的任务等,操作系统提供的各种定时功能都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

Cortex-M3 在内核部分包含了一个简单的定时器——SysTick。因为所有的 CM3 芯片都带有这个定时器,软件在不同芯片生产厂商的 CM3 器件间的移植工作就得以简化。该定时器的时钟源可以是内部时钟(FCLK,CM3 上的自由运行时钟),或者是外部时钟( CM3 处理器上的 STCLK 信号)。不过,STCLK 的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能大不相同。因此,需要阅读芯片的使用手册来确定选择什么作为时钟源。在 STM32 中 SysTick 以 HCLK(AHB 时钟)或 HCLK/8 作为运行时钟。

SysTick 定时器能产生中断,CM3 为它专门开出一个异常类型,并且在向量表中有它的一席之地​。它使操作系统和其他系统软件在 CM3 器件间的移植变得简单多了,因为在所有 CM3 产品间,SysTick 的处理方式都是相同的。SysTick 定时器除了能服务于操作系统之外,还能用于其他目的,如作为一个闹铃、用于测量时间等。Systick 定时器属于Cortex 内核部件,可以参考《​ARM Cortex-M3 权威指南​》((英)JosephYiu 著,宋岩译,北京航空航天大学出版社出版)或“STM32xxx-Cortex-M3programmingmanual”(这是 ST 官方提供的电子版编程手册,可以在 ST 官网下载)来了解。

[ps]本文的时钟系统基于STM32F1,ST的其他系列的时钟系统类似。

关于SysTick 定时器实现请看笔者博文:

​Systick系统定时器​

​Systick系统定时器(HAL库)​


欢迎访问我的网站:

​BruceOu的哔哩哔哩​

​BruceOu的主页​

​BruceOu的博客​

​BruceOu的简书​

接收更多精彩文章及资源推送,请订阅我的微信公众号:

《嵌入式 - 深入剖析STM32》详解STM32时钟系统_STM32_09