news 2026/9/18 5:16:29

ESP-IDF 睡眠模式完全指南:Light-sleep 与 Deep-sleep 的唤醒源、掉电选项与实战配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESP-IDF 睡眠模式完全指南:Light-sleep 与 Deep-sleep 的唤醒源、掉电选项与实战配置

ESP-IDF 睡眠模式完全指南:Light-sleep 与 Deep-sleep 的唤醒源、掉电选项与实战配置

【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf

导读

本文是 ESP-IDF 官方文档 sleep_modes.rst 的系统化技术解读,覆盖 ESP32 系列 SoC 的两大省电模式(Light-sleep 轻睡眠与 Deep-sleep 深睡眠)、全部可用的唤醒源(Timer、Touchpad、ext0/ext1、ULP、USB、GPIO、UART 等)、掉电域配置(Power-down Options)以及 Flash 在睡眠期间的省电策略。读完本文,你将能够依据具体应用场景选择正确的睡眠模式与唤醒源组合,并借助 esp_sleep.h 中完整的 API 与 deep_sleep、light_sleep 示例代码,搭建出可落地、低功耗的固件方案。


一、睡眠模式总览:Light-sleep 与 Deep-sleep 的本质区别

ESP-IDF 支持两大类省电模式,其核心差异在于"哪些电路保持供电、哪些电路被关断、唤醒后状态是否保留":

  • Light-sleep(轻睡眠):数字外设、大部分 RAM 与 CPU 被时钟门控(clock-gated),供电电压被降低。退出 Light-sleep 后,数字外设、RAM、CPU 恢复运行,内部状态被完整保留——本质上更像一次"暂停-恢复"。
  • Deep-sleep(深睡眠):CPU、大部分 RAM、所有由 APB_CLK 提供时钟的数字外设都被断电。仅以下部分保持上电:
    • RTC 控制器;
    • 支持 ULP 的芯片上:ULP 协处理器(:SOC_ULP_SUPPORTED 条件);
    • 支持 RTC FAST memory 的芯片上:RTC FAST 内存;
    • 支持 RTC SLOW memory 的芯片上:RTC SLOW 内存。

在 esp_sleep.h 中,两种模式由枚举esp_sleep_mode_t明确区分:

typedef enum { ESP_SLEEP_MODE_LIGHT_SLEEP, //!< light sleep mode ESP_SLEEP_MODE_DEEP_SLEEP //!< deep sleep mode } esp_sleep_mode_t;

Wi-Fi / Bluetooth 与睡眠模式的关系

在 Deep-sleep 和 Light-sleep 模式下,无线外设(Wi-Fi/BT)均被断电。进入睡眠前,应用必须显式关闭无线协议栈,相关调用包括:

  • esp_wifi_stop()(关闭 Wi-Fi);
  • nimble_port_stop()nimble_port_deinit()(关闭 NimBLE 协议栈);
  • esp_bluedroid_disable()esp_bluedroid_deinit()(关闭 Bluedroid);
  • esp_bt_controller_disable()esp_bt_controller_deinit()(关闭 BT 控制器)。

注意:即使不调用这些函数,睡眠模式下 Wi-Fi/Bluetooth 连接也不会被维持。若必须保持连接,应启用Wi-Fi/Bluetooth Modem-sleep 模式 + 自动 Light-sleep 特性(见 power_management.rst),系统会在驱动需要时自动唤醒以维持连接。

子睡眠模式(仅 ESP32-S2 / ESP32-S3 / ESP32-C2 / ESP32-C3)

对支持 ULP 的芯片,睡眠系统会根据应用所需功能自动选择功耗最低且满足全部需求的子睡眠模式。下表列出各子模式支持的功能(Y 表示支持):

Deep-sleep 子模式:

功能DSLP_ULTRA_LOWDSLP_DEFAULTDSLP_8MD256/DSLP_ADC_TSENS
ULP/Touch sensor(仅 ESP32-S2、S3)YYY
RTC IO 输入 / 高温下使用 RTC 内存YY
ADC_TSEN_MONITORY
8MD256 作为 RTC_SLOW_CLK 时钟源Y

Light-sleep 子模式:

功能LSLP_DEFAULTLSLP_ADC_TSENSLSLP_8MD256LSLP_LEDC8M/LSLP_XTAL_FPU
ULP/Touch sensor(仅 ESP32-S2、S3)YYYY
RTC IO 输入 / 高温下使用 RTC 内存YYYY
ADC_TSEN_MONITORYYY
8MD256 作为 RTC_SLOW_CLK 时钟源YY
数字外设使用 8 MHz RC 时钟Y
保持 XTAL 时钟开启Y

子模式由以下 API 与 Kconfig 选项触发:

  1. 超低功耗(实验性):禁用"RTC IO 输入 / 高温 RTC 内存"后芯片可进入超低功耗模式,由esp_sleep_sub_mode_config()配合ESP_SLEEP_ULTRA_LOW_MODE参数控制。
  2. ADC_TSEN_MONITOR:由 ULP 控制的 ADC/温度传感器监视模式,通过ulp_adc_init()或更上层 API 启用(仅支持监视模式的 ESP32-S2/S3)。
  3. 8MD256 时钟源:当通过 Kconfig 选项CONFIG_RTC_CLK_SRC_INT_8MD256选择 8MD256 作为 RTC_SLOW_CLK 时钟源时,Deep-sleep 期间芯片自动进入对应子模式。
  4. Light-sleep 中的 8 MHz RC 时钟:目前仅 LEDC 在 Light-sleep 使用该时钟源,选中后该特性自动开启。
  5. 保持 XTAL 时钟开启:由ESP_PD_DOMAIN_XTAL掉电域控制。

芯片差异提示:ESP32-S2 对 LSLP_8MD256、LSLP_LEDC8M、LSLP_XTAL_FPU 使用同一功耗模式;ESP32-S3 默认即支持 ADC_TSEN_MONITOR;ESP32-C2/C3 没有 ADC_TSEN_MONITOR 与 LSLP_ADC_TSENS 特性。


二、唤醒源(Wakeup Sources)详解

所有唤醒源均通过esp_sleep_enable_X_wakeup系列 API 启用。唤醒源在唤醒后不会自动关闭,若不再需要,应调用esp_sleep_disable_wakeup_source()显式禁用(传ESP_SLEEP_WAKEUP_ALL可一次性关闭全部唤醒源)。多个唤醒源可以同时启用,任意一个被触发即可唤醒芯片。在 esp_sleep.h 中,唤醒原因由esp_sleep_source_t枚举完整定义。

1. 定时器唤醒(Timer)

RTC 控制器内置定时器,可在预定义时间后唤醒芯片。时间以微秒精度指定,但实际分辨率取决于 RTC_SLOW_CLK 所选时钟源。此唤醒模式不需要RTC 外设或 RTC 内存保持上电。

esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us);

