当前位置: 首页 > article >正文

ESP32S3基于espidf 深度睡眠模式和唤醒使用

ESP32S3基于espidf 深度睡眠模式和唤醒使用


  • 📍睡眠模式官方在线文档介绍:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/system/sleep_modes.html?highlight=ulp
  • 有关RTC GPIO官方在线文档介绍:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/peripherals/gpio.html
📝超低功耗协处理器 (ULP-FSM, ULP-RISC-V)(ESP32S3参考手册)

超低功耗协处理器 (ULP, Ultra-Low-Power coprocessor) 是一种功耗极低的处理器设备,可在芯片进入Deep-sleep 时保持上电,允许开发者通过存储在 RTC 存储器中的专用程序,访问 RTC 外设、内部传感器及 RTC 寄存器。在对功耗敏感的场景下,主 CPU 处于睡眠状态以降低功耗,协处理器可以由协处理器定时器唤醒,通过控制 RTC GPIO、RTC I2C、SAR ADC、温度传感器 (TSENS) 等外设监测外部环境或与外部电路进行交互,并在达到唤醒条件时主动唤醒主 CPU。

esp32s3在 Deep-sleep 模式下,CPU、大部分 RAM、以及所有由时钟 APB_CLK 驱动的数字外设都会被断电。芯片上继续处于供电状态的部分仅包括:

  • RTC 控制器
    ULP 协处理器
    RTC 高速内存
    RTC 低速内存

在这里插入图片描述
ESP32-S3 搭载了基于有限状态机 (FSM) 实现的 ULP 协处理器(以下简称 ULP-FSM)和基于 RISC-V 指令集的ULP 协处理器(以下简称 ULP-RISC-V)

  • 特性
  • • 可访问最多 8 KB SRAM RTC 慢速内存,用于储存指令和数据
    • 时钟采用 17.5 MHz RTC_FAST_CLK
    • 支持正常模式和 Monitor 模式
    • 可唤醒 CPU 或向 CPU 发送中断
    • 可访问外设、内部传感器及 RTC 寄存器
    ULP-FSM 和 ULP-RISC-V 不能同时工作,用户只能选择其中一个作为 ESP32-S3 的超低功耗协处理器。
    ULP-FSM 与 ULP-RISC-V 特性比较如下:
    在这里插入图片描述

📘唤醒源

  • 📍相关参考文档:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/system/sleep_modes.html?highlight=ulp
1. 定时器唤醒(Timer Wakeup)

描述: 通过 RTC 定时器设置一个时间间隔,设备在深度睡眠后经过指定时间自动唤醒。

相关函数:

esp_sleep_enable_timer_wakeup(uint64_t time_in_us);
2. 外部唤醒(External Wakeup)

描述: 通过外部引脚的电平变化唤醒设备。ESP32-S3 支持两种外部唤醒方式:

    • EXT0: 单个 GPIO 引脚的电平触发。
    • EXT1: 多个 GPIO 引脚的组合触发。

相关函数:

  • EXT0:
esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);

gpio_num: 触发唤醒的 GPIO 引脚。
level: 触发电平(0 或 1)。

  • EXT1:
esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);

mask: GPIO 引脚的位掩码(例如 GPIO_SEL_12 表示 GPIO12)。
mode: 触发模式:
ESP_EXT1_WAKEUP_ALL_LOW: 所有引脚为低电平时触发。
ESP_EXT1_WAKEUP_ANY_HIGH: 任意引脚为高电平时触发。

特点: 适用于按键、传感器信号等外部事件触发唤醒。

  • 外部唤醒(EXT0/EXT1)可配置gpio引脚:(ESP32S3)
