睡眠模式

[English]

概述

ESP32-C3 具有 Light-sleep 和 Deep-sleep 两种睡眠节能模式。

在 Light-sleep 模式下,数字外设、CPU、以及大部分 RAM 都使用时钟门控,同时电源电压降低。退出该模式后,数字外设、CPU 和 RAM 恢复运行,内部状态保持不变。

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

  • RTC 控制器

  • RTC 高速内存

Light-sleep 和 Deep-sleep 模式有多种唤醒源。这些唤醒源也可以组合在一起,此时任何一个唤醒源都可以触发唤醒。通过 API esp_sleep_enable_X_wakeup 可启用唤醒源,通过 API esp_sleep_disable_wakeup_source() 可禁用唤醒源,详见下一小节。在系统进入 Light-sleep 或 Deep-sleep 模式前,可以在任意时刻配置唤醒源。

此外,应用程序可以使用 API esp_sleep_pd_config() 强制 RTC 外设和 RTC 内存进入特定断电模式。

配置唤醒源后,应用程序就可以使用 API esp_light_sleep_start()esp_deep_sleep_start() 进入睡眠模式。此时,系统将按照被请求的唤醒源配置硬件,同时 RTC 控制器会给 CPU 和数字外设断电。

睡眠模式下的 Wi-Fi 和 Bluetooth 功能

在 Light-sleep 和 Deep-sleep 模式下,无线外设会被断电。因此,在进入这两种睡眠模式前,应用程序必须调用恰当的函数(nimble_port_stop()nimble_port_deinit()esp_bluedroid_disable()esp_bluedroid_deinit()esp_bt_controller_disable()esp_bt_controller_deinit()esp_wifi_stop())来禁用 Wi-Fi 和 Bluetooth。在 Light-sleep 或 Deep-sleep 模式下,即使不调用这些函数也无法连接 Wi-Fi 和 Bluetooth。

如需保持 Wi-Fi 和 Bluetooth 连接,请启用 Wi-Fi 和 Bluetooth Modem-sleep 模式和自动 Light-sleep 模式(请参阅 电源管理 API)。在这两种模式下,Wi-Fi 和 Bluetooth 驱动程序发出请求时,系统将自动从睡眠中被唤醒,从而保持连接。

唤醒源

定时器

RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒芯片。时间精度为微秒,但其实际分辨率依赖于为 RTC SLOW_CLK 所选择的时钟源。

在这种唤醒模式下,无需为睡眠模式中的 RTC 外设或内存供电。

调用 esp_sleep_enable_timer_wakeup() 函数可启用使用定时器唤醒睡眠模式。

GPIO 唤醒

任何一个 IO 都可以用作外部输入管脚,将芯片从 Light-sleep 状态唤醒。调用 gpio_wakeup_enable() 函数可以将任意管脚单独配置为在高电平或低电平触发唤醒。此后,应调用 esp_sleep_enable_gpio_wakeup() 函数来启用此唤醒源。

此外,可将由 VDD3P3_RTC 电源域供电的 IO 用于芯片的 Deep-sleep 唤醒。调用 esp_deep_sleep_enable_gpio_wakeup() 函数可以配置相应的唤醒管脚和唤醒触发电平,该函数用于启用相应管脚的 Deep-sleep 唤醒功能。

UART 唤醒(仅适用于 Light-sleep 模式)

当 ESP32-C3 从外部设备接收 UART 输入时,通常需要在输入数据可用时唤醒芯片。UART 外设支持在 RX 管脚上观测到一定数量的上升沿时,将芯片从 Light-sleep 模式中唤醒。调用 uart_set_wakeup_threshold() 函数可设置被观测上升沿的数量。请注意,触发唤醒的字符(及该字符前的所有字符)在唤醒后不会被 UART 接收,因此在发送数据之前,外部设备通常需要首先向 ESP32-C3 额外发送一个字符以触发唤醒。