从源码看(esp_sleep.h),time_in_us的有效范围受lp_timer/rtc_timer计数器位宽与当前慢速时钟源限制:有效值须小于RTC 慢速时钟周期 × (2 ^ RTC 定时器位宽),越界返回ESP_ERR_INVALID_ARG

2. 触摸板唤醒(Touchpad)

RTC IO 模块内含触摸传感器中断唤醒逻辑,需在进入 Deep-sleep/Light-sleep之前完成触摸中断配置,再调用:

esp_err_t esp_sleep_enable_touchpad_wakeup(void);

注意(ESP32 适用):revision 0/1 的 ESP32 仅在 RTC 外设未被强制上电时(即ESP_PD_DOMAIN_RTC_PERIPH设为ESP_PD_OPTION_AUTO)才支持触摸唤醒;且触摸唤醒源不能与ext0唤醒同时使用。

3. 外部唤醒 ext0(单引脚电平触发)

RTC IO 模块可在某个 RTC GPIO 达到预定义电平(高或低)时触发唤醒。ext0 依赖 RTC 外设电源域,因此启用该唤醒源后RTC 外设在 Deep-sleep 期间会保持上电,此时内部上拉/下拉电阻可用:

rtc_gpio_pullup_en(gpio_num); rtc_gpio_pulldown_en(gpio_num); esp_sleep_enable_ext0_wakeup(gpio_num, level); // level: 0=low, 1=high

平台限制(源码 esp_sleep.h):仅 RTC 功能的 GPIO 可用——ESP32 为 0、2、4、12-15、25-27、32-39;ESP32-S2/S3 为 0-21。ESP32 revision 0/1 中 ext0 与 ULP、触摸唤醒不兼容。

警告:从睡眠唤醒后,用于唤醒的 IO pad 会被配置为 RTC IO。在将其作为数字 GPIO 使用前,必须调用rtc_gpio_deinit()重新配置。

4. 外部唤醒 ext1(多引脚组合)

ext1 由 RTC 控制器实现,支持在多个RTC GPIO 上按逻辑函数触发唤醒,且即使在 RTC 外设掉电时也有效:

  • ESP32ESP_EXT1_WAKEUP_ANY_HIGH(任一选中引脚为高)/ESP_EXT1_WAKEUP_ALL_LOW(所有选中引脚为低);
  • 其他芯片(S2/S3/C6/H2 等):ESP_EXT1_WAKEUP_ANY_HIGH/ESP_EXT1_WAKEUP_ANY_LOW

从源码看(esp_sleep.h),ESP_EXT1_WAKEUP_ALL_LOW在 ESP32 之后已被标记为 deprecated,取而代之的是ESP_EXT1_WAKEUP_ANY_LOW

当前推荐使用新增的分引脚管理 API:

esp_err_t esp_sleep_enable_ext1_wakeup_io(uint64_t io_mask, esp_sleep_ext1_wakeup_mode_t level_mode); // 追加 IO esp_err_t esp_sleep_disable_ext1_wakeup_io(uint64_t io_mask); // 移除 IO,传 0 清除全部

