一、Cortex-M低功耗基础:睡眠模式与深度睡眠模式
各位工程师朋友,咱们直接进入正题。
做低功耗待机方案,你首先得搞清楚Cortex-M内核到底能睡多「沉」。我个人习惯把睡眠模式比作「打盹」,深度睡眠模式比作「昏睡」——两者功耗差了一个数量级,但唤醒代价也不同。
1.1 电源管理单元(PMU)在干什么?
PMU说白了就是内核的「大管家」。它负责监控电压、时钟,决定哪些模块该断电,哪些该保留。
我在项目中遇到过一个问题:明明进了深度睡眠,电流却还是几十毫安。查了半天,发现是PMU没把GPIO的时钟关干净。嗯,这里要注意——PMU只管内核和总线,外设的时钟你得自己动手。
核心要点:
- PMU控制着内核电压调节器(Core Regulator)
- 睡眠模式:只停CPU时钟,外设和RAM保持供电
- 深度睡眠模式:关闭CPU和大部分外设时钟,仅保留唤醒源
1.2 睡眠模式 vs 深度睡眠模式:一张表说清楚
| 对比项 | 睡眠模式(Sleep) | 深度睡眠模式(Deep Sleep) |
|---|---|---|
| CPU时钟 | 停止 | 停止 |
| 系统时钟(HCLK) | 运行 | 停止或降频 |
| 外设时钟 | 可继续运行 | 大部分关闭 |
| RAM保持 | 全部保持 | 可配置部分保持 |
| 典型功耗(STM32L4为例) | 约 100μA/MHz | 约 1μA 以下 |
| 唤醒延迟 | 几个时钟周期 | 几十微秒到几百微秒 |
你想想看,如果你的制氧机只需要每秒钟检测一次氧气浓度,深度睡眠模式就是最佳选择。但如果你需要快速响应按键或通信中断,睡眠模式更合适。
1.3 如何通过WFI/WFE指令进入低功耗?
WFI(Wait For Interrupt)和WFE(Wait For Event)是两条ARM指令,专门用来让内核「睡觉」。
WFI: 执行后CPU立即停止,直到有中断发生才醒来。
WFE: 执行后CPU停止,但可以被事件(Event)唤醒,不一定要中断。
我曾经踩过一个坑:用WFI进入睡眠后,发现中断来了但没唤醒。查了半天,原来是中断优先级配置错了——只有优先级高于当前阈值的才能唤醒。嗯,细节决定成败。
我的习惯做法:
在进入WFI之前,先清掉所有pending的中断标志位。否则一进去就被唤醒,等于白睡。
代码示例:进入睡眠模式(STM32G4系列)
// 进入睡眠模式(Sleep Mode)
void enter_sleep_mode(void)
{
// 1. 清除唤醒标志
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
// 2. 设置睡眠模式(默认就是Sleep)
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
// 3. 醒来后继续执行这里
// 注意:醒来后时钟配置不变
}
代码示例:进入深度睡眠模式(Stop Mode)
// 进入深度睡眠模式(Stop Mode)
void enter_stop_mode(void)
{
// 1. 配置电压调节器为低功耗模式
HAL_PWREx_EnableUltraLowPower();
HAL_PWREx_EnableFastWakeUp();
// 2. 选择深度睡眠模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 3. 醒来后需要重新配置系统时钟!
SystemClock_Config(); // 这个函数必须自己实现
}
避坑指南:
我曾经在深度睡眠唤醒后忘记重新配置时钟,结果系统跑在HSI的16MHz上,而我的外设需要64MHz。整个系统卡了三天才找到原因。记住:深度睡眠唤醒后,HSE/PLL等高速时钟默认是关闭的。
1.4 实际项目中的选择策略
做制氧机待机方案,我建议这样选:
- 待机时间 < 1秒: 用睡眠模式。唤醒快,功耗也能接受。
- 待机时间 > 5秒: 用深度睡眠模式。省下的电量很可观。
- 中间地带: 看你的电池容量。如果用的是纽扣电池,果断深度睡眠。
我记得有个项目,客户要求待机电流低于10μA。我们用了深度睡眠模式,配合RTC定时唤醒,最终做到了3.5μA。嗯,这个数字我记得很清楚,因为当时老板请全组喝了奶茶。
1.5 小结
Cortex-M的低功耗基础,说白了就是三件事:
- 搞清楚PMU能管什么、不能管什么
- 根据唤醒延迟需求选睡眠模式还是深度睡眠模式
- 用WFI/WFE指令让内核睡觉,但别忘了醒来后的时钟恢复
下一章我们会聊到外设的时钟门控和电源域划分,那才是真正「抠功耗」的地方。咱们到时候细说。
一句话记住:
睡眠模式省的是「时间」,深度睡眠模式省的是「电量」。选哪个,看你等不等得起那几百微秒。