05. STM32F1的时钟树

发布时间 2023-07-23 20:05:33作者: 夏冰翎

一、STM32的时钟树

img

img

二、时钟源

  对于 STM32F1,输入时钟源(InputClock)主要包括 HSI,HSE,LSI,LSE。其中,从 时钟频率 来分可以分为 高速时钟源 和 低速时钟源,其中 HSI、HSE 是高速时钟,LSI 和 LSE 是低速时钟。从 来源 可分为 外部时钟源 和 内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源;其他是内部时钟源,芯片上电即可产生,不需要借助外部电路。

  • 高速外部振荡器 HSE(High Speed External Clock signal)
    • 外接 石英/陶瓷谐振器,频率为 4MHz~16MHz。常用的频率为 8MHz。
  • 低速外部振荡器 LSE(Low Speed External Clock signal)
    • 外接 32.768kHz 石英晶体,主要作用于 RTC 的时钟源。
  • 高速内部振荡器 HSI(High Speed InternalClock signal)
    • 由 内部RC振荡器 产生,频率为 8MHz。
  • 低速内部振荡器 LSI(Low Speed Internal Clock signal)
    • 由 内部RC振荡器 产生,频率为 40kHz,可作为 独立看门狗的时钟源。

芯片上电时默认由内部的 HSI 时钟启动,如果用户进行了硬件和软件的配置,芯片才会根据用户配置调试尝试切换到对应的外部时钟源;

三、锁相环PLL

  锁相环是自动控制系统中常用的一个反馈电路,在 STM32 主控中,锁相环的作用主要有两个部分:输入时钟净化 和 倍频。前者是利用锁相环电路的反馈机制实现,后者我们用于使芯片在更高且频率稳定的时钟下工作。

  在 STM32 中,锁相环的输出也可以作为芯片系统的时钟源。使用锁相环时只需要进行三个部分的配置。

【1】、PLL 时钟源

  PLL 时钟来源 可以有两个,一个来自 HSE,另外一个是 HSI/2,具体用哪个由 时钟配置寄存器 RCC_CFGR 的 位16:PLLSRC 设置。

img

  HSI 是内部高速的时钟信号,频率为 8M,根据温度和环境的情况频率会有漂移,一般不作为 PLL 的时钟来源。一般会选用 HSE 作为 PLL 的时钟来源。

img

  当选用 HSE 作为 PLL 的输入时钟时,可以选择 不分频 或者 2分频,这个由 时钟配置寄存器 RCC_CFGR 的 位17:PLLXTPRE 设置。

img

【2】、PLL 时钟 PLLCLK

  通过设置 PLL 的 倍频因子,可以对 PLL 的时钟来源进行 倍频,倍频因子可以是:2~16,具体设置成多少,由 时钟配置寄存器 RCC_CFGR 的 位21-18:PLLMUL[3:0] 设置。

img

  要实现 72MHz 的主频率,我们通过选择 HSE 不分频作为 PLL 输入的时钟信号,即输入 8Mhz。倍频因子可选择 2-16 倍频,我们选择 9 倍频,这样可以得到时钟信号为 8*9=72MHz。

72M 是 ST 官方推荐的稳定运行时钟,如果你想超频的话,增大倍频因子即可,最高为 128M。

如果使用 HSI/2 作为 PLL 时钟源,那么可以得到最高主频 8MHz/2*16=64MHz。

四、系统时钟SYSCLK

  STM32 的 系统时钟SYSCLK 为整个芯片提供了时序信号。对于相同的稳定运行的电路,时钟频率越高,指令的执行速度越快,单位时间能处理的功能越多。STM32 的系统时钟是可配置的,在 STM32F1 系列中,它可以为 HSI、PLLCLK、HSE 中的一个,通过 时钟配置寄存器 RCC_CFGR 的 位1-0:SW[1:0] 设置。