旧的esp_sleep_enable_ext1_wakeup(io_mask, level_mode)每次调用会重置之前的 ext1 配置,并在 v6.0 中弃用(源码注释明确说明)。

上拉/下拉电阻的处理:由于唤醒期间 RTC 外设域可能掉电,ESP-IDF 会在进入睡眠前自动锁定唤醒引脚状态(HOLD),退出后解锁,因此内部上拉/下拉依然可用:

esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); rtc_gpio_pullup_dis(gpio_num); rtc_gpio_pulldown_en(gpio_num);

若关闭RTC_PERIPH域,则系统在进入睡眠前对引脚施加 HOLD 特性维持上下拉状态,可进一步降低功耗:

rtc_gpio_pullup_dis(gpio_num); rtc_gpio_pulldown_en(gpio_num);

对缺少RTC_PERIPH域的芯片,只能使用 HOLD 特性,改用数字 GPIO 接口:

gpio_pullup_dis(gpio_num); gpio_pulldown_en(gpio_num);

每引脚独立电平(Per-Pin Mode):支持SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN的芯片可让不同 IO 同时使用不同唤醒电平;不支持时,若为多个 IO 配置了不同电平,esp_sleep_enable_ext1_wakeup_io会返回ESP_ERR_NOT_ALLOWED(源码有对应的硬件限制检查机制)。

警告:ext1 唤醒 IO 同样会被配置为 RTC IO,使用前需rtc_gpio_deinit()。若 RTC 外设默认掉电,进入睡眠前唤醒 IO 会进入保持状态,Light-sleep 唤醒后需调用rtc_gpio_hold_dis()解除保持再做引脚重配置;Deep-sleep 唤醒的该操作已在应用启动阶段自动处理。

5. ULP 协处理器唤醒

ULP 协处理器可在睡眠期间持续运行,用于轮询传感器、监视 ADC/GPIO 状态,并在检测到特定事件时唤醒芯片。ULP 属于 RTC 外设电源域,运行的程序存放于 RTC SLOW memory——因此启用该唤醒源时 RTC SLOW memory 会保持上电;RTC 外设会在 ULP 程序启动前自动上电、程序停止后自动掉电。

esp_err_t esp_sleep_enable_ulp_wakeup(void);

注意(ESP32):revision 0/1 的 ESP32 仅在 RTC 外设未强制上电(ESP_PD_OPTION_AUTO)时支持 ULP 唤醒,且不可与 ext0 同时使用。

6. USB 唤醒(仅 Light-sleep)

支持 USB 2.0 High-Speed OTG 的芯片可在 Light-sleep 期间检测到 USB 总线活动而唤醒——典型场景是 USB 设备应用在主机挂起总线后进入 Light-sleep,主机恢复总线时被唤醒。注意USB Serial/JTAG 外设不支持此唤醒源。

使用前必须保证高速连接外设电源域在睡眠期间保持上电:

esp_sleep_pd_config(ESP_PD_DOMAIN_CNNT, ESP_PD_OPTION_ON); esp_sleep_enable_usb_wakeup();

7. GPIO 唤醒(Light-sleep,任意 IO)

除 ext0/ext1 外,Light-sleep 还支持逐引脚独立配置电平触发的 GPIO 唤醒,且不受限于 RTC IO(任意 RTC 或数字 IO 均可)。流程为:先对每个引脚调用gpio_wakeup_enable()配置唤醒电平,再调用:

esp_err_t esp_sleep_enable_gpio_wakeup(void);

警告:进入 Light-sleep 前,检查被驱动的 GPIO 是否属于VDD_SPI(ESP32 为VDD_SDIO)电源域。若这些引脚需要在 Light-sleep 期间保持高电平,则该电源域必须保持上电,例如 ESP32-WROOM-32 的 GPIO16/17:

esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON);

CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP的交互:若在 Light-sleep 中启用了外设掉电(CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP),要继续使用gpio_wakeup_enable做 GPIO 唤醒,需先调用rtc_gpio_init()rtc_gpio_set_direction()将引脚设为 RTCIO 输入模式;或者改用esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown()

8. GPIO 唤醒(Deep-sleep 及外设掉电场景)

支持SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP的芯片可用esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown()从 Deep-sleep 唤醒,或在外设域掉电的 Light-sleep 中替代esp_sleep_enable_gpio_wakeup

esp_err_t esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(uint64_t gpio_pin_mask, esp_sleep_gpio_wake_up_mode_t mode);
  • 只有由VDD3P3_RTC电源域供电的 GPIO(RTC IO)可用于 Deep-sleep GPIO 唤醒,具体引脚以芯片数据手册 "IO Pins" 一节为准;
  • 支持边沿触发模式的芯片(SOC_RTC_GPIO_EDGE_WAKEUP_SUPPORTED)额外提供ESP_GPIO_WAKEUP_GPIO_POSEDGE(上升沿)、ESP_GPIO_WAKEUP_GPIO_NEGEDGE(下降沿)、ESP_GPIO_WAKEUP_GPIO_ANYEDGE(双边沿)三种模式(见 esp_sleep.h)。对于ANYEDGE模式,由于空闲电平不确定,系统会禁用内部上拉/下拉(当CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS启用时),建议使用外部电阻或稳定电平线路;
  • 该 API 默认启用内部电阻自动配置(CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS);若使用外部电阻,务必关闭该选项以免内外电阻互相干扰,且用低电平唤醒时强烈建议外加(上拉)电阻。

