2. STM32L4时钟系统:HSI、MSI、LSE、LSI时钟源详解,系统时钟配置与切换,降低系统时钟频率对功耗的影响
时钟,是单片机的心脏。这话一点不夸张。
STM32L4的时钟系统,说实话,比F系列要复杂一些。但复杂有复杂的好处——它给了你更多选择,让你能在性能和功耗之间找到那个最舒服的平衡点。
我刚开始用L4的时候,也被一堆时钟源搞得有点懵。HSI、MSI、LSE、LSI……每个都有脾气。后来踩了几个坑,才慢慢摸清楚它们的性格。
2.1 四大时钟源,各有各的活法
先看一张总图,把四个时钟源的关系理清楚。
2.2 HSI:16 MHz 的硬汉
HSI,全称 High Speed Internal oscillator。16 MHz,RC振荡器,上电就干活。
它的优点是快。从复位到跑起来,几乎不需要等待。缺点是精度一般,温漂大概在 ±1% 到 ±2% 之间。
我有个项目做手持测温仪,环境温度从 -20°C 到 60°C 变化,HSI 的频偏就有点明显了。后来换了 MSI,问题解决。
2.3 MSI:低功耗场景的 MVP
MSI,Multi-Speed Internal oscillator。这是 STM32L4 的一大亮点。
它的频率范围很宽:100 kHz、200 kHz、400 kHz、800 kHz、1 MHz、2 MHz、4 MHz、8 MHz、16 MHz、24 MHz、32 MHz、48 MHz。一共 12 档,软件可调。
最厉害的是,MSI 可以自动跟随系统电压调整频率。电压高就跑快点,电压低就跑慢点。这在低功耗场景下非常实用。
| 时钟源 | 频率范围 | 典型精度 | 启动时间 | 典型功耗 |
|---|---|---|---|---|
| HSI | 16 MHz(固定) | ±1% ~ ±2% | ~1 μs | ~100 μA |
| MSI | 100 kHz ~ 48 MHz | ±0.25%(校准后) | ~2 μs | ~5 μA @ 100 kHz |
| LSE | 32.768 kHz(固定) | ±5 ppm(晶振决定) | ~1 s | ~0.5 μA |
| LSI | 32 kHz(固定) | ±5% ~ ±10% | ~50 μs | ~0.4 μA |
你看,MSI 在 100 kHz 时功耗只有 5 μA 左右。这比 HSI 的 100 μA 低了整整一个数量级。
2.4 LSE 与 LSI:两个低速好兄弟
LSE,Low Speed External。32.768 kHz 晶振,专门给 RTC 用的。
LSI,Low Speed Internal。32 kHz RC振荡器,专门给独立看门狗(IWDG)用的。
这两个时钟源,功耗极低,但精度天差地别。
LSE 的精度取决于外部晶振,好的晶振能做到 ±5 ppm。LSI 就粗糙多了,温漂可能到 ±10%。
我曾经在一个需要精确计时的项目里,用了 LSI 给 RTC 做时钟源。结果一天下来误差好几分钟。后来换成 LSE,一天误差不到 1 秒。
2.5 系统时钟配置与切换
系统时钟的配置,说白了就是告诉单片机:你从哪个时钟源拿时间,跑多快。
STM32L4 的系统时钟树,比 F 系列多了一个选择器。你可以随时在 HSI、MSI、PLL 输出之间切换。
下面是一个典型的配置流程:
- 复位后,默认使用 MSI(4 MHz)
- 使能目标时钟源(比如 HSI)
- 等待时钟源稳定(检查就绪标志位)
- 配置 AHB、APB 分频器
- 切换系统时钟源
- 等待切换完成
- 可以关闭原时钟源(可选)
代码实现其实不复杂。我用 HAL 库举个例子:
// 从 MSI 切换到 HSI
void SystemClock_Switch_HSI(void)
{
// 1. 使能 HSI
RCC->CR |= RCC_CR_HSION;
// 2. 等待 HSI 就绪
while(!(RCC->CR & RCC_CR_HSIRDY));
// 3. 配置分频器(这里保持 1 分频)
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_HPRE) | RCC_CFGR_HPRE_DIV1;
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PPRE) | RCC_CFGR_PPRE_DIV1;
// 4. 切换系统时钟到 HSI
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
// 5. 等待切换完成
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
// 6. 可以关闭 MSI(可选)
// RCC->CR &= ~RCC_CR_MSION;
}
嗯,这里要注意:切换时钟源的时候,一定要等新时钟稳定了再切。否则系统会直接挂掉。
2.6 降低系统时钟频率对功耗的影响
这个道理其实很简单:频率越低,功耗越低。
CMOS 电路的动态功耗公式是:P = C × V² × f。频率 f 降一半,功耗就降一半。
但实际效果比公式更明显。因为降低频率后,你可以降低供电电压(通过调压器),而电压的平方项对功耗影响更大。
我做过一个对比测试,数据如下:
| 系统时钟频率 | 供电电压 | 运行模式电流 | 说明 |
|---|---|---|---|
| 48 MHz | 1.8 V | ~8 mA | 全速运行 |
| 16 MHz | 1.2 V | ~2.5 mA | 日常处理 |
| 4 MHz | 1.0 V | ~0.8 mA | 轻度任务 |
| 100 kHz | 0.9 V | ~50 μA | 休眠前准备 |
从 48 MHz 降到 100 kHz,电流从 8 mA 降到了 50 μA。降了 160 倍。
2.7 我的低功耗时钟配置模板
最后,分享一个我常用的配置思路。这个模板在我好几个低功耗项目里都用过,效果不错。
- 上电初始化: 用 MSI 4 MHz 完成基本外设配置
- 任务处理: 切换到 HSI 16 MHz 或 PLL 48 MHz 快速处理
- 空闲等待: 切回 MSI 100 kHz,进入休眠模式
- 唤醒后: 根据任务需求,动态调整频率
这个流程的核心思想是:按需分配频率。不浪费一个 Hz。
时钟系统这块,说白了就是选对时钟源,配好频率,动态切换。掌握了这些,你的低功耗设计就成功了一半。