可调用 esp_sleep_enable_uart_wakeup() 函数来启用此唤醒源。

使用 UART 唤醒之后,在芯片 Active 模式下需要让 UART 接受一些数据用来清零内部的唤醒指示信号。不然的话,下一次 UART 唤醒的触发将只需要比配置的阈值少两个上升沿的数量。

RTC 外设和内存断电

默认情况下,调用函数 esp_deep_sleep_start()esp_light_sleep_start() 后,所有唤醒源不需要的 RTC 电源域都会被断电。可调用函数 esp_sleep_pd_config() 来修改这一设置。

ESP32-C3 中只有 RTC 高速内存,因此,如果程序中的某些值被标记为 RTC_DATA_ATTRRTC_SLOW_ATTRRTC_FAST_ATTR 属性,那么所有这些值都将被存入 RTC 高速内存,默认情况下保持供电。如果有需要,您也可以使用函数 esp_sleep_pd_config() 对其进行修改。

Flash 断电

默认情况下,调用函数 esp_light_sleep_start() 后, flash 不会 断电,因为在 sleep 过程中断电 flash 存在风险。具体而言,flash 断电需要时间,但是在此期间,系统有可能被唤醒,导致 flash 重新被上电。此时,断电尚未完成又重新上电的硬件行为有可能导致 flash 无法正常工作。

理论上讲,在 flash 完全断电后可以仅唤醒系统,然而现实情况是 flash 断电所需的时间很难预测。如果用户为 flash 供电电路添加了滤波电容,断电所需时间可能会更长。此外,即使可以预知 flash 彻底断电所需的时间,有时也不能通过设置足够长的睡眠时间来确保 flash 断电的安全(比如,突发的异步唤醒源会使得实际的睡眠时间不可控)。

警告

如果在 flash 的供电电路上添加了滤波电容,那么应当尽一切可能避免 flash 断电。

因为这些不可控的因素,ESP-IDF 很难保证 flash断电的绝对安全。因此 ESP-IDF 不推荐用户断电 flash。对于一些功耗敏感型应用,可以通过设置 Kconfig 配置项 CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND 来减少 light sleep 期间 flash 的功耗。这种方式在几乎所有场景下都要比断电 flash 更好,兼顾了安全性和功耗。

考虑到有些用户能够充分评估断电 flash 的风险,并希望通过断电 flash 来获得更低的功耗,因此 ESP-IDF 提供了两种断电 flash 的机制:

  • 设置 Kconfig 配置项 CONFIG_ESP_SLEEP_POWER_DOWN_FLASH 将使 ESP-IDF 以一个严格的条件来断电 flash。严格的条件具体指的是,RTC timer 是唯一的唤醒源 睡眠时间比 flash 彻底断电所需时间更长。

  • 调用函数 esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_OFF) 将使 ESP-IDF 以一个宽松的条件来断电 flash。宽松的条件具体指的是 RTC timer 唤醒源未被使能 睡眠时间比 flash 彻底断电所需时间更长。

备注

  • Light sleep 时,ESP-IDF 没有提供保证 flash 一定会被断电的机制。

  • 不管用户的配置如何,函数 esp_deep_sleep_start() 都会强制断电 flash。

进入 Light-sleep 模式

函数 esp_light_sleep_start() 可用于在配置唤醒源后进入 Light-sleep 模式,也可用于在未配置唤醒源的情况下进入 Light-sleep 模式。在后一种情况中,芯片将一直处于睡眠模式,直到从外部被复位。

进入 Deep-sleep 模式

函数 esp_deep_sleep_start() 可用于在配置唤醒源后进入 Deep-sleep 模式,也可用于在未配置唤醒源的情况下进入 Deep-sleep 模式 模式。在后一种情况中,芯片将一直处于睡眠模式,直到从外部被复位。

配置 IO

一些 ESP32-C3 IO 在默认情况下启用内部上拉或下拉电阻。如果这些管脚在 Deep-sleep 模式下中受外部电路驱动,电流流经这些上下拉电阻时,可能会增加电流消耗。