唤醒信号时序要求:任何 GPIO/IO 唤醒信号——无论电平还是边沿——必须持续(或脉宽)至少 3 个 RTC 慢速时钟周期才能被唤醒逻辑可靠采样。慢速时钟周期时长取决于CONFIG_RTC_CLK_SRC,例如 RC_SLOW(约 136 kHz)约为 7.4 µs/周期,XTAL32K(32.768 kHz)约为 30.5 µs/周期。该要求同时适用于esp_sleep_enable_gpio_wakeupesp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown

9. UART 唤醒(仅 Light-sleep)

当芯片需要响应外部 UART 输入时,可使用 UART 外设的多模式唤醒。先通过uart_wakeup_setup()配置唤醒模式与参数(结构体为uart_wakeup_cfg_t),再调用:

esp_err_t esp_sleep_enable_uart_wakeup(int uart_num);

支持的四种唤醒模式(不同芯片支持的子集由 SOC 能力宏区分):

  • Mode 0UART_WK_MODE_ACTIVE_THRESH(有效沿阈值唤醒):所有时钟掉电后,RXD 引脚翻转一定次数即可唤醒,上升沿计数 ≥rx_edge_threshold阈值时触发(配置字段rx_edge_threshold)。注意:从 Mode 0 唤醒后,应通过 UART 发送额外数据或在 Active 模式下复位 UART 模块,否则下次唤醒会以比配置阈值少两个上升沿触发;
  • Mode 1UART_WK_MODE_FIFO_THRESH(RX FIFO 阈值唤醒):UART 核心时钟保持运行,RX 持续接收数据并存入 FIFO,字节数超过rx_fifo_threshold阈值时唤醒;
  • Mode 2UART_WK_MODE_START_BIT(起始位检测唤醒):UART RX 检测到起始位即唤醒;
  • Mode 3UART_WK_MODE_CHAR_SEQ(字符序列检测唤醒):RX 收到特定字符序列时唤醒,序列由wake_chars_seq字段配置,支持用*通配任意字符。

限制CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP会使 UART 唤醒失效;ESP32 不支持 UART2 唤醒;Mode 0 不需要时钟源,其余模式需要。

LP_UART 唤醒 ULP LP 核(支持SOC_ULP_LP_UART_SUPPORTED的芯片):LP_UART 支持与 HP UART 相同的四种唤醒模式,步骤如下:

  1. ulp_lp_core_cfg_t结构的wakeup_source字段中置位ULP_LP_CORE_WAKEUP_SOURCE_LP_UART
  2. 初始化 LP UART(调用lp_core_uart_init());
  3. 使用lp_core_uart_wakeup_setup()配置唤醒模式(与 HP UART 相同的uart_wakeup_cfg_t配置方法)。

注意:在具有SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED特性的芯片上,LP UART 唤醒信号在事件后保持触发状态。标准启动流程(ulp_lp_core_update_wakeup_cause)会自动调用ulp_lp_core_lp_uart_reset_wakeup_enlp_core_uart_clear_buf清除该状态;若未走标准启动流程,必须手动处理,否则会反复唤醒。完整示例见 lp_uart_char_seq_wakeup。

10. 其他唤醒源

源码 esp_sleep.h 中还列出了以下平台相关唤醒源,部分需对应 SOC 能力宏支持:Wi-Fi 唤醒(esp_sleep_enable_wifi_wakeup/ beacon 唤醒esp_sleep_enable_wifi_beacon_wakeup)、Bluetooth 唤醒(esp_sleep_enable_bt_wakeup)、VAD 唤醒(esp_sleep_enable_vad_wakeup)、VBAT 欠压唤醒(esp_sleep_enable_vbat_under_volt_wakeup)。

11. 禁用唤醒源

esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source);

该函数停用指定唤醒源的触发。传ESP_SLEEP_WAKEUP_ALL可禁用全部唤醒源。注意:此函数不会立即修改 RTC 中的唤醒配置,实际生效发生在esp_deep_sleep_start/esp_light_sleep_start执行时(源码注释明确说明)。


三、掉电选项(Power-down Options)

应用可以强制指定 RTC 外设与 RTC 内存的掉电模式;在 Deep-sleep 中还可以隔离部分 IO 进一步降低电流。

1. RTC 外设与内存掉电

默认情况下,esp_deep_sleep_start()esp_light_sleep_start()会关断所有未被已启用唤醒源需要的 RTC 电源域。可通过以下 API 覆盖默认行为:

esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, esp_sleep_pd_option_t option);

