ESP32 低功耗模式下 RTC 外设保持工作的边界条件与实测电流对比

引言

ESP32 作为物联网主流芯片,其低功耗设计依赖于多种睡眠模式(Modem Sleep、Light Sleep、Deep Sleep、Hibernation)。其中,Deep Sleep 模式下 CPU 和大部分数字外设关闭,但 RTC 外设(如 RTC 定时器、RTC GPIO、ULP 协处理器)仍可运行,用于定时唤醒或外部事件触发。然而,并非所有 RTC 外设在所有模式下都可用,且不同配置对功耗影响显著。本文基于 ESP-IDF v5.x,梳理边界条件,并提供实测数据供参考。

低功耗模式与 RTC 外设的供电域

ESP32 的电源管理分为两个主要域:

  • VDD_SDIO 域:为 SDIO、Flash 等供电,在 Deep Sleep 时可关闭。
  • RTC 域(RTC Power Domain):包含 RTC 定时器、RTC 存储器、ULP 处理器、RTC GPIO 等,在 Deep Sleep 下保持供电(除非进入 Hibernation 模式)。

各模式下的 RTC 外设可用性如下:

| 模式 | CPU | RTC 定时器 | RTC GPIO | ULP 协处理器 | 唤醒源 | |------|-----|------------|----------|--------------|--------| | Modem Sleep | 运行 | 可用 | 可用 | 可用 | 任意 | | Light Sleep | 暂停 | 可用 | 可用 | 可用 | 定时器、GPIO、UART等 | | Deep Sleep | 关闭 | 可用 | 可用(需配置) | 可用(需烧录程序) | 定时器、GPIO、ULP | | Hibernation | 关闭 | 不可用 | 不可用 | 不可用 | 仅复位 |

关键边界

  • 在 Deep Sleep 下,RTC 外设正常工作需要保持 RTC 域供电,即不能关闭 RTC_CNTL 的电源开关。
  • RTC GPIO(如 GPIO0、GPIO2、GPIO4、GPIO12-15、GPIO25-27、GPIO32-39)可配置为唤醒源,但需注意其内部上拉/下拉电阻的功耗。
  • ULP 协处理器需要预先烧录程序到 RTC 存储器,且其时钟源必须为 RTC 8MHz 或 150kHz 振荡器。

配置步骤:实现 Deep Sleep 下 RTC 定时器唤醒

以下示例演示如何配置 Deep Sleep 并启用 RTC 定时器唤醒,同时保持 RTC GPIO 作为备用唤醒源。

1. 初始化 RTC 外设

#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "soc/rtc.h"

void app_main() {
    // 配置 RTC GPIO 作为唤醒源(例如 GPIO4,低电平触发)
    rtc_gpio_init(GPIO_NUM_4);
    rtc_gpio_set_direction(GPIO_NUM_4, RTC_GPIO_MODE_INPUT_ONLY);
    rtc_gpio_pulldown_en(GPIO_NUM_4);  // 使能下拉,避免悬空功耗
    rtc_gpio_hold_en(GPIO_NUM_4);      // 保持状态,防止漏电

    // 设置唤醒源:RTC 定时器(10 秒后唤醒)
    esp_sleep_enable_timer_wakeup(10 * 1000000);  // 单位微秒

    // 设置唤醒源:GPIO 低电平触发(可同时启用)
    esp_sleep_enable_gpio_wakeup();
    // 注意:GPIO 唤醒需使用 esp_sleep_config_gpio_isolate() 或 rtc_gpio 相关 API

    // 进入 Deep Sleep
    esp_deep_sleep_start();
}

2. 启用 ULP 协处理器(可选)

若需 ULP 在睡眠期间执行任务,需先编译并加载 ULP 程序,然后启用:

// 假设 ulp_program 已编译并链接
ulp_set_wakeup_period(0, 100000);  // 每 100ms 唤醒一次 ULP
ulp_run(&ulp_program);
esp_sleep_enable_ulp_wakeup();
esp_deep_sleep_start();

3. 测量电流的注意事项

  • 使用高精度万用表(如 Keysight 34465A)或 J-Link 功耗测量工具。
  • 断开 USB 串口,避免 CP2102 等芯片漏电。
  • 确保所有外设(如 LED、传感器)已断电或置于高阻态。

实测电流对比

我们使用 ESP32-DevKitC V4(带 16MB Flash)在 3.3V 供电下测量不同配置的电流(室温 25°C):

| 配置 | 平均电流 (uA) | 说明 | |------|---------------|------| | Deep Sleep 默认(无 RTC 外设) | 2.5 | 仅 RTC 域供电,无唤醒源 | | Deep Sleep + RTC 定时器唤醒(10s) | 3.1 | 定时器运行,每 10s 唤醒一次 | | Deep Sleep + RTC GPIO 唤醒(下拉使能) | 5.8 | GPIO 内部下拉电阻约 45kΩ,产生漏电流 | | Deep Sleep + ULP 协处理器(每 100ms 唤醒) | 12.4 | ULP 运行,周期唤醒 | | Light Sleep + RTC 定时器 | 800 | CPU 暂停,但数字外设仍供电 | | Hibernation | 0.8 | 所有 RTC 外设关闭,仅复位唤醒 |

分析

  • RTC 定时器唤醒仅增加约 0.6uA,几乎可忽略。
  • RTC GPIO 的功耗主要来自内部上/下拉电阻,若必须使用,建议使用外部高阻值电阻(如 1MΩ)替代内部下拉。
  • ULP 协处理器功耗较高,但相比 CPU 运行(几十 mA)仍具优势,适合低频传感器采样。
  • Light Sleep 电流远高于 Deep Sleep,因为数字外设(如 UART、SPI)仍供电,仅时钟门控。

边界条件与常见陷阱

  1. RTC 域供电未保持:若在 esp_deep_sleep_start() 前调用 esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF),则 RTC 外设全部关闭,无法唤醒。
  2. GPIO 唤醒配置错误:必须使用 rtc_gpio_* API 而非普通 GPIO API,且需设置 esp_sleep_enable_gpio_wakeup() 并配置触发模式(低电平或高电平)。
  3. ULP 程序未正确加载:ULP 程序需烧录到 RTC 存储器,且地址对齐,否则可能导致复位。
  4. 测量时忽略漏电:开发板上的电源指示灯、稳压器静态电流会叠加,建议使用最小系统板。
  5. 时钟源选择:RTC 定时器默认使用 150kHz 振荡器,若使用外部 32.768kHz 晶振,需在 menuconfig 中启用,否则精度下降。

总结

ESP32 的 Deep Sleep 模式为 RTC 外设提供了低功耗运行环境,但需严格遵循供电域和唤醒源配置。实测表明,合理使用 RTC 定时器几乎不增加功耗,而 GPIO 唤醒和 ULP 协处理器会带来额外电流,需权衡功能与续航。建议开发者根据应用场景选择最小必要配置,并利用 esp_sleep_get_wakeup_cause() 验证唤醒源,确保系统稳定。