在 Deep-sleep 模式中:
  • 数字 GPIO (GPIO6 ~ 21) 处于高阻态。

  • RTC GPIO (GPIO0 ~ 5) 可能处于以下状态:
    • 如果未启用保持 (hold) 功能,RTC GPIO 将处于高阻态。

    • 如果启用保持功能,RTC GPIO 管脚将会在保持功能开启时处于锁存状态。

UART 输出处理

在进入睡眠模式之前,调用函数 esp_deep_sleep_start() 会冲刷掉 UART FIFO 缓存。

当使用函数 esp_light_sleep_start() 进入 Light-sleep 模式时,UART FIFO 将不会被冲刷。与之相反,UART 输出将被暂停,FIFO 中的剩余字符将在 Light-sleep 唤醒后被发送。

检查睡眠唤醒原因

esp_sleep_get_wakeup_cause() 函数可用于检测是何种唤醒源在睡眠期间被触发。

禁用睡眠模式唤醒源

调用 API esp_sleep_disable_wakeup_source() 可以禁用给定唤醒源的触发器,从而禁用该唤醒源。此外,如果将参数设置为 ESP_SLEEP_WAKEUP_ALL,该函数可用于禁用所有触发器。

应用程序示例

  • protocols/sntp:如何实现 Deep-sleep 模式的基本功能,周期性唤醒 ESP 模块,以从 NTP 服务器获取时间。

  • wifi/power_save:如何实现 Wi-Fi Modem-sleep 模式。

API 参考

Header File

Functions

esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source)

Disable wakeup source.

This function is used to deactivate wake up trigger for source defined as parameter of the function.

See docs/sleep-modes.rst for details.

备注

This function does not modify wake up configuration in RTC. It will be performed in esp_deep_sleep_start/esp_light_sleep_start function.

参数

source -- - number of source to disable of type esp_sleep_source_t

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_STATE if trigger was not active

esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)

Enable wakeup by timer.

参数

time_in_us -- time before wakeup, in microseconds

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_ARG if value is out of range (TBD)

bool esp_sleep_is_valid_wakeup_gpio(gpio_num_t gpio_num)

Returns true if a GPIO number is valid for use as wakeup source.

备注

For SoCs with RTC IO capability, this can be any valid RTC IO input pin.

参数

gpio_num -- Number of the GPIO to test for wakeup source capability

返回

True if this GPIO number will be accepted as a sleep wakeup source.

esp_err_t esp_deep_sleep_enable_gpio_wakeup(uint64_t gpio_pin_mask, esp_deepsleep_gpio_wake_up_mode_t mode)

Enable wakeup using specific gpio pins.

This function enables an IO pin to wake up the chip from deep sleep.

备注

This function does not modify pin configuration. The pins are configured inside esp_deep_sleep_start, immediately before entering sleep mode.

备注

You don't need to worry about pull-up or pull-down resistors before using this function because the ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS option is enabled by default. It will automatically set pull-up or pull-down resistors internally in esp_deep_sleep_start based on the wakeup mode. However, when using external pull-up or pull-down resistors, please be sure to disable the ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS option, as the combination of internal and external resistors may cause interference. BTW, when you use low level to wake up the chip, we strongly recommend you to add external resistors (pull-up).

参数
  • gpio_pin_mask -- Bit mask of GPIO numbers which will cause wakeup. Only GPIOs which have RTC functionality (pads that powered by VDD3P3_RTC) can be used in this bit map.

  • mode -- Select logic function used to determine wakeup condition:

    • ESP_GPIO_WAKEUP_GPIO_LOW: wake up when the gpio turn to low.

    • ESP_GPIO_WAKEUP_GPIO_HIGH: wake up when the gpio turn to high.

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_ARG if the mask contains any invalid deep sleep wakeup pin or wakeup mode is invalid