可配置的掉电域(esp_sleep_pd_domain_t,见 esp_sleep.h)包括:ESP_PD_DOMAIN_RTC_PERIPH(RTC IO、传感器、ULP 协处理器)、ESP_PD_DOMAIN_RTC_SLOW_MEMESP_PD_DOMAIN_RTC_FAST_MEMESP_PD_DOMAIN_XTALESP_PD_DOMAIN_XTAL32KESP_PD_DOMAIN_RC32KESP_PD_DOMAIN_RC_FASTESP_PD_DOMAIN_CPUESP_PD_DOMAIN_VDDSDIOESP_PD_DOMAIN_MODEM(含 Wi-Fi/BT/802.15.4)、ESP_PD_DOMAIN_TOPESP_PD_DOMAIN_CNNT(高速连接外设)等(具体可用项由各芯片 SOC 能力宏决定)。

掉电选项(esp_sleep_pd_option_t)三选一:

选项含义
ESP_PD_OPTION_OFF睡眠期间关断该电源域
ESP_PD_OPTION_ON睡眠期间保持该电源域上电
ESP_PD_OPTION_AUTO若某唤醒源需要则保持上电,否则关断(默认策略)

源码 esp_sleep.h 指出,手动模式采用引用计数策略管理:多个子系统可安全地请求/释放电源域资源,只有所有使用者都释放后电源域才会改变状态。

RTC 内存的默认行为

  • 若程序中将变量放入 RTC SLOW memory(如RTC_DATA_ATTR属性),默认 RTC SLOW memory 会保持上电,可通过esp_sleep_pd_config覆盖;
  • 对仅有 RTC FAST memory 的芯片(如 ESP32-C2),RTC_DATA_ATTRRTC_SLOW_ATTRRTC_FAST_ATTR的变量都会进入 RTC FAST memory,默认保持上电;
  • ESP32 revision 0:Deep-sleep 中 RTC FAST memory 始终开启,以便复位后运行 Deep-sleep stub(若应用不需要干净的复位行为可覆盖)。

2. Flash 掉电与省电策略(重点)

Light-sleep 期间 SPI Flash 的处理直接影响系统安全与功耗,是低功耗设计中最重要的决策点之一。

策略 A:保持 Flash 上电(默认、最安全)

esp_light_sleep_start()默认不会关断 SPI Flash,原因有二:一是 Flash 掉电需要时间,期间系统可能被唤醒,导致 Flash 在完全掉电前又被上电,存在工作异常风险;二是 Flash 掉电时长难以预测(例如电源电路加滤波电容后明显变长)且不可控(异步唤醒信号使实际睡眠时长不确定)。ESP 系列芯片 SPI Flash 的待机功耗通常低于 30 µA(典型约 10-30 µA)。若 Flash 电源电路加有滤波电容,应尽一切可能避免给 Flash 掉电。

适合保持上电的场景:

  1. 系统稳定性要求极高,无法接受 Flash 掉电的任何潜在风险;
  2. 睡眠时长短或不可预测(存在 GPIO、UART 等异步唤醒源);
  3. Flash 电源电路存在大滤波电容,难以估算实际掉电时间。
策略 B:Flash 进入深度掉电模式 DPD(推荐折中方案)

Light-sleep 下,ESP-IDF 推荐先用Deep Power-Down (DPD)降低 Flash 睡眠电流:启用CONFIG_ESP_SLEEP_SET_FLASH_DPD后,SPI Flash 进入深度掉电命令模式,同时供电轨保持开启。许多 SPI Flash 器件在 DPD 模式下电流可低至 1 µA 以下,且没有完全断电再上电的唤醒延迟。在绝大多数使用场景下,DPD 相比切断 Flash 供电在安全性与功耗之间取得了更好的平衡。

适合 DPD 的场景:

  1. 需要显著降低睡眠功耗,同时规避 Flash 重新上电的风险;
  2. 睡眠时长短或不可预测;
  3. 所用 SPI Flash 器件明确支持 Deep Power-Down 模式。

互斥策略警告:Light-sleep 中掉电 SPI Flash(CONFIG_ESP_SLEEP_POWER_DOWN_FLASHesp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_OFF)不能与 DPD 同时使用。Kconfig 仅在CONFIG_ESP_SLEEP_POWER_DOWN_FLASH被禁用时才暴露CONFIG_ESP_SLEEP_SET_FLASH_DPD(见 esp_hw_support/Kconfig)。

使用前必查:确认所用 SPI Flash 器件的 datasheet 支持 Deep Power-Down 模式。

策略 C:彻底关断 Flash 供电(高风险,仅限受控场景)

只有充分理解风险并愿意进一步降低功耗时才考虑:

  • Kconfig 选项CONFIG_ESP_SLEEP_POWER_DOWN_FLASH仅当 RTC 定时器是唯一唤醒源且睡眠时长大于 Flash 掉电时间时才关断 SPI Flash;
  • 调用esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_OFF):当 RTC 定时器未启用为唤醒源睡眠时长大于 Flash 掉电时间时关断 SPI Flash。