const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = {
    RTCIO_GPIO0_CHANNEL,    //GPIO0
    -1,//GPIO1
    RTCIO_GPIO2_CHANNEL,    //GPIO2
    -1,//GPIO3
    RTCIO_GPIO4_CHANNEL,    //GPIO4
    -1,//GPIO5
    -1,//GPIO6
    -1,//GPIO7
    -1,//GPIO8
    -1,//GPIO9
    -1,//GPIO10
    -1,//GPIO11
    RTCIO_GPIO12_CHANNEL,   //GPIO12
    RTCIO_GPIO13_CHANNEL,   //GPIO13
    RTCIO_GPIO14_CHANNEL,   //GPIO14
    RTCIO_GPIO15_CHANNEL,   //GPIO15
    -1,//GPIO16
    -1,//GPIO17
    -1,//GPIO18
    -1,//GPIO19
    -1,//GPIO20
    -1,//GPIO21
    -1,//GPIO22
    -1,//GPIO23
    -1,//GPIO24
    RTCIO_GPIO25_CHANNEL,   //GPIO25
    RTCIO_GPIO26_CHANNEL,   //GPIO26
    RTCIO_GPIO27_CHANNEL,   //GPIO27
    -1,//GPIO28
    -1,//GPIO29
    -1,//GPIO30
    -1,//GPIO31
    RTCIO_GPIO32_CHANNEL,   //GPIO32
    RTCIO_GPIO33_CHANNEL,   //GPIO33
    RTCIO_GPIO34_CHANNEL,   //GPIO34
    RTCIO_GPIO35_CHANNEL,   //GPIO35
    RTCIO_GPIO36_CHANNEL,   //GPIO36
    RTCIO_GPIO37_CHANNEL,   //GPIO37
    RTCIO_GPIO38_CHANNEL,   //GPIO38
    RTCIO_GPIO39_CHANNEL,   //GPIO39
};
  • gpio初始化配置:
#include "driver/gpio.h"

// 配置 GPIO 为输入模式
gpio_config_t io_conf = {
    .pin_bit_mask = (1ULL << GPIO_NUM_12), // 选择 GPIO12
    .mode = GPIO_MODE_INPUT,               // 输入模式
    .pull_up_en = GPIO_PULLUP_ENABLE,      // 使能上拉电阻
    .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用下拉电阻
    .intr_type = GPIO_INTR_DISABLE,        // 禁用中断(唤醒功能不需要中断)
};
gpio_config(&io_conf);


// 配置 EXT0 唤醒
esp_sleep_enable_ext0_wakeup(GPIO_NUM_12, 1); // GPIO12 高电平触发唤醒
// 配置 EXT1 唤醒
uint64_t mask = (1ULL << GPIO_NUM_12) | (1ULL << GPIO_NUM_13); // GPIO12 和 GPIO13
esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ANY_HIGH);  // 任意引脚高电平触发唤醒
  • 配置 GPIO 引脚并使用 EXT0 和 EXT1 唤醒模式:
#include "driver/gpio.h"
#include "esp_sleep.h"

void app_main() {
    // 配置 GPIO12 为输入模式,启用上拉电阻
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << GPIO_NUM_12), // GPIO12
        .mode = GPIO_MODE_INPUT,               // 输入模式
        .pull_up_en = GPIO_PULLUP_ENABLE,      // 使能上拉电阻
        .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用下拉电阻
        .intr_type = GPIO_INTR_DISABLE,        // 禁用中断
    };
    gpio_config(&io_conf);

    // 配置 EXT0 唤醒(GPIO12 高电平触发)
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_12, 1);

    // 或者配置 EXT1 唤醒(GPIO12 或 GPIO13 高电平触发)
    // uint64_t mask = (1ULL << GPIO_NUM_12) | (1ULL << GPIO_NUM_13);
    // esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ANY_HIGH);

    // 进入深度睡眠
    printf("Entering deep sleep\n");
    esp_deep_sleep_start();
}
3. 触摸传感器唤醒(Touchpad Wakeup)

描述: 通过触摸传感器的信号变化唤醒设备。

相关函数:

esp_sleep_enable_touchpad_wakeup();

特点: 适用于需要触摸交互的场景。

  • 可配置通道和对应引脚关系:

在这里插入图片描述

  • 相关参考例程:v5.4\esp-idf\examples\system\deep_sleep

  • 📝 代码配置:

#include "driver/touch_pad.h"
#include "esp_sleep.h"
#include "esp_log.h"

void app_main() {
    // 初始化触摸传感器
    touch_pad_init();

    // 配置触摸传感器引脚(例如 TOUCH_PAD_NUM8)
    touch_pad_config(TOUCH_PAD_NUM8, 0); // 0 表示默认阈值

    // 设置触摸传感器阈值
    touch_pad_set_thresh(TOUCH_PAD_NUM8, 1000); // 设置阈值为 1000

    // 启用触摸传感器滤波(可选)
    touch_pad_filter_start(10); // 滤波周期为 10ms

    // 启用触摸传感器唤醒
    esp_sleep_enable_touchpad_wakeup();

    // 进入深度睡眠
    ESP_LOGI("TOUCH", "Entering deep sleep");
    esp_deep_sleep_start();
}
4. ULP 协处理器唤醒(ULP Coprocessor Wakeup)

描述: ULP(Ultra Low Power)协处理器可以在深度睡眠模式下运行,并在满足条件时唤醒主处理器。

相关函数:

esp_sleep_enable_ulp_wakeup();

特点: 适用于需要低功耗运行并周期性检查某些条件的场景。

  • 需要使用到超低功耗协处理器 (ULP-FSM, ULP-RISC-V),配置比较麻烦,可以参见:v5.4\esp-idf\examples\system\ulp\lp_core\gpio_wakeup
  • ESP32S3使用ULP-RISC-V,adc唤醒测试失败,输入模拟电压达到设定的阈值,无法唤醒。使用ULP-FSM,adc唤醒测试没有问题,输入的模拟电压信号达到设定范围,即可唤醒,在ULP-FSM低功耗模式下,可以正常运行ADC功能,也可以正常响应唤醒。
    在这里插入图片描述
5. GPIO 唤醒(GPIO Wakeup)

描述: 通过 GPIO 引脚的电平变化唤醒设备。与外部唤醒类似,但 GPIO 唤醒支持更多的引脚和灵活配置。

GPIO 唤醒允许在深度睡眠模式下通过 GPIO 引脚的电平变化唤醒设备。与外部唤醒(EXT0/EXT1)相比,GPIO 唤醒支持更多的 GPIO 引脚,并且可以配置为高电平或低电平触发。

相关函数:

esp_sleep_enable_gpio_wakeup();
  • 所有GPIO引脚:

并非所有 GPIO 引脚都支持 GPIO 唤醒功能。请参考 ESP32-S3 的技术手册,确认所选引脚是否支持唤醒功能。

  • 配置 GPIO 引脚并使用 GPIO 唤醒功能:
#include "driver/gpio.h"
#include "esp_sleep.h"

void app_main() {
    // 配置 GPIO12 为输入模式,启用上拉电阻
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << GPIO_NUM_12), // GPIO12
        .mode = GPIO_MODE_INPUT,               // 输入模式
        .pull_up_en = GPIO_PULLUP_ENABLE,      // 使能上拉电阻
        .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用下拉电阻
        .intr_type = GPIO_INTR_DISABLE,        // 禁用中断
    };
    gpio_config(&io_conf);

    // 配置 GPIO12 为高电平触发唤醒
    gpio_wakeup_enable(GPIO_NUM_12, GPIO_INTR_HIGH_LEVEL);

    // 启用 GPIO 唤醒
    esp_sleep_enable_gpio_wakeup();

    // 进入深度睡眠
    printf("Entering deep sleep\n");
    esp_deep_sleep_start();
}
  1. UART 唤醒(UART Wakeup)

