Sleep Modes are strategies used to minimize energy consumption in electronic devices when they are not actively performing tasks.
These modes allow for significantly reduced energy consumption, which is crucial for applications that run on batteries or 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 outdated information about this in tutorials on the internet. If you have any doubts, consult the official documentation from the manufacturer.
Sleep Modes in the ESP32
The ESP32 has two Sleep modes. Combined with the “normal” (active) mode, there are three possible operating modes.
⚡ Active Mode
This is the “normal” mode where everything is connected. The CPU, RAM, and all peripherals are active.
The ESP32 is doing its tasks, processing data, with WiFi and BT enabled.
🔋 Light Sleep Mode
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 continues its execution at the same point in the program it was at, preserving memory.
We see this in the post How to use Light Sleep mode in an ESP32
💤 Deep Sleep Mode
Deep Sleep mode is much more aggressive. It is almost like turning off and on the ESP32.
The CPUs, RAM, and digital peripherals are turned off. Only the RTC remains active.
When returning to normal mode, the ESP32 starts from the beginning of the program. Everything we had saved in memory is lost.
We see this in the post How to use Deep Sleep mode in an ESP32
WakeUp Sources
WakeUp Sources are also the most important part of entering Sleep mode. They are the available ways to wake up from Sleep mode.
By default, the ESP32 will deactivate all peripherals, except those that we specify as WakeUp Sources. That is, the final state and consumption of the ESP32 will depend on the WakeUp Sources we define.
The WakeUp Sources that are available in both Deep Sleep and Light Sleep modes are the following.
- Timer
- Touchpad
- ULP Coprocessor Wakeup
- External Wakeup (Ext0 and Ext1)
And these that 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);
Alternatively, we could use the function esp_sleep_pd_config
(internally, the above functions do this):
esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
esp_sleep_pd_option_t option);
Where esp_sleep_pd_domain_t
can take the following 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;
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;
Disable Sleep Wakeup Source
If necessary, we can disable one of the WakeUp Sources that we have 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);
Get WakeUp Cause
The function esp_sleep_get_wakeup_cause()
can be used to check which activation 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;
For the touchpad, it is possible to identify which touch pin caused the activation using the functions esp_sleep_get_touchpad_wakeup_status()
.
void print_wakeup_touchpad(){
touchPin = esp_sleep_get_touchpad_wakeup_status();
Serial.printf("Touch detected on %d\n",touchPin);
}
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);
}
For ext1 wakeup sources, it is possible to identify which pin caused the activation using the functions esp_sleep_get_ext1_wakeup_status()
.
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);
}
Disable Radio
When entering a Sleep mode, the radio (WiFi and BT) is turned off in a “not so elegant” way. Therefore, if we are using any of these communication methods, we must explicitly disable it by doing:
esp_bluedroid_disable();
esp_bt_controller_disable();
esp_wifi_stop();
Which, in the case of using the Arduino environment, is done like this.
btStop();
WiFi.mode(WIFI_OFF);