注意

  • ESP-IDF不提供任何在 Light-sleep 所有条件下都能关断 SPI Flash 的机制;
  • esp_deep_sleep_start()无论用户如何配置都会强制关断 SPI Flash;
  • 建议功耗敏感应用优先使用CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND(PSRAM 对应CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND)降低 Light-sleep 期间 Flash 功耗,而不是直接掉电。

适合彻底掉电的前提(全部满足并经充分评估):

  1. 对极低功耗有严格要求;
  2. 唤醒源可控,通常只启用 RTC 定时器唤醒;
  3. 能保证实际睡眠时长大于 Flash 完全掉电所需时间(ESP 系列芯片该时间可能大于 300 ms,若电源电路存在并联电容则需更长);
  4. 睡眠过短时,Flash 上下电过程的功耗可能反而超过保持上电;
  5. 对 Flash 供电与 IO 状态有充分控制,避免睡眠期间引脚上拉导致 Flash 漏电。

由于 Flash 掉电过程受硬件设计、IO 阻抗、供电与环境因素影响很大,ESP-IDF无法保证Light-sleep 中 Flash 能被安全掉电,此方法仅适用于风险可控且经过充分验证的场景。

3. IO 隔离(仅 Deep-sleep)

部分 IO 具有默认使能的内部上拉/下拉电阻。若外部电路在 Deep-sleep 中驱动这些引脚,电流会流过这些电阻导致功耗上升。可通过rtc_gpio_isolate()隔离引脚:

rtc_gpio_isolate(GPIO_NUM_12);

典型案例:ESP32-WROVER 模块上 GPIO12 被外部上拉,且芯片内部有下拉——Deep-sleep 时电流会流过内外两组电阻。在esp_deep_sleep_start()前调用rtc_gpio_isolate(GPIO_NUM_12)即可消除额外电流(该写法正是 deep_sleep_example_main.c 中针对 ESP32 的处理)。

ESP32-C2/C3 的 Deep-sleep 引脚行为

  • 数字 GPIO(GPIO6~21)处于高阻态;
  • RTC GPIO(GPIO0~5)取决于 hold 功能:未启用时高阻态;启用时保持被锁存时刻的引脚状态。

四、进入睡眠与唤醒后的处理

1. 进入睡眠

调用以下函数进入对应睡眠模式(系统随后按已配置的唤醒源与掉电选项配置 RTC 控制器参数):

esp_err_t esp_light_sleep_start(void); // Light-sleep,唤醒后返回 void esp_deep_sleep_start(void); // Deep-sleep,noreturn,通常不返回

也可以不配置任何唤醒源进入睡眠,此时芯片将无限期睡眠,直到外部复位。

快捷 API:esp_deep_sleep(time_in_us)等价于esp_sleep_enable_timer_wakeup(time_in_us)+esp_deep_sleep_start()esp_deep_sleep_try_to_start()/esp_light_sleep_start()在睡眠被拒绝时会返回错误码(如ESP_ERR_NOT_ALLOWEDESP_ERR_SLEEP_REJECTESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION)。

关键限制:睡眠流程会禁用 cache,因此请求睡眠的任务其任务栈必须位于内部内存(DRAM 或 RTC fast memory)。若任务栈位于 PSRAM,睡眠请求会被拒绝并返回错误(对应源码中ESP_ERR_NOT_ALLOWED,见 esp_sleep.h)。

2. 控制台 UART 处理(UART Output Handling)

进入睡眠前,睡眠流程会预先处理控制台 UART(调试输出所用 UART,由CONFIG_ESP_CONSOLE_UART_NUM选择),避免 APB 时钟变化或掉电导致乱码与未定义行为。默认策略(自动模式):

  • Deep-sleep:总是等待控制台 UART FIFO 中的数据全部发送完毕再进入睡眠,保证调试输出不丢失;
  • Light-sleep:取决于 UART 电源域是否掉电——UART 保持供电时,完成当前帧后挂起UART,唤醒后恢复并继续发送剩余数据;UART 电源域掉电时,等待控制台 UART TX FIFO 数据全部发完,其他 UART 的数据被丢弃以更快进入睡眠。

可通过esp_sleep_set_console_uart_handling_mode()覆盖默认策略(枚举esp_sleep_uart_handling_mode_t,见 esp_sleep.h):

模式行为
ESP_SLEEP_AUTO_FLUSH_SUSPEND_UART(默认)根据睡眠类型与电源域自动选择 flush 或 suspend
ESP_SLEEP_ALWAYS_FLUSH_UART总是等 TX FIFO 全部发完再睡眠,保证调试输出可见,但入睡更慢、功耗更高
ESP_SLEEP_ALWAYS_SUSPEND_UART完成当前帧后挂起;Light-sleep 保持供电则唤醒后继续,掉电则未发数据丢失
ESP_SLEEP_ALWAYS_DISCARD_UART丢弃全部未发数据立即入睡,入睡最快、功耗最低
ESP_SLEEP_NO_HANDLING不做任何处理,仅当 UART 状态已知安全时使用

示例:确保每次睡眠前所有调试输出都被发送:

