OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 750|回复: 0

《M144Z-M3最小系统板使用指南——STM32F103版》第八章 STM32F103时钟系统介绍

[复制链接]

1117

主题

1128

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4667
金钱
4667
注册时间
2019-5-8
在线时间
1224 小时
发表于 2024-3-23 15:33:30 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2024-3-22 16:30 编辑

第八章 STM32F103时钟系统介绍
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板

2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版


4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boar ... _mini_sysboard.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子STM32技术交流QQ群:725095144

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

MCU都是基于时序控制的系统,本章将为STM32F103的时钟系统作一个简单的介绍,帮助读者更全面、系统地认识STM32F103的时钟系统结构,并掌握STM32F103的时钟配置。
本章分为如下几个小节:
8.1 认识时钟树
8.2 配置系统主频
8.3 开启和关闭外设时钟

8.1 认识时钟树
从数字电路的知识可以知道:任意复杂的电路控制系统都可以经由门电路组成的组合电路实现。STM32内部也是由多种多样的电路模块组合在一起实现的。若一个电路越复杂,在达到正确的输出结果前,它可能因为延时会有一些短暂的中间状态,而这些中间状态有时会导致输出结果会有一个短暂的错误,这叫做电路中的“毛刺现象”,如果电路需要运行得足够快,那么这些错误状态会被其它电路作为输入采样,最终形成一系列的系统错误。为了解决这个问题,在单片机系统中,设计时以时序电路控制替代纯粹的组合电路,在每一级输出结果前对各个信号进行采样,从而使得电路中某些信号即使出现延时也可以保证各个信号的同步,可以避免电路中发生的“毛刺现象”,达到精确控制输出的效果。
由于时序电路的重要性,因此在MCU设计时就设计了专门用于控制时序的电路,在芯片设计中称为时钟树设计。由此设计出来的时钟,可以精确控制单片机系统,这也是本小节要展开分析的。为什么是时钟树而不是时钟呢?一个MCU越复杂,时钟系统也会相应的变得复杂,如STM32F103的时钟系统就比较复杂,不像简单的51单片机,一个系统时钟就可以解决一切。对于STM32F103系列的芯片,正常工作的主频可以达到72MHz,但并不是所有外设都需要系统时钟这么高的频率,比如看门狗以及RTC只需要几十KHz的时钟频率即可工作。同一个电路,时钟频率越快功耗就越大,同时抗电磁干扰能力也会越弱,所以对于较为复杂的MCU一般都是采取多时钟的方法来解决这些问题。
STM32本身相对复杂,外设资源非常丰富,为了保证低功耗,STM32上电或复位后默认不开启这些外设功能,即不为这些外设提供时钟。用户可以根据自己的需要决定STM32芯片要使用的功能,即为这些外设提供时钟,同时也要配置时钟源和时钟的频率              
image001.png
图8.1.1 STM32F103时钟树
上图就是STM32F103的时钟树框图
①:该部分是四个时钟源,分别为:LSI(内部低速时钟)、LSE(外部低速时钟)、HSI(内部高速时钟)、HSE(外部高速时钟),这四个时钟源是整个时钟树的“源头”。
②:该部分为PLL(锁相环),这一部分内部是较为复杂的模拟电路,主要用于对输入的时钟信号倍频后输出,输入的时钟源可以来自HSI或HSE。
③:该部分主要用于选择系统时钟的时钟源,从图中可以看出,该选择器的输入有HSE、HSI和PLL1,输出作用于SYSCLK,而SYSCLK通过AHB Prescaler分频后输出,该输出将直接或间接地作为AHB、APB1和APB2总线上外设的时钟源,其中FCLK就是MCU内核的时钟,这部分对整个系统的运行起着至关重要的作用。
④:AHBPrescaler分频后的时钟再通过APB1Prescaler和APB2Prescaler分频后分别作为APB1和APB2总线上外设的时钟。
8.1.1 时钟源
STM32F103有四个时钟源,分别为:LSI(内部低速时钟)、LSE(外部低速时钟)、HSI(内部高速时钟)、HSE(外部高速时钟)。按低速时钟源和高速时钟源可分为LSI、LSE和HSI、HSE,按内部时钟源和外部时钟源可分为LSI、HSI和LSE、HSE,其中内部时钟源LSI和HSI是MCU芯片内部的时钟源,芯片上电后即可输出时钟,无需借助外部电路。
①:外部高速时钟HSE(High Speed External Clock)
该时钟信号由外部晶体、陶瓷谐振振荡器或外部时钟源产生,频率范围为4MHz~26MHz,正点原子M144Z-M3最小系统板STM32F103版使用频率为8MHz的晶体振荡器产生该时钟信号。
②:外部低速时钟LSE(Low Speed External Clock)
该时钟信号由外部晶体、陶瓷谐振振荡器或外部时钟源产生,频率为32.768KHz,主要作为RTC的时钟源,正点原子M144Z-M3最小系统板STM32F103版使用频率为32.768KHz的晶体振荡器产生该时钟信号。
③:内部高速时钟HSI(High Speed Internal Clock)
该时钟信号由内部RC振荡器产生,频率为16MHz。
④:内部低速时钟LSI(Low Speed Internal Clock)
该时钟信号由内部RC振荡器产生,频率为20KHz~35KHz(受温度、电压影响),主要作为独立看门狗或RTC的时钟源。
MCU上电时默认会使用HSI作为系统时钟启动,只有完成了相关的时钟配置,MCU才会根据配置切换到对应的时钟源,因此同时了解这几个时钟源是很有必要的,下文将会有提到时钟配置方法的章节。
8.1.2 锁相环
锁相环(PLL)是自动控制系统中常用的一个反馈电路,在STM32主控中,锁相环主要有对输入时钟进行净化和倍频这两个作用,前者是利用锁相环电路的反馈机制实现的,后者是用于使STM32主控稳定地工作于更高的时钟频率。
在STM32中,锁相环的输出时钟可以配置为系统时钟的时钟源,如下图所示:
image003.png
图8.1.2.1 PLL1输出时钟作为系统时钟示例
从上图中可以看出,HSE的时钟HSECLK被作为PLL的输入时钟输入PLL,随后在PLL中经过倍频后作为PLLCLK输出,PLLCLK被作为SYSCLK。
上面过程中的配置基本可以由时钟配置寄存器(RCC_CFGR)完成配置。
image005.png
图8.1.2.2 时钟配置寄存器PLLXTPRE位
PLLXTPRE位用于对输出PLL的HSECLK进行分频,可选不分频(写0)或二分频(写1)。将该位配置为0,即不对HSECLK进行分频。
image007.png
图8.1.2.3 时钟配置寄存器PLLSRC位
PLLSRC位用于选择PLL的输入时钟,可选HIS二分频(写0)或HSE(写1)。将该位配置位配置位1,即可使用HSE输入的8MHz时钟信号作为PLL的输入。
image009.png
图8.1.2.4 时钟配置寄存器PLLMUL位
PLLMUL位用于配置PLL的倍频系数,可选倍频系数位2~16,将改为配置为9,即可将输入PLL的8MHz时钟信号倍频为72MHz。
image011.png
图8.1.2.5 时钟配置寄存器SW位
SW位用于选择SYSCLK的时钟源,可选HIS(写0)、HSE(写1)或PLL(写2)。将该位配置为2,即可使用PLL输出的72MHz时钟信号作为SYSCLK的时钟源。
8.1.3 系统时钟
STM32的系统时钟(SYSCLK)为整个芯片的绝大多数外设和内核提供时钟信号,对于相同稳定运行的系统,时钟信号的频率越高,系统运行的速度也就越快,单位时间能够处理的事务也就越多。在上一小节中,将频率为8MHz的HSE时钟信号通过PLL倍频为72MHz的时钟信号作为SYSCLK的时钟源。SYSCLK时钟信号可直接或间接地作为AHB总线、APB1总线、APB2总线和内核的时钟源。  
image013.png
图8.1.3.1 各总线和内核时钟配置示例
①:AHB预分频器,可对SYSCLK进行分频,分频范围为1~512。对于示例,AHB预分频器选择不分频(/1),那么AHB总线、内核、APB1总线和APB2总线输入的时钟信号频率都为72MHz。
②:APB1预分频器,可对待输入APB1总线的时钟信号进行分频,分频范围为1~16,APB1总线的时钟频率最大值为36MHz。对于示例,APB1预分频器选择2,即对频率为72MHz的时钟信号进行2分频为36MHz后作为APB1总线的时钟频率。
③:APB2预分频器,可对待输入APB2总线的时钟信号进行分频,分频范围为1~16,APB2总线的时钟频率最大值为72MHz。对于示例,APB2预分频器选择1,即使用72MHz的时钟信号作为APB2总线的时钟。

8.2 配置系统主频
STM32F103在默认情况下,使用频率为8MHz的HSI作为系统时钟的时钟源,因此无需外部晶振也能够正常烧录和运行程序。
在上一小节中,介绍了如何配置时钟树,以让内核在72MHz的主频下运行,72MHz是ST官方针对STM32F103推荐的最大工作频率。
本节将介绍如何在代码中具体的对STM32F103的时钟进行配置。本书配置实验例程都是在main()函数中调用sys_stm32_clock_init()对STM32F103的时钟进行配置的,如下所示:
  1. int main(void)
  2. {
  3.     /* 省略其他无关代码 */
  4.    
  5.    sys_stm32_clock_init(RCC_PLL_MUL9); /* 配置系统时钟 */
  6.    
  7.     /* 省略其他无关代码 */
  8. }
复制代码
相信读者对sys_stm32_clock_init()函数传入的参数并不陌生,这就是在上一小节示例中配置时钟配置寄存器中PLLMUL的值。
sys_stm32_clock_init()函数的代码比较多,请读者在实验例程中查看本函数的具体实现,本小节中仅列出该函数的关键代码,如下所示:
  1. voidsys_stm32_clock_init(uint32_t plln)
  2. {
  3.    RCC_OscInitTypeDef rcc_osc_init = {0};
  4.    RCC_ClkInitTypeDef rcc_clk_init = {0};
  5.    
  6.     /* 配置PLL */
  7.    rcc_osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  8.     rcc_osc_init.HSEState = RCC_HSE_ON;
  9.    rcc_osc_init.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  10.    rcc_osc_init.PLL.PLLState = RCC_PLL_ON;
  11.    rcc_osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  12.    rcc_osc_init.PLL.PLLMUL = plln;
  13.    HAL_RCC_OscConfig(&rcc_osc_init);
  14.    
  15.     /* 配置时钟 */
  16.    rcc_clk_init.ClockType = (  RCC_CLOCKTYPE_SYSCLK |
  17.                                  RCC_CLOCKTYPE_HCLK |
  18.                                  RCC_CLOCKTYPE_PCLK1|
  19.                                  RCC_CLOCKTYPE_PCLK2);
  20.    rcc_clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  21.    rcc_clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
  22.    rcc_clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
  23.    rcc_clk_init.APB2CLKDivider = RCC_HCLK_DIV1;
  24.    HAL_RCC_ClockConfig(&rcc_clk_init, FLASH_LATENCY_2);
  25. }
