esp32-sleep-modes

What are sleep modes in ESP32

  • 7 min

Sleep Modes are strategies used to minimize energy consumption in electronic devices when they are not actively performing tasks.

These modes allow for significantly reducing energy consumption, which is crucial for battery-powered applications or devices that are permanently connected.

When we enter a Sleep mode, at some point we will need to return to “normal” mode. For this, there are several ways to “wake up” the ESP32. We call these events Wake-Up Sources.

There is a lot of obsolete information on this topic in tutorials on the internet. If in doubt, consult the manufacturer’s official documentation.

Sleep Modes in the ESP32

The ESP32 has two Sleep modes. Added to the “normal” (active) mode, there are three possible operating modes.

⚡ Active Mode

This is the normal mode where everything is connected and powered on. The CPU, RAM, and all peripherals are active.

The ESP32 is doing its thing, processing data, and with WiFi and BT enabled.

🔋 Light Sleep Mode

The Light Sleep mode is similar to the “suspend” mode of a computer. The ESP32 stops and reduces its consumption.

The CPU, RAM, and digital peripherals are disconnected from the clock and their voltage is reduced to save energy.

When returning to normal mode, the ESP32 resumes execution at the same point in the program it was at, preserving memory.

💤 Deep Sleep Mode

The Deep Sleep mode is much more aggressive. It is almost like turning the ESP32 off and on.

The CPUs, RAM, and digital peripherals are powered down. Only the RTC remains active.

When returning to normal mode, the ESP32 starts from the beginning of the program. Everything we had stored in memory is lost.

WakeUp Sources

WakeUp Sources are also the most important part for entering Sleep mode. They are the available ways to wake up from Sleep mode.

By default, the ESP32 will deactivate all peripherals, except those we specify as a WakeUp Source. That is, the final state and consumption of the ESP32 will depend on the WakeUp Sources we define.

The WakeUp Sources available in both modes, Deep Sleep and Light Sleep, are the following.

  • Timer
  • Touchpad
  • ULP Coprocessor Wakeup
  • External Wakeup (Ext0 and Ext1)

And these only work in Light Sleep

  • GPIO Wakeup
  • UART Wakeup
  • WIFI Wakeup

To configure them, we will use these functions:

// Light Sleep and Deep Sleep
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us);
esp_err_t esp_sleep_enable_touchpad_wakeup(void);
esp_err_t esp_sleep_enable_ulp_wakeup(void);
esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);
esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);

// Only in Light Sleep
esp_err_t esp_sleep_enable_gpio_wakeup(void);
esp_err_t esp_sleep_enable_uart_wakeup(int uart_num);
esp_err_t esp_sleep_enable_wifi_wakeup(void);
void esp_sleep_enable_gpio_switch(bool enable);
Copied!

Alternatively, we could use the esp_sleep_pd_config function (internally the previous ones do this):

esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
                                   esp_sleep_pd_option_t option);
Copied!

Where esp_sleep_pd_domain_t can take these values:

/**
 * @brief Power domains which can be powered down in sleep mode
 */
typedef enum {
    ESP_PD_DOMAIN_RTC_PERIPH,      //!< RTC IO, sensors and ULP co-processor
    ESP_PD_DOMAIN_RTC_SLOW_MEM,    //!< RTC slow memory
    ESP_PD_DOMAIN_RTC_FAST_MEM,    //!< RTC fast memory
    ESP_PD_DOMAIN_XTAL,            //!< XTAL oscillator
#if SOC_PM_SUPPORT_CPU_PD
    ESP_PD_DOMAIN_CPU,             //!< CPU core
#endif
    ESP_PD_DOMAIN_RTC8M,           //!< Internal 8M oscillator
    ESP_PD_DOMAIN_VDDSDIO,         //!< VDD_SDIO
    ESP_PD_DOMAIN_MAX              //!< Number of domains
} esp_sleep_pd_domain_t;
Copied!

And esp_sleep_pd_option_t can be:

/**
 * @brief Power down options
 */
typedef enum {
    ESP_PD_OPTION_OFF,      //!< Power down the power domain in sleep mode
    ESP_PD_OPTION_ON,       //!< Keep power domain enabled during sleep mode
    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.
} esp_sleep_pd_option_t;
Copied!

Disable Sleep Wakeup Source

If necessary, we can deactivate one of the WakeUp Sources we defined earlier.

/**
 * @brief Disable wakeup source
 *
 * This function is used to deactivate wake up trigger for source
 * defined as parameter of the function.
 * @param source - number of source to disable of type esp_sleep_source_t
 */
esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source);
Copied!

Get WakeUp Cause

The esp_sleep_get_wakeup_cause() function can be used to check which wake-up source caused the exit from sleep mode.

/**
 * @brief Sleep wakeup cause
 */
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)
    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_source_t;
Copied!

For the touchpad, it is possible to identify which touch pin caused the wake-up using the esp_sleep_get_touchpad_wakeup_status() function.

void print_wakeup_touchpad(){
  touchPin = esp_sleep_get_touchpad_wakeup_status();
  Serial.printf("Touch detected on %d\n",touchPin);
}
Copied!
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();
  Serial.printf("Wakeup reason: %d\n",wakeup_reason);
}
Copied!

For ext1 wake-up sources, it is possible to identify which touch pin caused the wake-up using the esp_sleep_get_ext1_wakeup_status() function.

void print_wakeup_ext1(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_ext1 = esp_sleep_get_wakeup_cause();
  Serial.printf("Ext1 wakeup reason: %d\n", wakeup_ext1);
}
Copied!

Disable radio

When entering a Sleep mode, the radio (WiFi and BT) is turned off in a “not very elegant” way. Therefore, if we are using any of these communication methods, we must explicitly deactivate it by doing.

esp_bluedroid_disable();
esp_bt_controller_disable();
esp_wifi_stop();
Copied!

Which, in the case of using the Arduino environment, is done like this.

btStop();
WiFi.mode(WIFI_OFF);
Copied!