img

  可以把主频通过 PLL 设置为 72MHz。仍使用 PLL 作为系统时钟源,如果使用 HSI/2,那么可以得到最高主频 8MHz/2*16=64MHz。

  系统时钟输入选择,可选时钟信号有 外部高速时钟 HSE(8M)、内部高速时钟 HSI(8M)和 经过倍频的 PLLCLK(72M),选择 PLL CLK 作为系统时钟,此时系统时钟的频率为 72MHz。

五、总线时钟

5.1、AHB总线时钟HCLK

  系统时钟 SYSCLK 经过 AHB预分频器 分频之后得到时钟叫 APB总线时钟,即 HCLK,分频因子可以是:[1,2,4,8,16,64,128,256,512],具体的由 时钟配置寄存器 RCC_CFGR 的 位7-4:HPRE[3:0] 设置。

img

  片上大部分外设的时钟都是经过 HCLK 分频得到,至于 AHB 总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB的时钟即可。我们这里设置为1分频,即HCLK=SYSCLK=72M。

5.2、APB1总线时钟PCLK1

  APB1 总线时钟 PCLK1 由 HCLK 经过低速 APB预分频器 得到,分频因子可以是:[1,2,4,8,16],具体的由 时钟配置寄存器 RCC_CFGR 的位10-8:PRRE1[2:0] 决定。

img

  APB1 总线时钟 PCLK1 选择的是 2分频,所以 APB1 总线时钟为 36M。由于 APB1 是低速总线时钟,所以 APB1 总线最高频率为 36MHz,片上低速的外设就挂载在该总线上,例如有看门狗定时器、定时器2/3/4/5/6/7、RTC时钟、USART2/3/4/5、SPI2(I2S2)与SPI3(I2S3)、I2C1与I2C2、CAN、USB设备和2个DAC。

5.3、APB2总线时钟PCLK2

  APB2 总线时钟 PCLK2 由 HCLK 经过 高速APB2预分频器 得到,分频因子可以是:[1,2,4,8,16],具体由 时钟配置寄存器 RCC_CFGR 的位13-11:PPRE2[2:0] 决定。

img

  APB2 总线时钟 PCLK2 选择的是 1 即 不分频,所以 APB2 总线时钟频率为 72M。与 APB2 高速总线链接的外设有 外部中断与唤醒控制、7个通用目的输入/输出口(PA、PB、PC、PD、PE、PF 和 PG)、定时器1、定时器8、SPI1、USART1、3个ADC 和 内部温度传感器。

六、其他时钟

6.1、USB时钟

  USB 时钟是由 PLLCLK 经过 USB预分频器 得到,分频因子可以是:[1,1.5],具体的由 时钟配置寄存器 RCC_CFGR 的 位22:USBPRE 配置。USB的时钟最高是 48M。

img

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

6.2、Cortex系统时钟

  Cortex 系统时钟由 HCLK 8分频 得到,等于 9M,Cortex 系统时钟用来驱动内核的系统定时器 SysTick,SysTick 一般用于操作系统的时钟节拍,也可以用做普通的定时。

6.3、ADC时钟

  ADC 时钟由 PCLK2 经过 ADC预分频器 得到,分频因子可以是:[2,4,6,8],具体的由 时钟配置寄存器 RCC_CFGR 的 位15-14:ADCPRE[1:0] 决定。ADC 时钟最高只能是 14M,如果采样周期设置成最短的 1.5 个周期的话,ADC 的转换时间可以达到最短的 1us。

img

6.4、RTC时钟

  RTC 时钟可由 HSE/128 分频得到,也可由低速外部时钟信号 LSE 提供,频率为 32.768KHz,也可由低速内部时钟信号 LSI 提供,具体选用哪个时钟由 备份域控制寄存器 RCC_BDCR 的 位9-8:RTCSEL[1:0] 配置。

img

img

6.5、独立看门狗时钟

  独立看门狗的时钟由 LSI 提供,且只能是由 LSI 提供,LSI 是低速的内部时钟信号,频率为 30~60KHz 直接不等,一般取 40KHz。

七、时钟信号输出MCO

  MCO 是 microcontroller clock output 的缩写,是微控制器时钟输出引脚,在 STM32 F1 系列中由 PA8 复用所得,主要作用是可以对外提供时钟,相当于一个有源晶振。MCO的时钟来源可以是:PLLCLK/2、HSI、HSE、SYSCLK,具体选哪个由 时钟配置寄存器 RCC_CFGR的 位26-24:MCO[2:0] 决定。

img

八、系统时钟配置

【1】、配置 HSE_VALUE

  在 stm32f1xx_hal_conf.h 头文件中的宏定义 HSE_VALUE 匹配我们实际硬件的高速晶振频率(这里是8MHZ),代码中通过使用宏定义的方式来选择 HSE_VALUE 的值是 25M 或者 8M,这里我们不去定义 USE_STM3210C_EVAL 这个宏或者全局变量即可,选择定义 HSE_VALUE 的值为 8M。

/**
  * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
  *        This value is used by the RCC HAL module to compute the system frequency
  *        (when HSE is used as system clock source, directly or through the PLL).  
  */
#if !defined  (HSE_VALUE) 
#if defined(USE_STM3210C_EVAL)
  #define HSE_VALUE    25000000U /*!< Value of the External oscillator in Hz */
#else
  #define HSE_VALUE    8000000U /*!< Value of the External oscillator in Hz */
#endif
#endif /* HSE_VALUE */

【2】、调用 SystemInit 函数

  在系统启动之后,程序会先执行 SystemInit 函数,进行系统一些初始化配置。启动代码调用 SystemInit 函数如下:

; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0   
                LDR     R0, =__main
                BX      R0
                ENDP

  ST 官方提供的 SystemInit 函数的实现方式如下,定义在system_stm32f1xx.c 文件下,源码在 156 行左右。

/**
  * @brief  Setup the microcontroller system
  *         Initialize the Embedded Flash Interface, the PLL and update the 
  *         SystemCoreClock variable.
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#if !defined(STM32F105xC) && !defined(STM32F107xC)
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F105xC */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#if defined(STM32F105xC) || defined(STM32F107xC)
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined(STM32F100xB) || defined(STM32F100xE)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;  
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F105xC */
  
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

【3】、选择时钟源,配置 PLL

  通过 HAL_RCC_OscConfig() 函数设置 PLL 的时钟源。该函数的函数声明如下:

HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)

  该函数只有一个形参,就是结构体 RCC_OscInitTypeDef 类型指针。RCC_OscInitTypeDef 结构体定义如下:

/**
  * @brief  RCC Internal/External Oscillator (HSE, HSI, LSE and LSI) configuration structure definition
  */
typedef struct
{
  uint32_t OscillatorType;       /*!< The oscillators to be configured.
                                       This parameter can be a value of @ref RCC_Oscillator_Type */

#if defined(STM32F105xC) || defined(STM32F107xC)
  uint32_t Prediv1Source;       /*!<  The Prediv1 source value.
                                       This parameter can be a value of @ref RCCEx_Prediv1_Source */
#endif /* STM32F105xC || STM32F107xC */

  uint32_t HSEState;              /*!< The new state of the HSE.
                                       This parameter can be a value of @ref RCC_HSE_Config */

  uint32_t HSEPredivValue;       /*!<  The Prediv1 factor value (named PREDIV1 or PLLXTPRE in RM)
                                       This parameter can be a value of @ref RCCEx_Prediv1_Factor */

  uint32_t LSEState;              /*!<  The new state of the LSE.
                                        This parameter can be a value of @ref RCC_LSE_Config */

  uint32_t HSIState;              /*!< The new state of the HSI.
                                       This parameter can be a value of @ref RCC_HSI_Config */

  uint32_t HSICalibrationValue;   /*!< The HSI calibration trimming value (default is RCC_HSICALIBRATION_DEFAULT).
                                       This parameter must be a number between Min_Data = 0x00 and Max_Data = 0x1F */

  uint32_t LSIState;              /*!<  The new state of the LSI.
                                        This parameter can be a value of @ref RCC_LSI_Config */

  RCC_PLLInitTypeDef PLL;         /*!< PLL structure parameters */

#if defined(STM32F105xC) || defined(STM32F107xC)
  RCC_PLL2InitTypeDef PLL2;         /*!< PLL2 structure parameters */
#endif /* STM32F105xC || STM32F107xC */
} RCC_OscInitTypeDef;

  该结构体前面几个参数主要是用来选择配置的振荡器类型。比如我们要开启 HSE,那么我们会设置 OscillatorType 的值为RCC_OSCILLATORTYPE_HSE,然后设置 HSEState 的值为 RCC_HSE_ON 开启 HSE。对于其他时钟源:HIS、LSI、LSE,配置方法类似。

  RCC_OscInitTypeDef 这个结构体还有一个很重要的成员变量是 PLL,它是结构体 RCC_PLLInitTypeDef 类型。它的作用是配置 PLL 相关参数。

