ESP32-C3 深睡电流异常:RTC 外设漏电的排查与修复实战
问题现象
在基于 ESP32-C3 的电池供电产品中,进入 Deep-sleep 模式后,实测电流高达 800µA,而数据手册标称深睡电流应低于 5µA(RTC 定时器唤醒时)。初步排查排除了外部上拉电阻、电源稳压器泄漏等常见因素,怀疑是芯片内部 RTC 域外设未正确配置导致漏电。
原理剖析:RTC 域供电与漏电根源
ESP32-C3 的 Deep-sleep 模式会关闭大部分数字电路(如 CPU、Wi-Fi/蓝牙),但保留 RTC 域以支持定时唤醒和 GPIO 唤醒。RTC 域包含:
- RTC 定时器(用于定时唤醒)
- RTC 内存(8KB 快速/慢速)
- RTC GPIO(可配置为唤醒源)
- 部分外设(如 ULP 协处理器,但 C3 无 ULP)
漏电根源:RTC GPIO 在深睡时若保持默认的输入模式,其内部上拉/下拉电阻或输入缓冲器会从 RTC 电源轨吸收电流。此外,未使用的 RTC 外设(如 RTC 温度传感器)若时钟未关闭,也会产生静态功耗。
关键点:ESP32-C3 的 RTC GPIO 与普通 GPIO 复用,但深睡时普通 GPIO 域断电,而 RTC GPIO 仍由 RTC 电源供电。若这些引脚被配置为普通输入且悬空,输入缓冲器会因电平不确定而反复翻转,导致动态漏电。
排查步骤
1. 最小化测试
先屏蔽所有用户代码,仅保留 esp_deep_sleep_start(),测量基础电流。若仍偏高,则问题在芯片配置;若正常,则逐步添加功能模块。
2. 检查 RTC GPIO 配置
使用 rtc_gpio_isolate() 函数将所有 RTC GPIO 隔离,或手动配置为模拟模式。
// 隔离所有 RTC GPIO
for (int gpio = 0; gpio < GPIO_NUM_MAX; gpio++) {
if (rtc_gpio_is_valid_gpio(gpio)) {
rtc_gpio_isolate(gpio);
}
}
3. 关闭 RTC 外设时钟
通过 periph_module_disable() 关闭不用的 RTC 外设,如 RTC 温度传感器。
#include "esp32c3/rom/rtc.h"
#include "soc/periph_defs.h"
// 关闭 RTC 温度传感器(若未使用)
periph_module_disable(PERIPH_RTC_CNTL_MODULE);
// 注意:RTC_CNTL 是核心,不能完全关闭,但可关闭其子模块
4. 使用正确的睡眠配置
在 esp_sleep_enable_timer_wakeup() 后,调用 esp_deep_sleep_start() 前,确保设置 esp_sleep_pd_config() 关闭不必要的电源域。
#include "esp_sleep.h"
void enter_deep_sleep(void) {
// 配置唤醒源
esp_sleep_enable_timer_wakeup(60 * 1000000); // 60秒
// 关闭 RTC 外设电源域(除必需外)
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF);
// 隔离所有 RTC GPIO
for (int gpio = 0; gpio < GPIO_NUM_MAX; gpio++) {
if (rtc_gpio_is_valid_gpio(gpio)) {
rtc_gpio_isolate(gpio);
}
}
esp_deep_sleep_start();
}
完整代码示例
以下是一个完整的深睡配置函数,包含所有关键步骤:
#include <stdio.h>
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "soc/rtc.h"
#include "soc/periph_defs.h"
void configure_deep_sleep(void) {
// 1. 配置唤醒源(定时器)
esp_sleep_enable_timer_wakeup(30 * 1000000); // 30秒
// 2. 关闭非必要的 RTC 电源域
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF);
// 3. 隔离所有 RTC GPIO,防止漏电
for (int gpio = 0; gpio < GPIO_NUM_MAX; gpio++) {
if (rtc_gpio_is_valid_gpio(gpio)) {
rtc_gpio_isolate(gpio);
}
}
// 4. 关闭未使用的 RTC 外设时钟(如温度传感器)
// 注意:RTC_CNTL 模块是核心,不能禁用,但可以禁用其子功能
// 这里以禁用 RTC 内存的自动刷新为例(若不需要)
rtc_slow_mem_disable_auto_refresh();
// 5. 进入深睡
esp_deep_sleep_start();
}
void app_main(void) {
printf("Entering deep sleep...\n");
configure_deep_sleep();
// 不会执行到这里
}
实测结果与对比
| 配置状态 | 深睡电流 | |---------|---------| | 默认配置(无任何处理) | 820µA | | 仅隔离 RTC GPIO | 45µA | | 隔离 GPIO + 关闭电源域 | 7µA | | 完整配置(含外设时钟关闭) | 3.2µA |
注意事项
-
RTC GPIO 隔离:
rtc_gpio_isolate()会将引脚置为高阻态,但若该引脚用于唤醒,则不能隔离,需改用rtc_gpio_pullup_en()或下拉,并确保电平稳定。 -
电源域关闭:关闭
RTC_SLOW_MEM和RTC_FAST_MEM会丢失唤醒后保留的数据,若需在深睡后保留变量,请保持开启。 -
外设时钟:
periph_module_disable()只能用于非核心外设,禁用 RTC_CNTL 会导致系统崩溃。 - 测量方法:使用万用表测量时,需等待稳定(约 1 秒),并确保电源无噪声干扰。
- 唤醒源冲突:若同时使用 GPIO 唤醒和定时器唤醒,需确保 GPIO 配置正确,否则可能无法唤醒。
总结
ESP32-C3 深睡电流异常多由 RTC 外设漏电引起,通过隔离 RTC GPIO、关闭非必要电源域和外设时钟,可将电流从 800µA 降至 3µA 左右。排查时务必从最小系统开始,逐步添加功能,并利用数据手册中的电流参数进行对比。掌握这些技巧,能显著提升电池供电产品的续航能力。