STM32学习笔记3——时钟树

本文最后更新于:2024年11月4日 晚上

0x00 Reference

STM32中的几个时钟SysTick、FCLK、SYSCLK、HCLK - Darrick_Jan - 博客园

0x01 时钟树

image-20241016213810675

A部分表示其他电路需要的输入源时钟信号;B 为一个特殊的振荡电路“PLL”,由几个部分构成;C 为我们重点需要关注的 MCU 内的注释中“SYSCLK”;AHB 预分频器将 SYSCLK 分频或不分频后分发给其他外设进行处理,包括到 F 部分的 Cortex-M 内核系统的时钟。D 和 E 部分分别为定时器等外设的时钟源 APB1/APB2。G 是 STM32 的时钟输出功能,其他部分等我们学习到再详细探讨

0x02 时钟源

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

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

芯片上电时默认由内部的 HSI 时钟启动,如果用户进行了硬件和软件的配置,芯片才会根据用户配置调试尝试切换到对应的外部时钟源,所以同时了解这几个时钟源信号还是很有必要的。

0x03 锁相环PLL

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

锁相环PLL的输出也可以作为芯片系统的时钟源。配置PLL需要配置三个部分

image-20241017124355853

  1. 这部分是HSE分频器,HSE分频器可以作为PLL输入,通过PLLXTPRE寄存器来控制分频倍数,可以HSE设置2分频或者不分频
    image-20241017124917712
  2. 这部分是PLL 时钟源的选择器,PLL可以选择HSE或者HSI作为输入时钟源,通过PLLSRC寄存器控制
    image-20241017124925593
  3. 这部分是PLL倍频器,它可以对PLL的输入时钟信号进行倍频,可选择 2-16 倍频,通过PLLMUL寄存器控制
    image-20241017125158426

0x04 系统时钟SYSCLK

系统时钟SYSCLK为整个芯片提供时钟信号,也就是整个芯片的工作频率。系统时钟还作为其他外设提供时钟信号,其他外设、总线的时钟信号通过SYSCLK倍频或分频获得。

系统时钟可以选择三个来源:外部高速时钟 HSE(8M)、内部高速时钟 HSI(8M)和经过倍频的 PLL CLK

对于配置系统时钟来说,也就是配置时钟信号的来源

image-20241017130108099

0x05 总线时钟

目前已经得到的SYSCLK时钟,并不是内核直接的工作频率,也不是外设直接使用的频率,外设都是挂在总线上的,使用的是总线的频率。而SYSCLK是总线频率的来源。

STM32中的几个时钟SysTick、FCLK、SYSCLK、HCLK - Darrick_Jan - 博客园

HCLK

首先是HCLK,SYSCLK经过分频器得到HCLK,通常不分频

HCLK是AHB总线的频率,此外HCLK还为内存DMA提供频率

FCLK

提供给CPU内核的时钟信号,CPU的主频就是指这个信号

PCLK1

APB1总线时钟频率,由HCLK分频得到,一般使用二分频

PCLK2

APB1总线时钟频率,同样由HCLK分频得到,一般不分频

0x06 时钟配置

下图是STM32C8T6的一个配置图,可以看到其SYSCLK使用的是PLL三倍频后的HSE,使用此配置生成的初始化时钟代码如下

image-20241103231446336
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;//振荡器类型选择HSE
RCC_OscInitStruct.HSEState = RCC_HSE_ON;//HSE状态是打开
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;//HSE预分频是DIV1-不分频
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;//使用PLL锁相环
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;//PLL时钟来源选择HSE
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL3;//PLL选择3倍频
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)//调用HAL_RCC_OscConfig进行配置
{
Error_Handler();
}

/** Initializes the CPU, AHB and APB buses clocks
*/
//选择初始化的时钟 HCLK,SYSCLK,PCLK1,PCLK2
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;//SYSCLK时钟源选择PLL
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;//HCLK选择一倍频
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;//PCLK1选择一倍频
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;//PCLK2选择一倍频

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)//配置对应的时钟,并且设置FLASH读写0时延
{
Error_Handler();
}
}

HAL_RCC_ClockConfig的第二个参数是啥?

Flash的读写频率为24MHz,这里的c8t6的主频也是24MHz,所以Flash可以满足CPU每个周期都操作一次。但是当CPU主频继续提高,Flash的工作频率就跟不上CPU了,所以就需要设置时延。打个比方,CPU主频为72MHz,就需要设置时延为2个周期,也就是CPU操作Flash后需要等待2个周期,Flash才能被继续操作,相当于三分频来适应Flash的工作频率

0x07MCO输出时钟信号

STM32允许输出时钟信号,可以用来调试或者为其他设备提供时钟信号

MCO支持输出SYSCLK,HSI,HSE,PLL/2

将引脚复用为MCO,就可以输出设置的时钟信号了

image-20241104000630388


STM32学习笔记3——时钟树
https://goooforward.github.io/blog/2024/10/15/study/STM32学习笔记3——时钟树/
作者
tangyuwei
发布于
2024年10月15日
许可协议