esp_err_t esp_sleep_enable_gpio_wakeup(void)

Enable wakeup from light sleep using GPIOs.

Each GPIO supports wakeup function, which can be triggered on either low level or high level. Unlike EXT0 and EXT1 wakeup sources, this method can be used both for all IOs: RTC IOs and digital IOs. It can only be used to wakeup from light sleep though.

To enable wakeup, first call gpio_wakeup_enable, specifying gpio number and wakeup level, for each GPIO which is used for wakeup. Then call this function to enable wakeup feature.

备注

On ESP32, GPIO wakeup source can not be used together with touch or ULP wakeup sources.

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_STATE if wakeup triggers conflict

esp_err_t esp_sleep_enable_uart_wakeup(int uart_num)

Enable wakeup from light sleep using UART.

Use uart_set_wakeup_threshold function to configure UART wakeup threshold.

Wakeup from light sleep takes some time, so not every character sent to the UART can be received by the application.

备注

ESP32 does not support wakeup from UART2.

参数

uart_num -- UART port to wake up from

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_ARG if wakeup from given UART is not supported

esp_err_t esp_sleep_enable_bt_wakeup(void)

Enable wakeup by bluetooth.

返回

  • ESP_OK on success

  • ESP_ERR_NOT_SUPPORTED if wakeup from bluetooth is not supported

esp_err_t esp_sleep_disable_bt_wakeup(void)

Disable wakeup by bluetooth.

返回

  • ESP_OK on success

  • ESP_ERR_NOT_SUPPORTED if wakeup from bluetooth is not supported

esp_err_t esp_sleep_enable_wifi_wakeup(void)

Enable wakeup by WiFi MAC.

返回

  • ESP_OK on success

esp_err_t esp_sleep_disable_wifi_wakeup(void)

Disable wakeup by WiFi MAC.

返回

  • ESP_OK on success

esp_err_t esp_sleep_enable_wifi_beacon_wakeup(void)

Enable beacon wakeup by WiFi MAC, it will wake up the system into modem state.

返回

  • ESP_OK on success

esp_err_t esp_sleep_disable_wifi_beacon_wakeup(void)

Disable beacon wakeup by WiFi MAC.

返回

  • ESP_OK on success

uint64_t esp_sleep_get_ext1_wakeup_status(void)

Get the bit mask of GPIOs which caused wakeup (ext1)

If wakeup was caused by another source, this function will return 0.

返回

bit mask, if GPIOn caused wakeup, BIT(n) will be set

uint64_t esp_sleep_get_gpio_wakeup_status(void)

Get the bit mask of GPIOs which caused wakeup (gpio)

If wakeup was caused by another source, this function will return 0.

返回

bit mask, if GPIOn caused wakeup, BIT(n) will be set

esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, esp_sleep_pd_option_t option)

Set power down mode for an RTC power domain in sleep mode.

If not set set using this API, all power domains default to ESP_PD_OPTION_AUTO.

参数
  • domain -- power domain to configure

  • option -- power down option (ESP_PD_OPTION_OFF, ESP_PD_OPTION_ON, or ESP_PD_OPTION_AUTO)

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_ARG if either of the arguments is out of range

esp_err_t esp_deep_sleep_try_to_start(void)

Enter deep sleep with the configured wakeup options.

The reason for the rejection can be such as a short sleep time.

备注

In general, the function does not return, but if the sleep is rejected, then it returns from it.

返回

  • No return - If the sleep is not rejected.

  • ESP_ERR_SLEEP_REJECT sleep request is rejected(wakeup source set before the sleep request)

void esp_deep_sleep_start(void)

Enter deep sleep with the configured wakeup options.

备注

The function does not do a return (no rejection). Even if wakeup source set before the sleep request it goes to deep sleep anyway.

esp_err_t esp_light_sleep_start(void)

Enter light sleep with the configured wakeup options.

