Save energy on ESP32 with Deep Sleep
The ESP32 has a power-saving mode called Deep Sleep which allows you to “put the ESP32 to sleep”. It’s a bit like putting a computer to sleep to save energy. The ESP32 can perform simple tasks during this mode and be woken up to perform more complex tasks.
What’s the point?
This power-saving mode is useful when the ESP32 is battery powered and the ESP32 “works” occasionally. (For example, reading a value from a sensor and sending it over Wi-Fi every 10 minutes). If the ESP32 is switched on 24 hours a day, the battery will be discharged very quickly. With Deep Sleep mode, the batteries will last much longer.
Deep Sleep mode put the ESP32 into a pristine state
Indeed, in Deep Sleep mode, the 2 CPUs of the ESP32 no longer work and it is the ULP (Ultra Low Processor) that takes over. It is a processor that consumes very little power and can perform specific actions. Flash and RAM are no longer powered either. Only RTC memory is still powered and can be used. Wi-Fi and Bluetooth are of course also disabled. Thanks to this RTC memory, you can always access peripherals, interrupts, timers and internal sensors.
Wake-up sources
- After putting the ESP32 into Deep Sleep mode, there are several ways to wake it up:
-
-
Use an internal timer (stopwatch) to wake up the ESP32 at a chosen time (internal alarm clock)
-
Use capacitive touch sensors
-
Use RTC pins
-
Note
You can combine different wake-up sources.
Warning
It is also possible to activate Deep Sleep mode without having configured any wake-up sources. In this case, the ESP32 will be in Deep Sleep mode indefinitely until a manual reset (or by reflashing the board). We cannot therefore “brick” the ESP32 with Deep Sleep mode.
Use
- When you want to use Deep Sleep mode, you have to think about:
-
-
Configure the ESP32 wake-up sources
-
Optionally choose which devices you want to turn off or keep during Deep Sleep mode. By default, the ESP32 turns off all devices that are not needed to detect the wake-up request.
-
Use the
esp_deep_sleep_start()
function to enter Deep Sleep mode.
-
Use a Timer as a wake-up source
Here is the code used to test the timer as a wake-up source:
#define uS_TO_S_FACTOR 1000000
#define TIME_TO_SLEEP 5
RTC_DATA_ATTR int bootCount = 0;
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t source_reveil;
source_reveil = esp_sleep_get_wakeup_cause();
switch(source_reveil){
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Réveil causé par un signal externe avec RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Réveil causé par un signal externe avec RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Réveil causé par un timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Réveil causé par un touchpad"); break;
default : Serial.printf("Réveil pas causé par le Deep Sleep: %d\n",source_reveil); break;
}
}
void setup(){
Serial.begin(115200);
++bootCount;
Serial.println("----------------------");
Serial.println(String(bootCount)+ "eme Boot ");
//Affiche la raison du réveil
print_wakeup_reason();
//Configuration du timer
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("ESP32 réveillé dans " + String(TIME_TO_SLEEP) + " seconds");
//Rentre en mode Deep Sleep
Serial.println("Rentre en mode Deep Sleep");
Serial.println("----------------------");
delay(100);
esp_deep_sleep_start();
Serial.println("Ceci ne sera jamais affiché");
}
void loop(){
}
The
print_wakeup_reason()
function displays the wake-up source of the ESP32. During the 1st boot of the ESP32, the wake-up was not caused by Deep Sleep but by the
“Hard resetting via RTS pin …”
on the Arduino IDE. Then during the subsequent boots, the ESP32 is awakened from deep sleep thanks to a timer every 5 seconds.
You can change the duration of Deep Sleep by modifying the timer with the
esp_sleep_enable_timer_wakeup()
function.
ets Jun 8 2016 00:22:57
rst: 0x10 (RTCWDT_RTC_RESET), boot: 0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP: 0xee
clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: 0x00
mode: DIO, clock div: 1
load: 0x3fff0018, len: 4
load: 0x3fff001c, len: 1216
ho 0 tail 12 room 4
load: 0x40078000, len: 9720
ho 0 tail 12 room 4
load: 0x40080400, len: 6352
entry 0x400806b8
----------------------
1st Boot
Waking up not caused by Deep Sleep: 0
ESP32 woken up in 5 seconds
Enter Deep Sleep mode
----------------------
ets Jun 8 2016 00:22:57
rst: 0x5 (DEEPSLEEP_RESET), boot: 0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP: 0xee
clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: 0x00
mode: DIO, clock div: 1
load: 0x3fff0018, len: 4
load: 0x3fff001c, len: 1216
ho 0 tail 12 room 4
load: 0x40078000, len: 9720
ho 0 tail 12 room 4
load: 0x40080400, len: 6352
entry 0x400806b8
----------------------
2nd Boot
Wake up caused by a timer
ESP32 woken up in 5 seconds
Enter Deep Sleep mode
----------------------
Use a Touchpad as a wake-up call source
Here is the code used to wake up the ESP32 with the touchpads:
#define seuil 30 //Seuil de détection pour le capteur capacitif
RTC_DATA_ATTR int bootCount = 0;
touch_pad_t touchPin;
void fonction_isr(){
}
void setup(){
Serial.begin(115200);
++bootCount;
Serial.println("----------------------");
Serial.println(String(bootCount)+ "eme Boot ");
//Affiche la source du reveil et le numéro du touchpad
print_wakeup_reason();
print_wakeup_touchpad();
//Configuration d'une interruption pour le touchpad T0 (GPIO4)
touchAttachInterrupt(T0, fonction_isr, seuil);
//Active le réveil par les touchpads
esp_sleep_enable_touchpad_wakeup();
//Rentre en mode Deep Sleep
Serial.println("Rentre en mode Deep Sleep");
Serial.println("----------------------");
esp_deep_sleep_start();
}
void loop(){
}
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t source_reveil;
source_reveil = esp_sleep_get_wakeup_cause();
switch(source_reveil){
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Réveil causé par un signal externe avec RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Réveil causé par un signal externe avec RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Réveil causé par un timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Réveil causé par un touchpad"); break;
default : Serial.printf("Réveil pas causé par le Deep Sleep: %d\n",source_reveil); break;
}
}
void print_wakeup_touchpad(){
touch_pad_t pin;
touchPin = esp_sleep_get_touchpad_wakeup_status();
switch(touchPin){
case 0 : Serial.println("Fil touché au GPIO 4"); break;
case 1 : Serial.println("Fil touché au GPIO 0"); break;
case 2 : Serial.println("Fil touché au GPIO 2"); break;
case 3 : Serial.println("Fil touché au GPIO 15"); break;
case 4 : Serial.println("Fil touché au GPIO 13"); break;
case 5 : Serial.println("Fil touché au GPIO 12"); break;
case 6 : Serial.println("Fil touché au GPIO 14"); break;
case 7 : Serial.println("Fil touché au GPIO 27"); break;
case 8 : Serial.println("Fil touché au GPIO 33"); break;
case 9 : Serial.println("Fil touché au GPIO 32"); break;
default : Serial.println("Réveil pas causé les touchpads"); break;
}
}
The
print_wakeup_reason()
function displays the wake-up source of the ESP32 and the
print_wakeup_touchpad()
function displays the number of the touchpad used. We add an interrupt on the touchpad T0 (GPIO4) with the function
touchAttachInterrupt()
During the 1st boot of the ESP32, the wake-up was not caused by Deep Sleep but by
“Hard resetting via RTS pin … “
on the Arduino IDE.
ets Jun 8 2016 00:22:57
rst: 0x10 (RTCWDT_RTC_RESET), boot: 0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP: 0xee
clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: 0x00
mode: DIO, clock div: 1
load: 0x3fff0018, len: 4
load: 0x3fff001c, len: 1216
ho 0 tail 12 room 4
load: 0x40078000, len: 9720
ho 0 tail 12 room 4
load: 0x40080400, len: 6352
entry 0x400806b8
----------------------
1st Boot
Waking up not caused by Deep Sleep: 0
Alarm clock not caused the touchpads
Enter Deep Sleep mode
----------------------
ets Jun 8 2016 00:22:57
rst: 0x5 (DEEPSLEEP_RESET), boot: 0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP: 0xee
clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: 0x00
mode: DIO, clock div: 1
load: 0x3fff0018, len: 4
load: 0x3fff001c, len: 1216
ho 0 tail 12 room 4
load: 0x40078000, len: 9720
ho 0 tail 12 room 4
load: 0x40080400, len: 6352
entry 0x400806b8
----------------------
2nd Boot
Waking up caused by a touchpad
Wire affected at GPIO 4
Enter Deep Sleep mode
-------------
Use a GPIO pin as a wake-up source
You can also use the GPIO pins with a push button to wake the ESP32 from Deep Sleep.
Warning
You can only use the RTC_GPIO pins (light blue inset)
In this example, we use a push button with an external pulldown resistor connected to pin 33:
RTC_DATA_ATTR int bootCount = 0;
void setup(){
Serial.begin(115200);
++bootCount;
Serial.println("----------------------");
Serial.println(String(bootCount)+ "eme Boot ");
//Affiche la source du reveil
print_wakeup_reason();
//Configure le GPIO33 comme source de réveil quand la tension vaut 3.3V
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,HIGH);
//Rentre en mode Deep Sleep
Serial.println("Rentre en mode Deep Sleep");
Serial.println("----------------------");
esp_deep_sleep_start();
}
void loop(){}
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t source_reveil;
source_reveil = esp_sleep_get_wakeup_cause();
switch(source_reveil){
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Réveil causé par un signal externe avec RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Réveil causé par un signal externe avec RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Réveil causé par un timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Réveil causé par un touchpad"); break;
default : Serial.printf("Réveil pas causé par le Deep Sleep: %d\n",source_reveil); break;
}
}
We get in the serial monitor:
ets Jun 8 2016 00:22:57
rst: 0x10 (RTCWDT_RTC_RESET), boot: 0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP: 0xee
clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: 0x00
mode: DIO, clock div: 1
load: 0x3fff0018, len: 4
load: 0x3fff001c, len: 1216
ho 0 tail 12 room 4
load: 0x40078000, len: 9720
ho 0 tail 12 room 4
load: 0x40080400, len: 6352
entry 0x400806b8
----------------------
1st Boot
Waking up not caused by Deep Sleep: 0
Enter Deep Sleep mode
----------------------
ets Jun 8 2016 00:22:57
rst: 0x5 (DEEPSLEEP_RESET), boot: 0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP: 0xee
clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: 0x00
mode: DIO, clock div: 1
load: 0x3fff0018, len: 4
load: 0x3fff001c, len: 1216
ho 0 tail 12 room 4
load: 0x40078000, len: 9720
ho 0 tail 12 room 4
load: 0x40080400, len: 6352
entry 0x400806b8
----------------------
2nd Boot
Waking up caused by an external signal with RTC_IO
Enter Deep Sleep mode
-----------------
Erasing RAM
When Deep Sleep mode is activated, the CPU and RAM are no longer powered. This implies that when the ESP32 wakes up from Deep Sleep, all the variables contained in the RAM are erased. Luckily, there is 8KB RTC RAM that stays on during Deep Sleep. To store variables in this memory, you must add the attribute
RTC_DATA_ATTR
.
For example, the variable that stores the number of ESP32 restarts in the examples is stored in this memory.
RTC_DATA_ATTR int bootCount = 0;