引言

ESP32-C3 作为一款高性价比的 RISC-V 芯片,在低功耗场景中表现出色。其深睡模式(Deep Sleep)下,主 CPU 停止运行,但 RTC 内存和 ULP 协处理器仍可工作,从而实现“定时唤醒”或“事件唤醒”。理解 RTC 内存的保持机制和 ULP 的唤醒时序,是设计低功耗系统的关键。

RTC 内存保持原理

RTC 内存(RTC Fast Memory)是芯片内部的一块静态 RAM,在深睡模式下由 RTC 电源域供电,数据不会丢失。它分为两个区域:

  • RTC_DATA_ATTR:用于存放需要在深睡后保留的变量。
  • RTC_NOINIT_ATTR:用于存放不经过初始化、直接保留的变量(如启动标志)。

这些变量在编译时被链接到 RTC 内存地址,深睡时主电源关闭,但 RTC 电源域持续供电,因此数据得以保留。

ULP 协处理器唤醒时序

ULP(Ultra Low Power)协处理器是一个独立的 RISC-V 核心,可在深睡模式下运行,执行传感器读取、GPIO 检测等任务。其唤醒时序如下:

  1. 配置阶段:主 CPU 将 ULP 程序加载到 RTC 内存,并设置唤醒源(如定时器或 GPIO)。
  2. 进入深睡:主 CPU 执行 esp_deep_sleep_start(),系统进入深睡,ULP 开始运行。
  3. ULP 执行:ULP 按程序轮询或等待事件,期间主 CPU 完全断电。
  4. 唤醒触发:当 ULP 检测到条件满足(如 GPIO 电平变化),或定时器溢出,ULP 会拉高唤醒信号。
  5. 系统恢复:主 CPU 从深睡中唤醒,复位并执行启动代码,可通过 esp_sleep_get_wakeup_cause() 判断唤醒源。

时序关键点:ULP 唤醒延迟通常在几十微秒级别,远快于外部 RTC 中断唤醒(毫秒级),适合对响应速度要求高的场景。

配置步骤与代码示例

以下示例演示如何利用 RTC 内存保存计数,并使用 ULP 定时唤醒(每 10 秒)来递增计数。

1. 定义 RTC 变量

RTC_DATA_ATTR int boot_count = 0;  // 深睡后保留
RTC_NOINIT_ATTR int flag;          // 不初始化,保留上次值

2. 配置 ULP 程序

ULP 程序需用汇编或 C 编写,并编译为二进制。此处使用 ESP-IDF 的 ulp 组件,简单示例:

// ulp_program.c
#include "ulp_riscv.h"

int main() {
    // 设置定时器唤醒,每 10 秒
    ulp_riscv_timer_start(10 * 1000000);
    // 等待唤醒事件(此处可添加 GPIO 检测逻辑)
    while (1) {
        // 空循环,由定时器触发唤醒
    }
    return 0;
}

编译后,在主程序中加载:

#include "ulp_riscv.h"
extern const uint8_t ulp_program_start[];

void app_main() {
    // 加载 ULP 程序到 RTC 内存
    ulp_riscv_load_binary(ulp_program_start);
    // 启动 ULP
    ulp_riscv_run();

    // 进入深睡
    esp_deep_sleep_start();
}

3. 唤醒后处理

void app_main() {
    // 检查唤醒原因
    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
    if (cause == ESP_SLEEP_WAKEUP_ULP) {
        boot_count++;  // 递增计数
        ESP_LOGI("MAIN", "ULP woke up, count=%d", boot_count);
    }

    // 重新加载 ULP 并深睡
    ulp_riscv_load_binary(ulp_program_start);
    ulp_riscv_run();
    esp_deep_sleep_start();
}

注意事项

  • RTC 内存大小:ESP32-C3 的 RTC 内存仅 8KB,需合理规划变量,避免溢出。
  • ULP 程序限制:ULP 不能访问所有外设,仅支持 GPIO、I2C 等有限功能,且代码需精简。
  • 唤醒源冲突:若同时配置多个唤醒源,需在唤醒后逐一检查,避免误判。
  • 电源稳定性:深睡时电压波动可能影响 RTC 内存,建议使用稳压器。
  • 调试技巧:使用 esp_sleep_get_wakeup_cause() 打印唤醒原因,便于定位问题。

总结

ESP32-C3 的 RTC 内存和 ULP 协处理器为低功耗设计提供了强大支持。通过合理利用 RTC 变量保持状态,并配置 ULP 定时或事件唤醒,开发者可以构建功耗极低且响应迅速的嵌入式系统。掌握其唤醒时序,是优化系统性能的关键。