返回

  • ESP_OK on success (returned after wakeup)

  • ESP_ERR_SLEEP_REJECT sleep request is rejected(wakeup source set before the sleep request)

  • ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION after deducting the sleep flow overhead, the final sleep duration is too short to cover the minimum sleep duration of the chip, when rtc timer wakeup source enabled

esp_err_t esp_deep_sleep_try(uint64_t time_in_us)

Enter deep-sleep mode.

The device will automatically wake up after the deep-sleep time Upon waking up, the device calls deep sleep wake stub, and then proceeds to load application.

Call to this function is equivalent to a call to esp_deep_sleep_enable_timer_wakeup followed by a call to esp_deep_sleep_start.

参数

time_in_us -- deep-sleep time, unit: microsecond

返回

  • No return - If the sleep is not rejected.

  • ESP_ERR_SLEEP_REJECT sleep request is rejected(wakeup source set before the sleep request)

void esp_deep_sleep(uint64_t time_in_us)

Enter deep-sleep mode.

The device will automatically wake up after the deep-sleep time Upon waking up, the device calls deep sleep wake stub, and then proceeds to load application.

Call to this function is equivalent to a call to esp_deep_sleep_enable_timer_wakeup followed by a call to esp_deep_sleep_start.

备注

The function does not do a return (no rejection).. Even if wakeup source set before the sleep request it goes to deep sleep anyway.

参数

time_in_us -- deep-sleep time, unit: microsecond

esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb)

Register a callback to be called from the deep sleep prepare.

警告

deepsleep callbacks should without parameters, and MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.

参数

new_dslp_cb -- Callback to be called

返回

  • ESP_OK: Callback registered to the deepsleep misc_modules_sleep_prepare

  • ESP_ERR_NO_MEM: No more hook space for register the callback

void esp_deep_sleep_deregister_hook(esp_deep_sleep_cb_t old_dslp_cb)

Unregister an deepsleep callback.

参数

old_dslp_cb -- Callback to be unregistered

esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)

Get the wakeup source which caused wakeup from sleep.

返回

cause of wake up from last sleep (deep sleep or light sleep)

void esp_wake_deep_sleep(void)

Default stub to run on wake from deep sleep.

Allows for executing code immediately on wake from sleep, before the software bootloader or ESP-IDF app has started up.

This function is weak-linked, so you can implement your own version to run code immediately when the chip wakes from sleep.

See docs/deep-sleep-stub.rst for details.

void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub)

Install a new stub at runtime to run on wake from deep sleep.

If implementing esp_wake_deep_sleep() then it is not necessary to call this function.

However, it is possible to call this function to substitute a different deep sleep stub. Any function used as a deep sleep stub must be marked RTC_IRAM_ATTR, and must obey the same rules given for esp_wake_deep_sleep().

void esp_set_deep_sleep_wake_stub_default_entry(void)

Set wake stub entry to default esp_wake_stub_entry

esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void)

Get current wake from deep sleep stub.

返回

Return current wake from deep sleep stub, or NULL if no stub is installed.

void esp_default_wake_deep_sleep(void)

The default esp-idf-provided esp_wake_deep_sleep() stub.

See docs/deep-sleep-stub.rst for details.

void esp_deep_sleep_disable_rom_logging(void)

Disable logging from the ROM code after deep sleep.

Using LSB of RTC_STORE4.

esp_err_t esp_sleep_cpu_pd_low_init(void)

CPU Power down low-level initialize, enable CPU power down during light sleep.

返回

  • ESP_OK on success

  • ESP_ERR_NO_MEM not enough retention memory

esp_err_t esp_sleep_cpu_pd_low_deinit(void)

CPU Power down low-level deinitialize, disable CPU power down during light sleep.

返回

  • ESP_OK on success

  • ESP_ERR_NO_MEM not enough retention memory

esp_err_t esp_sleep_cpu_retention_init(void)

CPU Power down initialize.

返回

  • ESP_OK on success

  • ESP_ERR_NO_MEM not enough retention memory