fflush(stdout); esp_sleep_set_console_uart_handling_mode(ESP_SLEEP_ALWAYS_FLUSH_UART); esp_light_sleep_start();

示例:最小化入睡时间并允许丢弃控制台输出:

esp_sleep_set_console_uart_handling_mode(ESP_SLEEP_ALWAYS_DISCARD_UART); esp_deep_sleep_start();

中断看门狗提示:睡眠流程运行在临界区内。使用 flush 类模式时,应将CONFIG_ESP_INT_WDT_TIMEOUT_MS设为大于SOC_UART_FIFO_LEN ×(当前波特率下发送一个字符的时间),否则 TX FIFO 积压数据过多时,flush 耗时可能超过中断看门狗超时,导致睡眠入口触发看门狗复位。

3. 检查唤醒原因

esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void);

该函数返回上次唤醒的来源(注意:多个唤醒源同时触发时,旧 API 可能丢失部分信息,新 APIesp_sleep_get_wakeup_causes()以位图形式返回全部唤醒源,旧 API 已标记 deprecated)。进一步定位:

  • 触摸唤醒:esp_sleep_get_touchpad_wakeup_status()返回触发唤醒的触摸引脚;
  • ext1 唤醒:esp_sleep_get_ext1_wakeup_status()返回位掩码,BIT(n)置位表示 GPIO n 触发唤醒;
  • GPIO(外设掉电)唤醒:esp_sleep_get_gpio_wakeup_status()返回 RTC IO 位掩码,配合esp_sleep_wakeup_io_bit2num()转换为 GPIO 编号。

在 deep_sleep_example_main.c 中可以看到完整的位图判断范例:先检查ESP_SLEEP_WAKEUP_UNDEFINED判断是否为 Deep-sleep 复位,再依次检查 TIMER、GPIO、EXT0、EXT1,并通过esp_sleep_get_ext1_wakeup_status()结合__builtin_ctzll()定位具体引脚。


五、应用示例与 API 参考

官方示例导航

示例演示内容
protocols/sntpDeep-sleep 基础用法:模块周期性唤醒从 NTP 服务器获取时间
wifi/power_saveWi-Fi Modem-sleep 模式与自动 Light-sleep 维持 Wi-Fi 连接
bluetooth/nimble/power_saveBluetooth Modem-sleep 模式与自动 Light-sleep 维持蓝牙连接
system/deep_sleep各种 Deep-sleep 唤醒触发源(RTC 定时器、GPIO、EXT0/EXT1 等)与 ULP 协处理器编程
system/light_sleepLight-sleep 定时器、GPIO 等唤醒触发源
peripherals/usb/device/tusb_cdc_acm_wakeupUSB 2.0 从 Light-sleep 唤醒
peripherals/touch_sensor/touch_sens_sleep触摸传感器触发 Light-sleep / Deep-sleep 唤醒
lowpower/vbatDeep-sleep 期间使用备用电池供电(VBAT),主电源移除后 RTC 定时器继续运行

示例工程结构参考:examples/system/deep_sleep 下包含main/deep_sleep_example_main.c(主流程与唤醒原因打印)、main/ext_wakeup.c(ext0/ext1 配置)、main/gpio_wakeup.c(GPIO 唤醒配置)、partitions.csv(分区表)、pytest_deep_sleep.py(自动化测试)与sdkconfig.defaults(默认配置);examples/system/light_sleep 则提供了 Light-sleep 的完整可运行工程。

完整 API 清单

所有睡眠相关 API 集中在 esp_sleep.h(对应文档中的 API Reference 一节),核心接口汇总:

  • 进入睡眠esp_light_sleep_startesp_deep_sleep_startesp_deep_sleepesp_deep_sleep_tryesp_deep_sleep_try_to_start
  • 唤醒源启用/禁用esp_sleep_enable_timer_wakeupesp_sleep_enable_touchpad_wakeupesp_sleep_enable_ext0_wakeupesp_sleep_enable_ext1_wakeup/esp_sleep_enable_ext1_wakeup_io/esp_sleep_disable_ext1_wakeup_ioesp_sleep_enable_ulp_wakeupesp_sleep_enable_usb_wakeupesp_sleep_enable_gpio_wakeupesp_sleep_enable_gpio_wakeup_on_hp_periph_powerdownesp_sleep_enable_uart_wakeupesp_sleep_enable_wifi_wakeupesp_sleep_enable_bt_wakeupesp_sleep_disable_wakeup_source
  • 掉电域配置esp_sleep_pd_configesp_sleep_config_gpio_isolateesp_sleep_enable_gpio_switch
  • 唤醒原因查询esp_sleep_get_wakeup_causeesp_sleep_get_wakeup_causesesp_sleep_get_touchpad_wakeup_statusesp_sleep_get_ext1_wakeup_statusesp_sleep_get_gpio_wakeup_statusesp_sleep_wakeup_io_bit2num
  • 控制台 UART 处理esp_sleep_set_console_uart_handling_mode
  • 高级/扩展esp_deep_sleep_register_hook/esp_deep_sleep_deregister_hook(Deep-sleep 准备回调)、esp_wake_deep_sleep/esp_set_deep_sleep_wake_stub(Deep-sleep 唤醒 stub)、esp_deep_sleep_disable_rom_loggingesp_sleep_cpu_retention_init/esp_sleep_cpu_pd_low_init(Light-sleep CPU 掉电)