复制代码
跟上一小节介绍的一致,AHB、APB2和APB1总线的预分频器分别配置为不分频、2分频和不分频;根据函数的传入参数配置时钟配置寄存器的PLLMUL位的值,并将PLL的时钟源配置为HSE;将PLLCLK配置为SYSCLK的时钟源。上面列出的代码仅是一些关键代码,除了列出代码的操作外还需要一些额外的操作,例如使能HSE并等待HSE稳定等,建议读者打开本书配套的任意实验例程,在sys.c文件中详细地查看本函数的具体实现。
通过sys_stm32_clock_init()函数就能够非常方便地配置系统主频了,例如,在考虑对MCU的性能需求和功耗的场景中,可以适当降低MCU的主频,来达到性能和功耗的平衡。

8.3 开启和关闭外设时钟
在前面的章节中,分析了STM32F103的时钟系统和相关的配置步骤,但是在使用某些外设之前,还需要手动开启相应外设的时钟,这是因为MCU在上电或复位后会默认关闭大部分外设的时钟,以降低功耗,因此,在程序开发中,对于某些开启的时钟但不再使用的外设,也应将其时钟关闭。
STM32F103外设的时钟由RCC(Reset andClock Control)控制,RCC中控制外设时钟的寄存器被按总线进行分类,涉及了五个寄存器,分别为RCC_AHB1ENR、RCC_AHB2ENR、RCC_AHB3ENR、RCC_APB1ENR和RCC_APB2ENR,这五个寄存器分别用于管理AHB总线、APB1总线和APB2总线上外设的时钟。
下面以GPIOA为例,介绍如何配置RCC中相应的寄存器来开启或关闭GPIOA的时钟。首先能够确定GPIOA是位于APB2总线上的外设,因此可以判断用于控制GPIOA时钟的寄存器为RCC_APB2ENR。在RCC_APB2ENR寄存器中可以找到IOPAEN位,该位就是用于控制GPIOA外设时钟使能和禁止的,如下图所示:   
image015.png
图8.3.3 RCC_APB2ENR寄存器IOPAEN位
由上图可知,往RCC_APB2ENR寄存器的IOPAEN位写入1后,就能配置使能GPIOA外设的时钟,往RCC_APB2ENR寄存器的IOPAEN位写入0后,就能配置禁止GPIOA外设的时钟。
在HAL库中提供了用于开启和关闭外设时钟的宏定义,这些宏定义被定义在stm32f1xx_hal_rcc.h文件中,如以所示:
  1. #define __HAL_RCC_GPIOA_CLK_ENABLE()                           \
  2.     do {                                                        \
  3.          __IO uint32_t tmpreg;                                  \
  4.          SET_BIT(RCC->APB2ENR,RCC_APB2ENR_IOPAEN);             \
  5.          /* Delayafter an RCC peripheral clock enabling */     \
  6.          tmpreg = READ_BIT(RCC->APB2ENR,RCC_APB2ENR_IOPAEN);   \
  7.          UNUSED(tmpreg);                                         \
  8.     }while(0U)
  9. #define __HAL_RCC_GPIOA_CLK_DISABLE()  (RCC->APB2ENR &= ~(RCC_APB2ENR_IOPAEN))
复制代码
上面的两个宏定义中,__HAL_RCC_GPIOA_CLK_ENABLE()用于使能GPIOA端口的时钟,而__HAL_RCC_GPIOA_CLK_DISABLE()用于失能GPIOA端口的时钟。
细心的读者可能会发现HAL库提供的用于使能和失能外设时钟的宏定义,其命名规则大致为__HAL_RCC_+外设名称+_CLK_+ENABLE或DISABLE()。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 05:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表