esp_err_t esp_sleep_cpu_retention_deinit(void)

CPU Power down de-initialize.

Release system retention memory.

返回

  • ESP_OK on success

void esp_sleep_config_gpio_isolate(void)

Configure to isolate all GPIO pins in sleep state.

void esp_sleep_enable_gpio_switch(bool enable)

Enable or disable GPIO pins status switching between slept status and waked status.

参数

enable -- decide whether to switch status or not

Macros

ESP_PD_DOMAIN_RTC8M

Type Definitions

typedef void (*esp_deep_sleep_cb_t)(void)
typedef esp_sleep_source_t esp_sleep_wakeup_cause_t
typedef void (*esp_deep_sleep_wake_stub_fn_t)(void)

Function type for stub to run on wake from sleep.

Enumerations

enum esp_deepsleep_gpio_wake_up_mode_t

Logic function used for EXT1 wakeup mode.

Values:

enumerator ESP_GPIO_WAKEUP_GPIO_LOW
enumerator ESP_GPIO_WAKEUP_GPIO_HIGH
enum esp_sleep_pd_domain_t

Power domains which can be powered down in sleep mode.

Values:

enumerator ESP_PD_DOMAIN_XTAL

XTAL oscillator.

enumerator ESP_PD_DOMAIN_RC_FAST

Internal Fast oscillator.

enumerator ESP_PD_DOMAIN_CPU

CPU core.

enumerator ESP_PD_DOMAIN_VDDSDIO

VDD_SDIO.

enumerator ESP_PD_DOMAIN_MAX

Number of domains.

enum esp_sleep_pd_option_t

Power down options.

Values:

enumerator ESP_PD_OPTION_OFF

Power down the power domain in sleep mode.

enumerator ESP_PD_OPTION_ON

Keep power domain enabled during sleep mode.

enumerator ESP_PD_OPTION_AUTO

Keep power domain enabled in sleep mode, if it is needed by one of the wakeup options. Otherwise power it down.

enum esp_sleep_source_t

Sleep wakeup cause.

Values:

enumerator ESP_SLEEP_WAKEUP_UNDEFINED

In case of deep sleep, reset was not caused by exit from deep sleep.

enumerator ESP_SLEEP_WAKEUP_ALL

Not a wakeup cause, used to disable all wakeup sources with esp_sleep_disable_wakeup_source.

enumerator ESP_SLEEP_WAKEUP_EXT0

Wakeup caused by external signal using RTC_IO.

enumerator ESP_SLEEP_WAKEUP_EXT1

Wakeup caused by external signal using RTC_CNTL.

enumerator ESP_SLEEP_WAKEUP_TIMER

Wakeup caused by timer.

enumerator ESP_SLEEP_WAKEUP_TOUCHPAD

Wakeup caused by touchpad.

enumerator ESP_SLEEP_WAKEUP_ULP

Wakeup caused by ULP program.

enumerator ESP_SLEEP_WAKEUP_GPIO

Wakeup caused by GPIO (light sleep only on ESP32, S2 and S3)

enumerator ESP_SLEEP_WAKEUP_UART

Wakeup caused by UART (light sleep only)

enumerator ESP_SLEEP_WAKEUP_WIFI

Wakeup caused by WIFI (light sleep only)

enumerator ESP_SLEEP_WAKEUP_COCPU

Wakeup caused by COCPU int.

enumerator ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG

Wakeup caused by COCPU crash.

enumerator ESP_SLEEP_WAKEUP_BT

Wakeup caused by BT (light sleep only)

enum esp_sleep_mode_t

Sleep mode.

Values:

enumerator ESP_SLEEP_MODE_LIGHT_SLEEP

light sleep mode

enumerator ESP_SLEEP_MODE_DEEP_SLEEP

deep sleep mode

enum [anonymous]

Values:

enumerator ESP_ERR_SLEEP_REJECT
enumerator ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION