RCC 概念篇——单片机的心跳从哪来


Ciallo(∠・ω< )⌒☆

系列专栏 直达链接
🔤 C 语言 进入专栏 →
🧱 数据结构 进入专栏 →
🔧 C++ 进入专栏 →
🐍 Python 进入专栏 →
🔌 STM32 进入专栏 →

🏠 博客主页:暖焰核心

📦 作者仓库:github | gitee

文章目录

  • 引言
    • [一、 节拍器](#一、 节拍器)
    • [二、 控制成本](#二、 控制成本)
      • [2.1 一笔成本账](#2.1 一笔成本账)
      • [2.2 与门](#2.2 与门)
      • [2.3 未使能时的读数](#2.3 未使能时的读数)
    • [三、 时钟树](#三、 时钟树)
      • [3.1 全图与三个部分](#3.1 全图与三个部分)
      • [3.2 树根、树干与树叶](#3.2 树根、树干与树叶)
    • [四、 时钟源](#四、 时钟源)
      • [4.1 四个原始时钟源](#4.1 四个原始时钟源)
      • [4.2 时钟的默认](#4.2 时钟的默认)
      • [4.3 倍频器 PLL](#4.3 倍频器 PLL)
      • [4.4 32.768 kHz 的由来](#4.4 32.768 kHz 的由来)
    • [五、 倍频与分频](#五、 倍频与分频)
      • [5.1 共享源头](#5.1 共享源头)
      • [5.2 72 MHz 的来路](#5.2 72 MHz 的来路)
      • [5.3 三个特殊分频](#5.3 三个特殊分频)
      • [5.4 MCO 时钟输出](#5.4 MCO 时钟输出)
    • [六、 外设使能](#六、 外设使能)
      • [6.1 一排时钟开关](#6.1 一排时钟开关)
      • [6.2 APB1 与 APB2 的外设归属](#6.2 APB1 与 APB2 的外设归属)
      • [6.3 RCC 的位置与寄存器](#6.3 RCC 的位置与寄存器)
    • [七、 HSE 的保命机制 CSS](#七、 HSE 的保命机制 CSS)
    • [八、 RTC 与看门狗的低速时钟](#八、 RTC 与看门狗的低速时钟)
      • [8.1 两个慢节奏计数器](#8.1 两个慢节奏计数器)
      • [8.2 一秒的由来](#8.2 一秒的由来)
      • [8.3 备份域与写保护](#8.3 备份域与写保护)
    • [九、 上电那一刻](#九、 上电那一刻)

引言

前几篇把灯点亮了、把按键读回来了,有一个问题:芯片里的 CPU 和那些外设,到底是被什么推着跑的?为什么同样是这块板子,时钟配好了能跑到 72 MHz,配不好就只能用默认的低频率?

答案是时钟。STM32F103 标称的 72 MHz 不是天上掉下来的,它是从一颗 8 MHz 的晶振出发,经过倍频、分频,一路分发到每个外设手里的。这棵分发网络在手册里画成一棵树,所以叫时钟树,而管着这棵树的外设叫 RCC(Reset and Clock Control,复位和时钟控制)。

一、 节拍器

CPU 看起来什么都能干,但它自己不会主动干活。取指令、分析指令、执行指令,每一步都要有人喊拍子,喊拍子的就是时钟。

时钟信号的本质是个方波:电压按固定周期在高电平和低电平之间来回跳。部件们在脉冲到来的瞬间动一下,其余时间原地待命。方波越密,一秒内动的次数越多,跑得越快;方波越疏,节奏越慢。

把 CPU 换成串口、I2C(Inter-Integrated Circuit,两线制的板级通信总线)也一样:串口收到一个脉冲发一个字节,I2C 收到一个脉冲传一次数据。整颗芯片都在等同一样东西,就是脉冲。所以「主频 72 MHz」翻译过来就是:一秒里有 7200 万个脉冲在催它干活。

麻烦在于,片上每个部件要的节奏还不一样。CPU 要最快的;看门狗一秒数一次就够;RTC 更慢,它计的是秒。怎么用尽量少的电路,喂出这么多不同频率的脉冲?时钟树就是这道题的答案。

二、 控制成本

2.1 一笔成本账

一颗 STM32F103ZET6 里挂着几十个片上外设,GPIO(General Purpose Input/Output,通用输入输出)、定时器、串口、I2C、SPI(Serial Peripheral Interface,串行外设接口)都在其列,但一块具体的板子往往只用得上其中一小部分。要是所有外设永远接着时钟,没人用的也在被脉冲一遍遍空催,电就白烧了。功耗高,供电和散热的水准就得跟着抬,产品成本上去了,市场竞争力就下来了。

2.2 与门

设计者的解法是让时钟进外设之前先过一道闸。电路上这道闸就是一个与门:时钟一路、使能信号一路,两路都有效,脉冲才放行;使能一断,外设这边彻底安静。

text 复制代码
            +-------+
时钟源 -----+  AND  +----- 外设的时钟输入
            +---^---+
                |
使能位 ---------+

所谓「使能外设时钟」,本质就是把这颗与门的闸抬起来。用哪个外设就开哪个的闸,不用的全部关着,功耗和自由度两头都占了。

2.3 未使能时的读数

注意:当外设时钟没有启用时,软件读它的寄存器,返回的数值始终是 0x0。

忘了开时钟就去操作外设,读回来的全是 0,写进去的也不生效。外设看起来「坏了」「失联了」,其实只是闸没开。很多「怎么写都没反应」的怪问题,原因就是这个。

三、 时钟树

3.1 全图与三个部分

时钟要有源,要能变出不同频率,还要能逐个开关。STM32 把这整套东西画成一张图,就是时钟树。

整张图看着密密麻麻,按频率高低其实能切成三块:右上一大块是高频区,驱动 CPU、内存和绝大多数片上外设,是日常开发真正打交道的主体;左下一块是低频区,喂 RTC 和独立看门狗这两个慢节奏设备;剩下一个小角是时钟输出,把内部时钟引出芯片给别人用。

3.2 树根、树干与树叶

这棵树有根有干有叶。

树根是时钟的发生源,内外各一套;树干负责倍频和选择,决定系统时钟跑多快;树枝是一级级分频器,把主干频率摊到各条总线;树叶就是一个个具体外设,每片叶子上还挂着自己的开关。后面三节就顺着树的结构走:先选树根,再理树干,最后开树叶。

四、 时钟源

4.1 四个原始时钟源

STM32F103 提供四个「原始时钟来源」,两内两外:

简称 全称 来源 频率 特点
HSI High Speed Internal 内部 RC 振荡器 8 MHz 上电即用,精度一般
HSE High Speed External 外部晶振 4~16 MHz,板载 8 MHz 精度高,要等起振
LSI Low Speed Internal 内部 RC 振荡器 40 kHz 喂独立看门狗
LSE Low Speed External 外部晶振 32.768 kHz 精度高,给 RTC 计秒

在时钟树全图上,它们就是被标出来的那四块:

RC 振荡器靠电阻电容的充放电产生振荡,成本低、说开就开,但频率会随温度和电压漂;外部晶振是石英的,稳得多,代价是占引脚、要等起振。高速这对恰好一内一外,低速这对也是。正经项目的主时钟用 HSE 图它稳,看门狗和 RTC 用低速那对,够用就好。

4.2 时钟的默认

芯片刚上电、一行代码都没跑的时候,系统时钟就是 HSI。证据写在 RCC_CR 的复位值里:0x0000 0083。低位拆开正好是 HSION(使能)和 HSIRDY(就绪)两位都为 1,也就是硬件设计成上电就把内部 8 MHz 振荡器开起来、等它稳定。

HSI 是内部 RC,不依赖任何外部电路,晶振焊没焊、焊得好不好都不影响它,所以芯片永远能靠它先转起来。后来把时钟切到更高频率是软件的事,但起步那一刻,是 HSI 在推着 CPU 跑。

它还能校准:RCC_CR 里有校准位,出厂值自动加载,默认能校到 8 MHz ±1% 左右;校准值每加一档,频率大约变 40 kHz。但再校也是 RC,跟石英晶振的稳定度没得比,这也是正经项目要把主时钟切到 HSE 的原因。

4.3 倍频器 PLL

严格数的话时钟源是四个,但树上还有个绕不开的角色:PLL(Phase Locked Loop,锁相环)。它自己不产生脉冲,而是把已有时钟「乘」出一个更高的频率,输出叫 PLLCLK,习惯上也算作一路时钟源。

它的输入可以二选一,由 PLLSRC 位决定:选 0 用 HSI 除以 2(4 MHz),选 1 用 HSE,还可以先经 PLLXTPRE 除 2 再进来。倍多少由 PLLMUL 位段决定,2 倍到 16 倍任选。注意:PLL 输出不得超过 72 MHz。

PLL 输入 输入频率 顶格输出
HSI ÷ 2 4 MHz 4 × 16 = 64 MHz
HSE 直入 8 MHz(板载) 8 × 9 = 72 MHz

这就解释了一个奇怪的现象:为什么用 HSI 当源头,系统最快只能到 64 MHz?4 × 16 就是 64,倍频系数到 16 就封顶了。

4.4 32.768 kHz 的由来

LSE 的频率看着别扭,其实是精心挑的:32768 正好是 2 的 15 次方。二进制分频器做「除以 2」最顺手,一条 15 级的分频链除到底,正好一秒一个脉冲。RTC 要的就是一秒一格的秒针,所以这颗晶振几乎是量身定做,钟表行业用了几十年,便宜又准。

五、 倍频与分频

5.1 共享源头

树根只有一两个,树叶却有几十片,频率需求各不相同,中间全靠倍频和分频变花样。

倍频是把一个周期拆成 n 个,频率乘 n;分频反过来,n 个周期并成一个,频率除以 n。图里同一条 8 MHz 的源,串口那边 ×2 后节奏翻倍,I2C 那边 ÷2 后节奏减半,各取所需。

5.2 72 MHz 的来路

从晶振到各条总线,每一级拆开看:

级 位段与配置 动作 输出频率
晶振 无 产生原始脉冲 HSE 8 MHz
PLL PLLSRC=1、PLLMUL 配 9 倍 8 × 9 PLLCLK 72 MHz
系统时钟 SW=10 选中 PLL SYSCLK 72 MHz
AHB HPRE 不分频 72 ÷ 1 HCLK 72 MHz
APB1 PPRE1 ÷ 2 72 ÷ 2 PCLK1 36 MHz
APB2 PPRE2 不分频 72 ÷ 1 PCLK2 72 MHz

这张表就是时钟树高频区的主干道:8 MHz 进门,PLL 乘 9 顶到 72 MHz,再由 AHB 摊给两条外设总线。APB1 有一条硬规定,手册原话是「软件必须保证 APB1 时钟频率不超过 36 MHz」,所以它至少得除 2。

AHB(Advanced High-performance Bus,高性能总线)跑高速成员,APB(Advanced Peripheral Bus,外设总线)专门挂外设,APB1 和 APB2 是它的两个档位。SYSCLK 是系统时钟,全芯片的根;HCLK 是 AHB 总线时钟,CPU、内存、DMA(Direct Memory Access,直接内存访问)挂在这条上;PCLK1、PCLK2 分别是 APB1、APB2 两条外设总线的时钟。CPU 内核还有个自由运行的 FCLK,一般与 HCLK 同频,不用特别操心。另外 Cortex 内核里的系统节拍定时器 SysTick,还可以选 HCLK 除以 8 当外部时钟,做精确延时的时候用得上。

5.3 三个特殊分频

定时器时钟会偷偷乘 2。 手册有条规则:APB 分频系数为 1 时,定时器时钟等于总线频率;分频系数不是 1 时,定时器时钟等于总线频率的 2 倍。上一节的配置里 APB1 除 2 得 36 MHz,挂在它下面的 TIM2 到 TIM7 拿到的是 36 × 2 = 72 MHz;APB2 没分频,TIM1 和 TIM8 直接拿 72 MHz。也就是说不管挂在哪条总线,定时器最后拿到的都是 72 MHz,硬件替你把频率补齐了。不知道这条的话,算定时周期一定会算错。

总线 本篇分频 总线频率 定时器实际时钟
APB1 ÷ 2 36 MHz 36 × 2 = 72 MHz
APB2 ÷ 1 72 MHz 72 × 1 = 72 MHz

USB 的 48 MHz 是除 1.5 除出来的。 USB(Universal Serial Bus,通用串行总线)全速设备要 48 MHz,可主干线上没有这个数(72 ÷ 2 是 36,72 ÷ 1 是 72)。硬件给 USB 单独留了个预分频器 USBPRE:72 ÷ 1.5 = 48,正好。手册还特别提醒,这个位要在使能 USB 时钟之前配好。

ADC 的时钟上限是 14 MHz。 ADC(Analog-to-Digital Converter,模数转换器)挂在 APB2 上,但有专门的预分频器 ADCPRE,从 PCLK2 里除 2、4、6、8 取一路。72 ÷ 2 = 36、72 ÷ 4 = 18,都超了 14 MHz 的上限,主频跑满时只能选 ÷ 6(12 MHz)或 ÷ 8(9 MHz)。分频档位摆在那,不代表每一档都能用。

5.4 MCO 时钟输出

时钟树还有个对外的小窗口:MCO(Microcontroller Clock Output,微控制器时钟输出),把内部选中的时钟直接送到一个 GPIO 引脚上,给片外设备当节奏,或者接示波器量一下,验证配置到底对没对。可选的源有 SYSCLK、HSI、HSE 和 PLL 二分频四种,靠 MCO[2:0] 三个位选。要留意的只有引脚的物理极限:输出不得超过 50 MHz,这是 I/O 口的速度上限,不是时钟树的。

六、 外设使能

6.1 一排时钟开关

前面说每个外设的时钟都过一道与门,那这些与门的使能端接在哪?答案是几个专门的寄存器。它们就是一排开关的集合:每一位管一个外设的时钟,写 1 闭合、写 0 断开。

看 RCC_APB1ENR 的位分布,每一位都写着一个外设的名字:TIM2EN、TIM3EN、SPI2EN、I2C1EN......想让谁收到时钟脉冲,就把对应位写成 1。前面点灯代码里的 __HAL_RCC_GPIOx_CLK_ENABLE,本质上就是在往这类寄存器的某一位写 1。

6.2 APB1 与 APB2 的外设归属

哪些外设挂 APB1、哪些挂 APB2,从两个使能寄存器的位分布就能读全:

总线 挂载的外设
APB2(最高 72 MHz) GPIOA 到 GPIOG、AFIO、USART1、SPI1、TIM1、TIM8、ADC1/ADC2/ADC3
APB1(最高 36 MHz) TIM2 到 TIM7、USART2/USART3、UART4/UART5、I2C1/I2C2、SPI2/SPI3、USB、CAN、DAC、PWR、BKP、WWDG

跟速度相关的都往 APB2 挤,GPIO、高速串口、高速定时器、ADC 都在;慢速通信和电源管理类的外设留在 APB1。以后拿到一个新外设,先查它挂在哪条总线,时钟使能位就在对应的寄存器里。

表里几个眼生的:AFIO 是复用功能 IO,管引脚的第二职业;CAN 是车载总线;DAC 是数模转换器;WWDG 是窗口看门狗,与独立看门狗相对;PWR 和 BKP 分别是电源控制和备份接口,第八节备份域还会见到它们。

在 ZET6 这类大容量型号上,APB1 的定时器是 TIM2 到 TIM7 一共六个,不是只有 TIM2 到 TIM4。手册的位图里 TIM5EN、TIM6EN、TIM7EN 都在,别按只有三个来配。

6.3 RCC 的位置与寄存器

RCC 就是这整棵树的物业管理处:它自己挂在 AHB 总线上,手里握着全树所有选择器、分频器和与门的开关。

它名下的寄存器一共八个,各管一摊:

寄存器 管什么
RCC_CR 四个时钟源的开关与就绪标志、PLL 开关、CSS 开关
RCC_CFGR 分频倍频系数、系统时钟切换、MCO、ADC 与 USB 预分频
RCC_CIR 时钟相关中断的使能与标志
RCC_AHBENR AHB 外设时钟使能(DMA、FSMC、CRC 这些)
RCC_APB2ENR APB2 外设时钟使能
RCC_APB1ENR APB1 外设时钟使能
RCC_BDCR 备份域:LSE 与 RTC 的开关、备份域复位
RCC_CSR 复位原因记录、LSI 开关

RCC_AHBENR 的复位值是 0x0000 0014,不是 0。拆开正好是 SRAMEN(SRAM 接口)和 FLITFEN(闪存接口)两位默认为 1;反过来,DMA、CRC(循环冗余校验)、FSMC(外部存储器控制器)这些的时钟默认全是关的。

七、 HSE 的保命机制 CSS

树根有两棵,只挑一棵用就有个隐患:万一它停了呢?高温、线路老化、晶振虚焊,任何一样都能让 HSE 突然没了输出。而 HSE 一停,PLL 跟着断,CPU 和全部外设瞬间停摆,设备就死在那了。

CSS(Clock Security System,时钟安全系统)就是为这一刻准备的。它平时盯着 HSE,一旦检测到失效,硬件立刻做三件事:关掉 HSE 和 PLL、把系统时钟强制切回 HSI 的 8 MHz、产生一个 NMI(Non-Maskable Interrupt,不可屏蔽中断)通知软件来收拾残局。整个过程不需要软件参与,等软件收到中断时,芯片已经在 8 MHz 上活着了。

NMI 是一类不能被屏蔽的中断。普通中断可以因为优先级或关中断被暂时拦住,它不行,所以系统级的急事交给它正合适。

注意这个保护是单向的:只有 HSE 挂了会自动切 HSI,反过来 HSI 挂了没有切 HSE 的机制,规格里根本不存在「HSI 失效检测」这回事。工业设备里这套机制很常见:主时钟出事,系统至少能以低频率活着,把故障上报出去或者安全停机,而不是直接失控。

八、 RTC 与看门狗的低速时钟

8.1 两个慢节奏计数器

时钟树的低频区专门伺候两个慢家伙:RTC(Real-Time Clock,实时时钟)和 IWDG(Independent Watchdog,独立看门狗)。这俩本质都是计数器:RTC 往上加,一秒加一,记的是当前时刻;IWDG 往下减,减到 0 就把整个芯片复位。程序跑飞了不再喂狗,计数器减到底,系统自动重启,这就是看门狗的看家本领。

它们更新一次都是秒级、毫秒级的事,MHz 级的时钟纯属浪费,kHz 就够。

8.2 一秒的由来

RTC 的时钟源三选一:LSE(32.768 kHz)、LSI(40 kHz)或者 HSE 除以 128。首选 LSE,主电源断了它还能靠纽扣电池继续走;看门狗则只能用 LSI,独立运行,不受外部晶振影响,不然晶振一出事,连负责「看门」的都躺了。

32.768 kHz 进了 RTC 还要再分频,默认分频系数是 32768,除完正好一秒一个脉冲,这正是 4.4 节那个数字的选择理由。要是非要选 HSE 当源,就得自己重新算:8 MHz 先除 128 得 62500 Hz,再配一个 62500 的分频,一样凑得出 1 Hz。能凑,但没必要。

8.3 备份域与写保护

RTC 和 LSE 这几个开关住在一个特殊区域:备份域。这块区域由 VBAT 引脚供电,那颗纽扣电池接的正是它:主电源一断,电池顶上,里面的寄存器和时钟配置在整机断电后依然还在。

代价是写保护:RCC_BDCR 里的 LSEON、RTCSEL 这些位在复位后是锁死的,得先把电源控制寄存器里的 DBP 位(解除备份域写保护)置 1 才能改。设计意图也好理解:备份域的价值就在于「别的都动了它也别动」,要是任何一次复位都能随手改它的配置,掉电续时就没意义了。

九、 上电那一刻

芯片上电后的全过程:

text 复制代码
选时钟源 -------> 配倍频与分频 -------> 使能外设
(HSE/HSI)       (PLL与各级分频)       (ENR 位段)

刚上电时 RCC_CR 的复位值里 HSION 已置 1,HSI 的 8 MHz 先跑起来,CPU 靠它取指执行;想跑满 72 MHz,就按第一步选 HSE 当源,第二步把 PLL 配成 9 倍、各级分频配好,切过去;之后每用到一个新外设,第三步把 RCC_APB2ENR 或 RCC_APB1ENR 里对应的那位写成 1,闸一开,脉冲就到了。

这套配置过程在 CubeMX(ST 的图形化配置工具)里被画成了可视化的时钟树:每个选择器、每级分频都是个下拉框,改一个数,全树的频率跟着重算。

对照着前面那棵树看这张截图,其实还是那三步:左边选树根,中间调树干,右边开树叶。软件只是把手册里的位段翻译成了下拉框。

芯片跑多快,不是晶振单方面说了算,也不是代码说了算,是时钟树上每一个选择器和分频器的配置共同决定的。8 MHz 进树根,9 倍频上主干,一排开关分发到树叶,RCC 管的就是这一切。


相关推荐
Naisu Xu1 小时前
AGM SOC AG32VF407(MCU+CPLD)点灯测试
单片机·嵌入式硬件
送外卖的工程师14 小时前
STM32智能家庭安防系统
stm32·单片机·嵌入式硬件
送外卖的工程师14 小时前
STM32智能消毒柜
stm32·单片机·嵌入式硬件
CodeFragment15 小时前
裸机开发速记:启动流程|GIC 中断|时钟系统|UART 通信
arm开发·单片机·嵌入式硬件
ebiobiz15 小时前
基于 GD32 Embedded Builder (GEB) 与 Nimmake 的 MCU 工程搭建指南
c++·python·单片机·嵌入式硬件·mcu
额额额对了16 小时前
SPI通信
linux·c语言·汇编·单片机·嵌入式硬件·arm
创界工坊工作室16 小时前
14-基于stm32的水肥一体化灌溉系统设计
stm32·单片机·嵌入式硬件
斑马13917 小时前
ARM学习笔记(八)——PWM与ADC
单片机·嵌入式硬件
恒锐丰科技林技术员18 小时前
EG2106 半桥 MOS/IGBT 驱动芯片解析与工程应用
经验分享·嵌入式硬件·硬件工程