描述: 通过 UART 接收到的数据唤醒设备。(仅适用于 Light-sleep 模式)

相关函数:

esp_sleep_enable_uart_wakeup(int uart_num);

uart_num: UART 端口号(例如 UART_NUM_0)。

  • 特点: 适用于需要通过串口通信唤醒的场景。
  • 串口唤醒配置代码:
#include "driver/uart.h"
#include "esp_sleep.h"
#include "esp_log.h"

#define UART_NUM UART_NUM_1
#define TX_PIN GPIO_NUM_17
#define RX_PIN GPIO_NUM_18

void uart_init() {
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    uart_param_config(UART_NUM, &uart_config);
    uart_set_pin(UART_NUM, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    uart_driver_install(UART_NUM, 1024, 0, 0, NULL, 0);
}

void enable_uart_wakeup() {
    esp_sleep_enable_uart_wakeup(UART_NUM);
}

void enter_light_sleep() {
    ESP_LOGI("UART", "Entering light sleep");
    esp_light_sleep_start();
    ESP_LOGI("UART", "Woken up from light sleep");
}

void app_main() {
    // 初始化 UART
    uart_init();

    // 启用 UART 唤醒
    enable_uart_wakeup();

    // 进入 Light-sleep 模式
    enter_light_sleep();
}
  • 调用 API esp_sleep_disable_wakeup_source(esp_sleep_source_t source) 可以禁用给定唤醒源的触发器,从而禁用该唤醒源。
typedef enum {
    ESP_SLEEP_WAKEUP_UNDEFINED,    //!< In case of deep sleep, reset was not caused by exit from deep sleep
    ESP_SLEEP_WAKEUP_ALL,          //!< Not a wakeup cause, used to disable all wakeup sources with esp_sleep_disable_wakeup_source
    ESP_SLEEP_WAKEUP_EXT0,         //!< Wakeup caused by external signal using RTC_IO
    ESP_SLEEP_WAKEUP_EXT1,         //!< Wakeup caused by external signal using RTC_CNTL
    ESP_SLEEP_WAKEUP_TIMER,        //!< Wakeup caused by timer
    ESP_SLEEP_WAKEUP_TOUCHPAD,     //!< Wakeup caused by touchpad
    ESP_SLEEP_WAKEUP_ULP,          //!< Wakeup caused by ULP program
    ESP_SLEEP_WAKEUP_GPIO,         //!< Wakeup caused by GPIO (light sleep only on ESP32, S2 and S3)
    ESP_SLEEP_WAKEUP_UART,         //!< Wakeup caused by UART (light sleep only)
    ESP_SLEEP_WAKEUP_WIFI,              //!< Wakeup caused by WIFI (light sleep only)
    ESP_SLEEP_WAKEUP_COCPU,             //!< Wakeup caused by COCPU int
    ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG,   //!< Wakeup caused by COCPU crash
    ESP_SLEEP_WAKEUP_BT,           //!< Wakeup caused by BT (light sleep only)
    ESP_SLEEP_WAKEUP_VAD,          //!< Wakeup caused by VAD
} esp_sleep_source_t;
  • 如果将参数设置为 ESP_SLEEP_WAKEUP_ALL,该函数可用于禁用所有触发器。
  1. WiFi 唤醒(WiFi Wakeup)

描述: 通过 WiFi 信号唤醒设备。ESP32-S3 支持在深度睡眠模式下通过 WiFi 唤醒。

相关函数:

esp_sleep_enable_wifi_wakeup();

特点: 适用于需要 WiFi 远程唤醒的场景。

  1. RTC 看门狗定时器唤醒(RTC Watchdog Timer Wakeup)
    描述: 通过 RTC 看门狗定时器唤醒设备。

相关函数:

esp_sleep_enable_rtc_watchdog_wakeup();
  1. SDIO 唤醒(SDIO Wakeup)

描述: 通过 SDIO 接口的信号变化唤醒设备。

相关函数:

esp_sleep_enable_sdio_wakeup();

特点: 适用于需要 SDIO 接口唤醒的场景。

  1. 组合唤醒源

描述: 可以同时启用多个唤醒源,设备在满足任意一个唤醒源条件时唤醒。

示例:

esp_sleep_enable_timer_wakeup(5000000); // 5秒后唤醒
esp_sleep_enable_ext0_wakeup(GPIO_NUM_12, 1); // GPIO12高电平唤醒
esp_deep_sleep_start(); // 进入深度睡眠

📗RTC 快速内存(RTC Fast Memory)用法

RTC快速内存是ESP32芯片中一块特殊的内存区域,即使在深度睡眠模式下也能保持供电,因此可以在唤醒时快速执行代码。esp32s3可访问最多 8 KB SRAM RTC 慢速内存,用于储存指令和数据.

  • 使用方法一:​ 将函数放置在文件名以rtc_wake_stub开头的源文件中。这种命名约定会让编译器自动将这些文件中的内容链接到RTC内存中。​
  • 例程见:v5.4\esp-idf\examples\system\deep_sleep_wake_stub
  • 使用方法二:​ 在ESP-IDF中,RTC_IRAM_ATTR 是一个特殊的属性宏,用于将函数或变量放置在 RTC 快速内存(RTC Fast Memory) 中。RTC 快速内存是一块特殊的内存区域,即使在深度睡眠模式下也能保持供电,因此适合存放需要在唤醒时立即执行的代码或数据。
#include "esp_sleep.h"
#include "esp_attr.h"  // 包含 RTC_IRAM_ATTR 的定义

// 使用 RTC_IRAM_ATTR 将函数放置在 RTC 内存中
void RTC_IRAM_ATTR my_wake_stub_function() {
    // 这里是唤醒后立即执行的代码
    // 例如:读取 RTC 寄存器的值或执行一些低级别操作
    printf("Wake stub function executed!\n");
}

void app_main() {
    // 设置唤醒存根函数
    esp_set_deep_sleep_wake_stub(&my_wake_stub_function);

    // 进入深度睡眠
    esp_deep_sleep_start();
}

http://www.kler.cn/a/537703.html

相关文章:

  • 无限使用Cursor
  • 蓝桥杯Java之输入输出练习题
  • 探索robots.txt:网站管理者的搜索引擎指南
  • 解释一下数据库中的事务隔离级别,在 Java 中如何通过 JDBC设置事务隔离级别?
  • HAL库 Systick定时器 基于STM32F103EZT6 野火霸道,可做参考
  • Linux之安装docker
  • XML Schema 限定 / Facets
  • leetcode1313--解压缩编码列表
  • Kong故障转移参数配置
  • [图文]课程讲解片段-Fowler分析模式的剖析和实现01
  • 2025.2.8——一、[护网杯 2018]easy_tornado tornado模板注入
  • CNN-day10-经典神经网络MobileNet V1&V2&V3
  • Spring 中的 事务 隔离级别以及传播行为
  • kafka 3.5.0 raft协议安装
  • PHP在线客服系统
  • 【WebLogic】Oracle发布WebLogic 14c最新版本-14.1.2.0
  • 「JVS更新日志」生产计划排程系统APS已上线!以及智能BI、低代码、规则引擎2.6更新说明
  • anaconda中可以import cv2,但是notebook中cv2 module not found
  • 深入理解 C++17 std::is_swappable
  • 使用 Axios ——个人信息修改与提示框实现
  • 参数映射服务完整解决方案
  • Could not create task ‘:mainActivity:minifyReleaseWithR8‘.
  • 【Flink快速入门-8.Flink Flink 架构介绍】
  • 利用Termux在安卓手机中安装 PostgreSQL
  • CPP集群聊天服务器开发实践(一):用户注册与登录
  • Chrome谷歌多开教程:实用方法与工具