/**
  * @brief  RCC PLL configuration structure definition
  */
typedef struct
{
  uint32_t PLLState;      /*!< PLLState: The new state of the PLL.
                              This parameter can be a value of @ref RCC_PLL_Config */

  uint32_t PLLSource;     /*!< PLLSource: PLL entry clock source.
                              This parameter must be a value of @ref RCC_PLL_Clock_Source */

  uint32_t PLLMUL;        /*!< PLLMUL: Multiplication factor for PLL VCO input clock
                              This parameter must be a value of @ref RCCEx_PLL_Multiplication_Factor */
} RCC_PLLInitTypeDef;

  RCC_PLLInitTypeDef 结构体结构体主要用来设置 PLL 时钟源以及相关分频倍频参数。

【4】、选择系统时钟源,配置总线分频器

  通过 HAL_RCC_ClockConfig() 函数设置系统时钟的时钟源。该函数的函数声明如下:

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)

  该函数有两个形参,第一个形参 RCC_ClkInitStruct 是结构体 RCC_ClkInitTypeDef 类型指针变量,用于设置 SYSCLK 时钟源以及SYSCLK、AHB、APB1 和 APB2 的分频系数。第二个形参FLatency用于设置 FLASH 延迟。

  RCC_ClkInitTypeDef 结构体的定义如下:

/**
  * @brief  RCC System, AHB and APB busses clock configuration structure definition
  */
typedef struct
{
  uint32_t ClockType;             /*!< The clock to be configured.
                                       This parameter can be a value of @ref RCC_System_Clock_Type */

  uint32_t SYSCLKSource;          /*!< The clock source (SYSCLKS) used as system clock.
                                       This parameter can be a value of @ref RCC_System_Clock_Source */

  uint32_t AHBCLKDivider;         /*!< The AHB clock (HCLK) divider. This clock is derived from the system clock (SYSCLK).
                                       This parameter can be a value of @ref RCC_AHB_Clock_Source */

  uint32_t APB1CLKDivider;        /*!< The APB1 clock (PCLK1) divider. This clock is derived from the AHB clock (HCLK).
                                       This parameter can be a value of @ref RCC_APB1_APB2_Clock_Source */

  uint32_t APB2CLKDivider;        /*!< The APB2 clock (PCLK2) divider. This clock is derived from the AHB clock (HCLK).
                                       This parameter can be a value of @ref RCC_APB1_APB2_Clock_Source */
} RCC_ClkInitTypeDef;

  第二个参数的可选值如下:

#define FLASH_ACR_HLFCYA_Pos        (3U)   

#define FLASH_ACR_LATENCY_0         (0x1UL << FLASH_ACR_LATENCY_Pos)    /*!< 0x00000001 */
#define FLASH_ACR_LATENCY_1         (0x2UL << FLASH_ACR_LATENCY_Pos)    /*!< 0x00000002 */

#define FLASH_LATENCY_0             0x00000000U                         /*!< FLASH Zero Latency cycle */
#define FLASH_LATENCY_1             FLASH_ACR_LATENCY_0                 /*!< FLASH One Latency cycle */
#define FLASH_LATENCY_2             FLASH_ACR_LATENCY_1                 /*!< FLASH Two Latency cycles */

img

我们要使用某个外设,必须先使能该外设的时钟;