六、关键 Kconfig 选项速查

以下选项贯穿全文提到的睡眠策略,均可在menuconfig中配置(位于Component config → ESP System Settings等路径):

Kconfig 选项作用
CONFIG_RTC_CLK_SRCRTC 慢速时钟源选择,决定定时器唤醒分辨率与 GPIO 唤醒信号采样周期
CONFIG_RTC_CLK_SRC_INT_8MD256用 8MD256 作为 RTC_SLOW_CLK 时钟源,Deep-sleep 自动进入 8MD256 子模式
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEPLight-sleep 中外设掉电(影响 GPIO/UART 唤醒可用性)
CONFIG_ESP_SLEEP_SET_FLASH_DPDLight-sleep 中让 SPI Flash 进入 Deep Power-Down 模式(与断电互斥)
CONFIG_ESP_SLEEP_POWER_DOWN_FLASHLight-sleep 中掉电 SPI Flash(仅定时器唤醒且睡眠足够长时生效)
CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND不掉电前提下降低 Light-sleep 期间 Flash 漏电功耗
CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND同上,针对 PSRAM
CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORSGPIO 唤醒时自动配置内部上拉/下拉
CONFIG_ESP_CONSOLE_UART_NUM控制台 UART 编号(决定睡眠前 UART 处理的对象)
CONFIG_ESP_INT_WDT_TIMEOUT_MS中断看门狗超时,需大于 flush 控制台 UART 所需时间

选择建议:默认状态下,ESP-IDF 对 Flash 采用"保持上电"的安全策略;若需进一步降耗,优先启用CONFIG_ESP_SLEEP_SET_FLASH_DPD;仅在场景完全受控(单一 RTC 定时器唤醒、睡眠时长充足、硬件设计可靠)时才考虑彻底掉电 Flash。

【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 4:02:25

大模型私有化部署实战:从选型到落地,LLM如何重构企业研发流程

把大模型“搬进”公司&#xff1a;我们的研发部&#xff0c;正在被 LLM 重新定义去年年底&#xff0c;我们研发部做了一次“豪赌”——把大模型&#xff08;LLM&#xff09;真正接到自己的业务线里来&#xff0c;而不是继续当一个只会聊天的玩具。从前端的代码补全&#xff0c;…

作者头像 李华
网站建设 2026/9/17 4:02:10

API连通性测试实践:从curl到自动化巡检的完整指南

1. 项目动机&#xff1a;为什么我会专门做一次API连通性测试先说个有意思的背景&#xff1a;这个项目的原始标题其实是从一个内部交接文档里抄出来的&#xff0c;当时同事在群里发了一个“API连通性测试-请忽略本文”的标题&#xff0c;本意是占个位、提醒自己后面补充内容。结…

作者头像 李华
网站建设 2026/9/17 4:00:11

requestAnimationFrame:前端动画与JS性能优化实战

做前端动画这些年&#xff0c;requestAnimationFrame&#xff08;下面我简称 rAF&#xff09;大概是那种“人人都听过、但真正吃透的人不多”的 API。它看着简单&#xff0c;一行requestAnimationFrame(fn)就能跑&#xff0c;可真要拿它来做 js 性能优化&#xff0c;里面的门道…

作者头像 李华
网站建设 2026/9/17 4:00:07

OFDM系统MATLAB仿真全解析:从IFFT到BER曲线验证

简介&#xff1a;面向通信工程学习者与MATLAB初学者的OFDM&#xff08;正交频分复用&#xff09;算法实现包&#xff0c;聚焦多载波调制核心原理&#xff0c;覆盖从信道分割、子载波正交化到收发链路的完整仿真流程。OFDM是4G/5G、Wi-Fi等现代系统的核心技术&#xff0c;理解其…

作者头像 李华
网站建设 2026/9/17 3:59:53

Spring Boot校园服务平台源码解析与二次开发实战指南

Spring Boot学生校园服务生活集合平台这类项目&#xff0c;每年毕业季都能在源码站刷到好几页同款。标题里挂着的“附源码67568”说明这套东西已经流传得很广了&#xff0c;也侧面印证了校园服务平台在选题界的常青树地位——它业务场景真实、功能边界清晰、技术栈又刚好卡在Ja…

作者头像 李华
网站建设 2026/9/17 3:57:38

计算机网络第一章复习指南:时延计算与分层模型高频考点解析

说起计算机网络复习&#xff0c;谢希仁老师这本第八版教材几乎是无数人的入门标配。很多人把第一章“概述”当成纯记忆章&#xff0c;觉得背背概念就过去了&#xff0c;但真正考试和考研408里&#xff0c;第一章的失分点恰恰最多。第一章看起来是“常识”&#xff0c;实际上埋了…

作者头像 李华