4、低功耗模式详解(中):Stop 0/1/2模式差异对比、SRAM与寄存器保持策略、RTC与LPUART在Stop模式下的唤醒能力

上一节我们把STM32L4的几种睡眠模式捋了一遍。今天重点聊聊Stop模式——这玩意儿在实际项目中用得最多,坑也最多。

Stop模式说白了就是CPU停了,但SRAM和寄存器还能选着保留。L4系列把Stop分成了三档:Stop 0、Stop 1、Stop 2。我刚开始接触时也觉得不就是个Stop嘛,分这么细干嘛?后来在做一个电池供电的传感器节点时才发现,这三档的功耗和唤醒速度差异,直接决定了产品能不能撑过标称的续航时间。

Stop 0 / Stop 1 / Stop 2 到底差在哪?

先看一张对比表,心里有个底:

特性 Stop 0 Stop 1 Stop 2
CPU时钟 关闭 关闭 关闭
SRAM1保持 全部 全部 全部
SRAM2保持 全部 全部 可选(默认关闭)
寄存器保持 全部 全部 全部
内部调压器 范围1(高性能) 范围2(低功耗) 范围2(低功耗)
典型电流 ~200 μA ~45 μA ~3 μA
唤醒时间 ~5 μs ~8 μs ~15 μs
主要用途 快速响应 平衡模式 超低功耗待机

看到没?Stop 0的电流是Stop 2的将近70倍。但唤醒时间也快了3倍。这就是典型的「用功耗换速度」。

我个人习惯是:如果应用需要频繁唤醒(比如每10ms一次),我会选Stop 0,因为唤醒快,整体平均功耗反而低。如果唤醒间隔在100ms以上,Stop 2更划算。

SRAM与寄存器的保持策略

这里有个容易翻车的地方——SRAM2的保持。

Stop 2模式下,SRAM2默认是掉电的。如果你在SRAM2里放了关键数据,醒来发现全丢了,那可就麻烦了。

我记得有一次调试一个数据记录仪,每次从Stop 2唤醒后,采集到的数据总是对不上。查了两天才发现,环形缓冲区放在了SRAM2,而我没有在进入Stop 2前做保持配置。

正确的做法是这样:

// 保持SRAM2在Stop 2模式下不掉电
if (HAL_PWREx_EnableSRAM2Content() != HAL_OK)
{
    Error_Handler();
}

// 进入Stop 2模式
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);

寄存器方面,L4做得比较厚道——所有内核寄存器和外设寄存器在Stop模式下都保持。这意味着你不需要像在Standby模式下那样,醒来后重新初始化一堆东西。

我的经验:虽然寄存器保持,但有些外设的FIFO或数据缓冲区在Stop模式下会清空。比如LPUART的接收FIFO,如果你在进入Stop前没把数据读走,醒来就没了。我一般会在进入Stop前把FIFO清干净。

RTC与LPUART的唤醒能力

Stop模式下,哪些外设还能干活?这是选型的关键。

RTC和LPUART是Stop模式下最常用的两个唤醒源。它们各自的特点很鲜明:

  • RTC唤醒:定时精准,功耗极低(~1 μA),适合周期性唤醒
  • LPUART唤醒:异步触发,适合外部事件驱动,但需要额外配置

RTC的配置比较简单,我直接贴一段常用的:

// 配置RTC每10秒唤醒一次
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 10, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);

// 进入Stop模式,等待RTC唤醒
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);

LPUART的唤醒就有点讲究了。它支持两种唤醒方式:地址匹配唤醒和起始位唤醒。

地址匹配唤醒适合多机通信场景——只有地址匹配时才会唤醒MCU。起始位唤醒则更通用,任何数据到来都能唤醒。

注意:LPUART在Stop模式下唤醒,需要确保LPUART的时钟源是LSE或LSI。如果用HSI或MSI,进入Stop后时钟就断了,LPUART直接罢工。我见过有人在这上面折腾了一整天。

配置LPUART起始位唤醒的代码:

// 使能LPUART的Stop模式唤醒
HAL_UARTEx_EnableStopMode(&hlpuart1);

// 配置接收中断
HAL_UART_Receive_IT(&hlpuart1, &rx_byte, 1);

// 进入Stop模式
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);

醒来后,LPUART的中断服务函数会正常执行。但要注意——唤醒后系统时钟需要重新配置,因为Stop模式下HCLK和PCLK都停了。

Stop模式选择决策流程

说了这么多,到底怎么选?我画了个流程图,帮你快速决策:

Stop模式选择决策流程 Stop模式选择决策流程 进入Stop模式 唤醒间隔 < 50ms? (频繁唤醒场景) 是 Stop 0 ~200 μA / ~5 μs唤醒 否 唤醒间隔 < 500ms? (中等频率场景) 是 Stop 1 ~45 μA / ~8 μs唤醒 否 Stop 2 ~3 μA / ~15 μs唤醒 选型建议 • 唤醒间隔 < 50ms → Stop 0:唤醒快,整体平均功耗低 • 唤醒间隔 50ms~500ms → Stop 1:功耗与唤醒速度的平衡点 • 唤醒间隔 > 500ms → Stop 2:极致省电,注意SRAM2保持配置 • 如果使用LPUART唤醒,确保时钟源为LSE/LSI

实际项目中的避坑指南

最后分享几个我踩过的坑:

  • GPIO状态保持:进入Stop前,把不用的GPIO设为模拟模式或上拉/下拉固定电平。浮空引脚在Stop模式下会漏电,我曾经因为这个多耗了10 μA。
  • DMA传输:Stop模式下DMA会停止。如果你用DMA做外设数据传输,进入Stop前要确保DMA传输完成,否则醒来后DMA状态可能异常。
  • 唤醒后时钟恢复:Stop 0/1/2唤醒后,系统时钟会自动恢复到进入前的配置。但如果你用了MSI作为系统时钟,唤醒后MSI需要重新校准,这段时间大概几个微秒,对时序敏感的应用要注意。

一句话总结:Stop 0适合快速响应,Stop 2适合超低功耗待机,Stop 1是中间态。选型时先看唤醒间隔,再看外设需求,最后别忘了SRAM2的保持配置。