This article is a complete guide for the ESP32 Deep Sleep mode with Arduino IDE. We’ll show you how to put the ESP32 into deep sleep and take a look at different modes to wake it up: timer wake up, touch wake up, and external wake up. This guide provides practical examples with code, code explanation, and circuit diagrams.
Updated 8 October 2024.
Related Content: ESP8266 Deep Sleep with Arduino IDE
This article is divided into 4 different parts:
Introducing Deep Sleep Mode
The ESP32 can switch between different power modes:
- Active mode
- Modem Sleep mode
- Light Sleep mode
- Deep Sleep mode
- Hibernation mode
You can compare the five different modes on the following table from the ESP32 Espressif datasheet.
The ESP32 Espressif datasheet also provides a table comparing the power consumption of the different power modes.
And here’s also Table 10 to compare the power consumption in active mode:
Why Deep Sleep Mode?
Having your ESP32 running on active mode with batteries is not ideal since batteries’ power will drain very quickly.
If you put your ESP32 in deep sleep mode, it will reduce the power consumption, and your batteries will last longer.
Having your ESP32 in deep sleep mode means cutting with the activities that consume more power while operating but leaving just enough activity to wake up the processor when something interesting happens.
In deep sleep mode, neither CPU nor Wi-Fi activities take place, but the Ultra Low Power (ULP) co-processor can still be powered on.
While the ESP32 is in deep sleep mode, the RTC memory also remains powered on, so we can write a program for the ULP co-processor and store it in the RTC memory to access peripheral devices, internal timers, and internal sensors.
This mode of operation is useful if you need to wake up the main CPU by an external event, timer, or both while maintaining minimal power consumption.
RTC_GPIO Pins
During deep sleep, some of the ESP32 pins can be used by the ULP co-processor, namely the RTC_GPIO pins, and the Touch Pins. The ESP32 datasheet provides a table identifying the RTC_GPIO pins. You can find that table here on page 14.
You can use that table as a reference, or take a look at the following pinout to locate the different RTC_GPIO pins. The RTC_GPIO pins are highlighted with an orange rectangular box.
You might also like reading: ESP32 Pinout Reference: Which GPIO pins should you use?
Wake Up Sources
After putting the ESP32 into deep sleep mode, there are several ways to wake it up:
- You can use the timer, waking up your ESP32 using predefined periods of time;
- You can use the touch pins;
- You can use two possibilities of external wake up: you can use either one external wake up, or several different external wake-up sources;
- You can use the ULP co-processor to wake up – this won’t be covered in this guide.
Writing a Deep Sleep Sketch
To write a sketch to put your ESP32 into deep sleep mode, and then wake it up, you need to keep in mind that:
- First, you need to configure the wake up sources. This means configure what will wake up the ESP32. You can use one or combine more than one wake up source.
- You can decide what peripherals to shut down or keep on during deep sleep. However, by default, the ESP32 automatically powers down the peripherals that are not needed with the wake up source you define.
- Finally, you use the esp_deep_sleep_start() function to put your ESP32 into deep sleep mode.
Timer Wake Up
The ESP32 can go into deep sleep mode, and then wake up at predefined periods of time. This feature is specially useful if you are running projects that require time stamping or daily tasks, while maintaining low power consumption.
The ESP32 RTC controller has a built-in timer you can use to wake up the ESP32 after a predefined amount of time.
Enable Timer Wake Up
Enabling the ESP32 to wake up after a predefined amount of time is very straightforward. In the Arduino IDE, you just have to specify the sleep time in microseconds in the following function:
esp_sleep_enable_timer_wakeup(time_in_us)
Code
Let’s see how this works using an example from the library. Open your Arduino IDE, and go to File > Examples > ESP32 Deep Sleep, and open the TimerWakeUp sketch.
/*
Simple Deep Sleep with Timer Wake Up
=====================================
ESP32 offers a deep sleep mode for effective power
saving as power is an important factor for IoT
applications. In this mode CPUs, most of the RAM,
and all the digital peripherals which are clocked
from APB_CLK are powered off. The only parts of
the chip which can still be powered on are:
RTC controller, RTC peripherals ,and RTC memories
This code displays the most basic deep sleep with
a timer to wake it up and how to store data in
RTC memory to use it over reboots
This code is under Public Domain License.
Author:
Pranav Cherukupalli <[email protected]>
*/
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */
RTC_DATA_ATTR int bootCount = 0;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
}
}
void setup(){
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
/*
First we configure the wake up source
We set our ESP32 to wake up every 5 seconds
*/
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
" Seconds");
/*
Next we decide what all peripherals to shut down/keep on
By default, ESP32 will automatically power down the peripherals
not needed by the wakeup source, but if you want to be a poweruser
this is for you. Read in detail at the API docs
http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
Left the line commented as an example of how to configure peripherals.
The line below turns off all RTC peripherals in deep sleep.
*/
//esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
//Serial.println("Configured all RTC Peripherals to be powered down in sleep");
/*
Now that we have setup a wake cause and if needed setup the
peripherals state in deep sleep, we can now start going to
deep sleep.
In the case that no wake up sources were provided but deep
sleep was started, it will sleep forever unless hardware
reset occurs.
*/
Serial.println("Going to sleep now");
delay(1000);
Serial.flush();
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){
//This is not going to be called
}
Let’s take a look at this code. The first comment describes what is powered off during deep sleep with timer wake up.
In this mode CPUs, most of the RAM, and all the digital peripherals which are clocked from APB_CLK are powered off. The only parts of the chip which can still be powered on are: RTC controller, RTC peripherals ,and RTC memories
When you use timer wake-up, the parts that will be powered on are RTC controller, RTC peripherals, and RTC memories.
Define the Sleep Time
These first two lines of code define the period of time the ESP32 will be sleeping.
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */
This example uses a conversion factor from microseconds to seconds, so that you can set the sleep time in the TIME_TO_SLEEP variable in seconds. In this case, the example will put the ESP32 into deep sleep mode for 5 seconds.
Save Data on RTC Memories
With the ESP32, you can save data on the RTC memories. The ESP32 has 8kB SRAM on the RTC part, called RTC fast memory. The data saved here is not erased during deep sleep. However, it is erased when you press the reset button (the button labeled EN on the ESP32 board).
To save data on the RTC memory, you just have to add RTC_DATA_ATTR before a variable definition. The example saves the bootCount variable on the RTC memory. This variable will count how many times the ESP32 has woken up from deep sleep.
RTC_DATA_ATTR int bootCount = 0;
Wake Up Reason
Then, the code defines the print_wakeup_reason() function, that prints the source that caused the wake-up from deep sleep.
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break;
default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
}
}
The setup()
In the setup() is where you should put your code. You need to write all the instructions before calling the esp_deep_sleep_start() function.
This example starts by initializing the serial communication at a baud rate of 115200.
Serial.begin(115200);
Then, the bootCount variable is increased by one in every reboot, and that number is printed in the serial monitor.
++bootCount;
Serial.println("Boot number: " + String(bootCount));
Then, the code calls the print_wakeup_reason() function, but you can call any function you want to perform a desired task. For example, you may want to wake up your ESP32 once a day to read a value from a sensor.
Next, the code defines the wake-up source by using the following function:
esp_sleep_enable_timer_wakeup(time_in_us)
This function accepts as argument the time to sleep in microseconds as we’ve seen previously. In our case, we have the following:
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Then, after all the tasks are performed, the ESP32 goes to sleep by calling the following function:
esp_deep_sleep_start()
As soon as you call the esp_deep_sleep_start() function, the ESP32 will go to sleep and will not run any code written after this function. When it wakes up from deep sleep, it will run the code from the beginning.
loop()
The loop() section is empty because the ESP32 will sleep before reaching this part of the code. So, you need to write all your tasks in the setup() before calling the esp_deep_sleep_start() function.
Testing the Timer Wake Up
Upload the example sketch to your ESP32. Make sure you have the right board and COM port selected. Open the Serial Monitor at a baud rate of 115200.
Every 5 seconds, the ESP32 wakes up, prints a message on the serial monitor, and goes to deep sleep again.
Every time the ESP32 wakes up, the bootCount variable increases. It also prints the wake-up reason as shown in the figure below.
However, notice that if you press the EN button on the ESP32 board, it resets the boot count to 1 again.
You can modify the provided example, and instead of printing a message you can make your ESP do any other task. The timer wake up is useful to perform periodic tasks with the ESP32, like daily tasks, without draining much power.
Touch Wake Up
You can wake up the ESP32 from deep sleep using the touch pins. This section shows how to do that using the Arduino IDE.
Enable Touch Wake-Up
Enabling the ESP32 to wake up using a touchpin is simple. In the Arduino IDE, you need to use the following function—pass as argument the touch pin and the touch threshold:
touchSleepWakeUpEnable(TOUCH_PIN, THRESHOLD);
Code
Let’s see how this works using an example from the library. Open your Arduino IDE, and go to File > Examples > ESP32 Deep Sleep, and open the TouchWakeUp sketch.
/*
Deep Sleep with Touch Wake Up
=====================================
This code displays how to use deep sleep with
a touch as a wake up source and how to store data in
RTC memory to use it over reboots
ESP32 can have multiple touch pads enabled as wakeup source
ESP32-S2 and ESP32-S3 supports only 1 touch pad as wakeup source enabled
This code is under Public Domain License.
Author:
Pranav Cherukupalli <[email protected]>
*/
#if CONFIG_IDF_TARGET_ESP32
#define THRESHOLD 40 /* Greater the value, more the sensitivity */
#else //ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted) */
#define THRESHOLD 5000 /* Lower the value, more the sensitivity */
#endif
RTC_DATA_ATTR int bootCount = 0;
touch_pad_t touchPin;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break;
default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
}
}
/*
Method to print the touchpad by which ESP32
has been awaken from sleep
*/
void print_wakeup_touchpad() {
touchPin = esp_sleep_get_touchpad_wakeup_status();
#if CONFIG_IDF_TARGET_ESP32
switch (touchPin) {
case 0: Serial.println("Touch detected on GPIO 4"); break;
case 1: Serial.println("Touch detected on GPIO 0"); break;
case 2: Serial.println("Touch detected on GPIO 2"); break;
case 3: Serial.println("Touch detected on GPIO 15"); break;
case 4: Serial.println("Touch detected on GPIO 13"); break;
case 5: Serial.println("Touch detected on GPIO 12"); break;
case 6: Serial.println("Touch detected on GPIO 14"); break;
case 7: Serial.println("Touch detected on GPIO 27"); break;
case 8: Serial.println("Touch detected on GPIO 33"); break;
case 9: Serial.println("Touch detected on GPIO 32"); break;
default: Serial.println("Wakeup not by touchpad"); break;
}
#else
if (touchPin < TOUCH_PAD_MAX) {
Serial.printf("Touch detected on GPIO %d\n", touchPin);
} else {
Serial.println("Wakeup not by touchpad");
}
#endif
}
void setup() {
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32 and touchpad too
print_wakeup_reason();
print_wakeup_touchpad();
#if CONFIG_IDF_TARGET_ESP32
//Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27)
touchSleepWakeUpEnable(T3, THRESHOLD);
touchSleepWakeUpEnable(T7, THRESHOLD);
#else //ESP32-S2 + ESP32-S3
//Setup sleep wakeup on Touch Pad 3 (GPIO3)
touchSleepWakeUpEnable(T3, THRESHOLD);
#endif
//Go to sleep now
Serial.println("Going to sleep now");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
//This will never be reached
}
Setting the Threshold
The first thing you need to do is setting a threshold value for the touch pins.
#define THRESHOLD 40 // Greater the value, more the sensitivity
The values read by a touch pin decrease when you touch it. The threshold value means that the ESP32 will wake up when the value read on the touch pin is below 40. You can adjust that value depending on the desired sensitivity.
Important: however, if you’re using an ESP32-S2 or ESP32-S3 model, things work a little
differently. That’s why there’s a different section in the code defining a different threshold for those boards. In this case, the lower the value, the more the sensitivity.
#if CONFIG_IDF_TARGET_ESP32
#define THRESHOLD 40 // Greater the value, more the sensitivity
#else // ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted)
#define THRESHOLD 5000 // Lower the value, more the sensitivity
#endif
Setting Touch Pins as a Wake-up Source
To set a touch pin as a wake-up source, you can use the touchSleepWakeUpEnable() function that accepts as arguments the touch pin and the threshold value that will wake up the board.
In this example, it sets GPIO 15 (T3) and GPIO 27 (T7) as wake-up sources with the same threshold value.
#if CONFIG_IDF_TARGET_ESP32
// Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27)
touchSleepWakeUpEnable(T3, THRESHOLD);
touchSleepWakeUpEnable(T7, THRESHOLD);
If you’re using an ESP32-S2 or S3 model, the example just defines wake-up on GPIO 3 (T3). Note that the touch pin numbering might be different depending on the board model you’re using.
#else // ESP32-S2 + ESP32-S3
// Setup sleep wakeup on Touch Pad 3 (GPIO3)
touchSleepWakeUpEnable(T3, THRESHOLD);
Finally, call the esp_deep_sleep_start() to put the ESP32 in deep sleep mode.
esp_deep_sleep_start();
These were the general instructions to set up touch pins as a wake-up source. Now, let’s take a look at the other sections of the code.
setup()
When the ESP32 wakes up from sleep, it will run the code from the start until it finds the esp_deep_sleep_start() function.
In this particular example, we have a control variable called bootCount that will be increased between each sleep cycle so that we have an idea of how many times the ESP32 woke up.
// Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
We also call the print_wakeup_reason() and print_wakeup_touchpad() functions defined earlier in the code to print the wake-up reason and the pin that caused the wake-up.
// Print the wakeup reason for ESP32 and touchpad too
print_wakeup_reason();
print_wakeup_touchpad();
Wiring the Circuit
To test this example, wire a cable to GPIO 15, as shown in the schematic below.
If you’re using an ESP32-S2 or ESP32-S3 model, please check the location of your touch pins.
Testing the Example
Upload the code to your ESP32, and open the Serial Monitor at a baud rate of 115200.
The ESP32 goes into deep sleep mode.
You can wake it up by touching the wire connected to Touch Pin 3.
When you touch the pin, the ESP32 displays on the Serial Monitor: the boot number, the wake-up cause, and which touch-sensitive GPIO caused the wake-up.
External Wake Up
Besides the timer and the touch pins, we can also awake the ESP32 from deep sleep by toggling the value of a signal on a pin, like the press of a button. This is called an external wake up. You have two possibilities of external wake up: ext0, and ext1.
External Wake Up (ext0)
This wake up source allows you to use a pin to wake up the ESP32.
The ext0 wake up source option uses RTC GPIOs to wake up. So, RTC peripherals will be kept on during deep sleep if this wake up source is requested.
To use this wake up source, you use the following function:
esp_sleep_enable_ext0_wakeup(GPIO_NUM_X, level)
This function accepts as first argument the pin you want to use, in this format GPIO_NUM_X, in which X represents the GPIO number of that pin.
The second argument, level, can be either 1 or 0. This represents the state of the GPIO that will trigger wake up.
Note: with this wake up source, you can only use pins that are RTC GPIOs.
External Wake Up (ext1)
the RTC controller. So, RTC peripherals and RTC memories can be powered off in this mode.
To use this wake-up source, you use the following function:
esp_sleep_enable_ext1_wakeup_io(bitmask, mode);
This function accepts two arguments:
- A bitmask of the GPIO numbers that will cause the wake up;
- Mode: the logic to wake up the ESP32. It can be:
- ESP_EXT1_WAKEUP_ALL_LOW: wake up when all GPIOs go low;
- ESP_EXT1_WAKEUP_ANY_HIGH: wake up if any of the GPIOs go high.
If you’re using an ESP32-S2, ESP32-S3, ESP32-C6 or ESP32-H2, these are the available modes:
- ESP_EXT1_WAKEUP_ANY_LOW: wake up when any of the selected GPIOs is low
- ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high
Note: you can only use pins that are RTC GPIOs.
For all the details about the ext1 deep sleep wake-up source, take a look at the Espressif deep sleep documentation.
y use pins that are RTC GPIOs.
Code
Let’s explore the example that comes with the ESP32 library. Go to File > Examples > ESP32 Deep Sleep > ExternalWakeUp:
/*
Deep Sleep with External Wake Up
=====================================
This code displays how to use deep sleep with
an external trigger as a wake up source and how
to store data in RTC memory to use it over reboots
This code is under Public Domain License.
Hardware Connections
======================
Push Button to GPIO 33 pulled down with a 10K Ohm
resistor
NOTE:
======
Only RTC IO can be used as a source for external wake
source. They are pins: 0,2,4,12-15,25-27,32-39.
Author:
Pranav Cherukupalli <[email protected]>
*/
#include "driver/rtc_io.h"
#define BUTTON_PIN_BITMASK(GPIO) (1ULL << GPIO) // 2 ^ GPIO_NUMBER in hex
#define USE_EXT0_WAKEUP 1 // 1 = EXT0 wakeup, 0 = EXT1 wakeup
#define WAKEUP_GPIO GPIO_NUM_33 // Only RTC IO are allowed - ESP32 Pin example
RTC_DATA_ATTR int bootCount = 0;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break;
default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
}
}
void setup() {
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
/*
First we configure the wake up source
We set our ESP32 to wake up for an external trigger.
There are two types for ESP32, ext0 and ext1 .
ext0 uses RTC_IO to wakeup thus requires RTC peripherals
to be on while ext1 uses RTC Controller so does not need
peripherals to be powered on.
Note that using internal pullups/pulldowns also requires
RTC peripherals to be turned on.
*/
#if USE_EXT0_WAKEUP
esp_sleep_enable_ext0_wakeup(WAKEUP_GPIO, 1); //1 = High, 0 = Low
// Configure pullup/downs via RTCIO to tie wakeup pins to inactive level during deepsleep.
// EXT0 resides in the same power domain (RTC_PERIPH) as the RTC IO pullup/downs.
// No need to keep that power domain explicitly, unlike EXT1.
rtc_gpio_pullup_dis(WAKEUP_GPIO);
rtc_gpio_pulldown_en(WAKEUP_GPIO);
#else // EXT1 WAKEUP
//If you were to use ext1, you would use it like
esp_sleep_enable_ext1_wakeup_io(BUTTON_PIN_BITMASK(WAKEUP_GPIO), ESP_EXT1_WAKEUP_ANY_HIGH);
/*
If there are no external pull-up/downs, tie wakeup pins to inactive level with internal pull-up/downs via RTC IO
during deepsleep. However, RTC IO relies on the RTC_PERIPH power domain. Keeping this power domain on will
increase some power comsumption. However, if we turn off the RTC_PERIPH domain or if certain chips lack the RTC_PERIPH
domain, we will use the HOLD feature to maintain the pull-up and pull-down on the pins during sleep.
*/
rtc_gpio_pulldown_en(WAKEUP_GPIO); // GPIO33 is tie to GND in order to wake up in HIGH
rtc_gpio_pullup_dis(WAKEUP_GPIO); // Disable PULL_UP in order to allow it to wakeup on HIGH
#endif
//Go to sleep now
Serial.println("Going to sleep now");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
//This is not going to be called
}
This example awakes the ESP32 when you trigger GPIO 33 to high. The code example shows how to use both methods: ext0 and ext1. If you upload the code as it is, you’ll use ext0. The function to use ext1 is commented. We’ll show you how both methods work and how to use them.
Let’s take a quick look at the code.
Save Data on RTC Memories
With the ESP32, you can save data on the RTC memories. The ESP32 has 8kB SRAM on the RTC part, called RTC fast memory. The data saved here is not erased during deep sleep. However, it is erased when you press the reset button (the button labeled EN on the ESP32 board).
To save data on the RTC memory, you just have to add RTC_DATA_ATTR before a variable definition. The example saves the bootCount variable on the RTC memory. This variable will count how many times the ESP32 has woken up from deep sleep.
RTC_DATA_ATTR int bootCount = 0;
Wake Up Reason
Then, the code defines the print_wakeup_reason() function, that prints the reason by which the ESP32 has been awakened from sleep.
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break;
default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
}
}
setup()
In the setup(), you start by initializing the serial communication:
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
Then, you increment one to the bootCount variable, and print that variable in the Serial Monitor.
++bootCount;
Serial.println("Boot number: " + String(bootCount));
Next, you print the wake-up reason using the print_wakeup_reason() function defined earlier.
//Print the wakeup reason for ESP32
print_wakeup_reason();
After this, you need to enable the wake-up sources. We’ll test each of the wake-up sources, ext0 and ext1, separately.
ext0
In this example, the ESP32 wakes up when the GPIO 33 is triggered to high:
esp_sleep_enable_ext0_wakeup(WAKEUP_GPIO, 1); // 1 = High, 0 = Low
Instead of GPIO 33, you can use any other RTC GPIO pin. Just define it on the WAKEUP_GPIO variable at the beginning of the code.
#define WAKEUP_GPIO GPIO_NUM_33 // Only RTC IO are allowed
Internal Pull-Up and Pull-Down Resistors
We also call the following two lines:
rtc_gpio_pullup_dis(WAKEUP_GPIO);
rtc_gpio_pulldown_en(WAKEUP_GPIO);
The rtc_gpio_pullup_dis() function disables any internal pull-up resistors on the wake-up GPIO—it ensures that the pin is not unintentionally held high. This is important because a pull-up resistor would keep the pin high, potentially causing unintended wakeups.
The rtc_gpio_pulldown_en() function enables the internal pull-down resistor on the wake-up GPIO—it ensures the pin is held low until a valid wakeup signal (HIGH) is received. By configuring the pin with a pull-down resistor, we guarantee that it remains in a stable low state during deep sleep. This stability ensures that the ESP32 wakes up only when the specified GPIO pin receives an external high signal, matching the wakeup condition set by the esp_sleep_enable_ext0_wakeup(WAKEUP_GPIO, 1).
Wiring the Circuit
To test this example, wire a pushbutton to your ESP32 by following the next schematic diagram. The button is connected to GPIO 33 using a pull down 10K Ohm resistor.
Note: only RTC GPIOs can be used as a wake up source. Instead of GPIO 33, you could also use any RTC GPIO pins to connect your button.
Testing the Example
Let’s test this example. Upload the example code to your ESP32. Make sure you have the right board and COM port selected. Open the Serial Monitor at a baud rate of 115200.
Press the pushbutton to wake up the ESP32.
Try this several times, and see the boot count increasing with each button press.
Using this method is useful to wake up your ESP32 using a pushbutton, for example, to execute a particular task. However, with this method, you can only use one GPIO as a wake-up source.
What if you want to have different buttons, all of them wake up the ESP, but do different tasks? For
ext1
The ext1 wake-up source allows you to wake up the ESP32 using different GPIOs and perform different tasks depending on the GPIO that caused the wake-up.
Instead of using the esp_sleep_enable_ext0_wakeup() function, you use the esp_sleep_enable_ext1_wakeup_io() function.
esp_sleep_enable_ext1_wakeup_io(BUTTON_PIN_BITMASK(WAKEUP_GPIO), ESP_EXT1_WAKEUP_ANY_HIGH);
In this particular example, to run that part of the code, make sure you set the USE_EXT0_WAKEUP variable to 0 at the beginning of the code like so:
#define USE_EXT0_WAKEUP 0 // 1 = EXT0 wakeup, 0 = EXT1 wakeup
The esp_sleep_enable_ext1_wakeup_io() function
The first argument of the esp_sleep_enable_ext1_wakeup_io() function is a bitmask of the GPIOs you’ll use as a wake-up source, and the second argument defines the logic to wake up the ESP32.
GPIOs Bitmask
To define the GPIOs bitmask, we can use the BUTTON_PIN_BITMASK() macro defined at the beginning of the code.
#define BUTTON_PIN_BITMASK(GPIO) (1ULL << GPIO) // 2 ^ GPIO_NUMBER in hex
BUTTON_PIN_BITMASK(GPIO) is a macro that creates a bitmask for a specific GPIO. It is not a function but behaves somewhat similarly by accepting an argument and returning a value.
So, if you want to return the bitmask for a specific GPIO, you just need to call it like so:
BUTTON_PIN_BITMASK(WAKEUP_GPIO)
So, the esp_sleep_enable_ext1_wakeup_io() will look like this:
esp_sleep_enable_ext1_wakeup_io(BUTTON_PIN_BITMASK(WAKEUP_GPIO), ESP_EXT1_WAKEUP_ANY_HIGH);
Bitmask for Multiple GPIOs
To create a bitmask for multiple GPIOs using the BUTTON_PIN_BITMASK(GPIO) macro, you can use bitwise OR (|) to combine the individual bitmasks for each GPIO pin. Here’s how you can do it:
Suppose you want to create a bitmask for GPIO pins 2 and 15. You can do this by combining the individual bitmasks for each pin like this:
uint64_t bitmask = BUTTON_PIN_BITMASK(GPIO_NUM_2) | BUTTON_PIN_BITMASK(GPIO_NUM_15);
We’ll see an example using multiple GPIOs as a wake-up source next.
Wake-Up Mode
The second argument of the esp_sleep_enable_ext1_wakeup_io() function is the wake-up mode. As we’ve seen previously, these are your options:
- ESP_EXT1_WAKEUP_ALL_LOW: wake up when all GPIOs go low;
- ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the GPIOs go high.
If you’re using an ESP32-S2, ESP32-S3, ESP32-C6 or ESP32-H2, these are the available modes:
- ESP_EXT1_WAKEUP_ANY_LOW: wake up when any of the selected GPIOs is low
- ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high
In our particular example, we’re using ESP_EXT1_WAKEUP_ANY_HIGH. So, the ESP32 will wake-up when any of the GPIOs from the bitmask are high.
Like with the ext0, we disable pull-up internal resistors and enable pull-down resistors to ensure stability of the reading of the wake-up GPIO.
External Wake Up – Multiple GPIOs
Now, you should be able to wake up the ESP32 using different buttons, and identify which button caused the wake up. In this example we’ll use GPIO 2 and GPIO 15 as a wake-up source.
Schematic
Wire two buttons to your ESP32. In this example, we’re using GPIO 2 and GPIO 15, but you can connect your buttons to any RTC GPIOs.
Code Multiple GPIOs – External Wake-Up
You need to make some modifications to the example code we’ve used before:
- create a bitmask to use GPIO 15 and GPIO 2. We’ve shown you how to do this before;
- enable ext1 as a wake-up source;
- create a function that identifies the GPIO that caused the wake-up.
The next sketch has all those changes implemented.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/learn-esp32-with-arduino-ide/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include "driver/rtc_io.h"
#define BUTTON_PIN_BITMASK(GPIO) (1ULL << GPIO) // 2 ^ GPIO_NUMBER in hex
#define WAKEUP_GPIO_2 GPIO_NUM_2 // Only RTC IO are allowed - ESP32 Pin example
#define WAKEUP_GPIO_15 GPIO_NUM_15 // Only RTC IO are allowed - ESP32 Pin example
// Define bitmask for multiple GPIOs
uint64_t bitmask = BUTTON_PIN_BITMASK(WAKEUP_GPIO_2) | BUTTON_PIN_BITMASK(WAKEUP_GPIO_15);
RTC_DATA_ATTR int bootCount = 0;
/*
Method to print the GPIO that triggered the wakeup
*/
void print_GPIO_wake_up(){
int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
Serial.print("GPIO that triggered the wake up: GPIO ");
Serial.println((log(GPIO_reason))/log(2), 0);
}
/*
Method to print the reason by which ESP32 has been awaken from sleep
*/
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("Wakeup caused by external signal using RTC_IO");
break;
case ESP_SLEEP_WAKEUP_EXT1:
Serial.println("Wakeup caused by external signal using RTC_CNTL");
print_GPIO_wake_up();
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wakeup caused by timer");
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
Serial.println("Wakeup caused by touchpad");
break;
case ESP_SLEEP_WAKEUP_ULP:
Serial.println("Wakeup caused by ULP program");
break;
default:
Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
break;
}
}
void setup() {
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
//Use ext1 as a wake-up source
esp_sleep_enable_ext1_wakeup_io(bitmask, ESP_EXT1_WAKEUP_ANY_HIGH);
// enable pull-down resistors and disable pull-up resistors
rtc_gpio_pulldown_en(WAKEUP_GPIO_2);
rtc_gpio_pullup_dis(WAKEUP_GPIO_2);
rtc_gpio_pulldown_en(WAKEUP_GPIO_15);
rtc_gpio_pullup_dis(WAKEUP_GPIO_15);
//Go to sleep now
Serial.println("Going to sleep now");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
//This is not going to be called
}
How Does the Code Work?
Let’s take a quick look at how the code works.
GPIOs Bitmask
You define the GPIOs bitmask at the beginning of the code:
#define BUTTON_PIN_BITMASK(GPIO) (1ULL << GPIO) // 2 ^ GPIO_NUMBER in hex
#define WAKEUP_GPIO_2 GPIO_NUM_2 // Only RTC IO are allowed -
#define WAKEUP_GPIO_15 GPIO_NUM_15 // Only RTC IO are allowed
// Define bitmask for multiple GPIOs
uint64_t bitmask = BUTTON_PIN_BITMASK(WAKEUP_GPIO_2) | BUTTON_PIN_BITMASK(WAKEUP_GPIO_15);
Identify the GPIO that Caused the Wake-up
We create a function called print_GPIO_wake_up() that prints the GPIO that caused the wake-up:
void print_GPIO_wake_up(){
int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
Serial.print("GPIO that triggered the wake up: GPIO ");
Serial.println((log(GPIO_reason))/log(2), 0);
}
The esp_sleep_get_ext1_wakeup_status() function returns a bitmask with the GPIO that caused the wake-up. We can get the GPIO number as follows:
log(GPIO_reason))/log(2)
Print the Wake-Up Reason
We modified the print_wakeup_reason() function to print the GPIO that caused the wake-up when the wake-up source is ext1:
case ESP_SLEEP_WAKEUP_EXT1:
Serial.println("Wakeup caused by external signal using RTC_CNTL");
print_GPIO_wake_up();
break;
Enable ext1 as a Wake-Up Source
Enable ext1 as a wake-up source by passing the GPIOs bitmask and wake-up mode.
esp_sleep_enable_ext1_wakeup_io(bitmask, ESP_EXT1_WAKEUP_ANY_HIGH);
Don’t forget to disable any internal pull-up resistors and enable pull-down resistors on the GPIOs used as a wake-up source.
rtc_gpio_pulldown_en(WAKEUP_GPIO_2);
rtc_gpio_pullup_dis(WAKEUP_GPIO_2);
rtc_gpio_pulldown_en(WAKEUP_GPIO_15);
rtc_gpio_pullup_dis(WAKEUP_GPIO_15);
Enable Deep Sleep
Finally, call esp_deep_sleep_start() to put the ESP32 in deep sleep mode.
esp_deep_sleep_start();
Testing the Sketch
After uploading the code to the board, the ESP32 will be in deep sleep mode. You can wake it up by pressing the pushbuttons.
Open the Serial Monitor at a baud rate of 115200. Press the pushbuttons to wake up the ESP32. On the Serial Monitor, you should get the wake-up reason and the GPIO that caused the wake-up.
Wrapping Up
In this article we’ve shown you how to use deep sleep with the ESP32 and different ways to wake it up. You can wake up the ESP32 using a timer, the touch pins, or a change on a GPIO state.
Let’s summarize what you’ve learned about each wake-up source:
- To enable the timer wake-up, you use the esp_sleep_enable_timer_wakeup(time_in_us) function;
- Use the esp_deep_sleep_start() function to start deep sleep.
- To enable the touch pins as a wake-up source use the touchSleepWakeUpEnable() function;
- Finally, you use the esp_deep_sleep_start() function to put the ESP32 in deep sleep mode.
- You can only use RTC GPIOs as an external wake-up;
- You can use two different methods: ext0 and ext1;
- ext0 allows you to wake up the ESP32 using one single GPIO pin;
- ext1 allows you to wake up the ESP32 using several GPIO pins.
We hope you’ve found this guide useful. If you want to learn more about ESP32, make sure you check all our ESP32 projects and our ESP32 eBook.
This is an excerpt from our course: Learn ESP32 with Arduino IDE. If you like ESP32 and you want to learn more, we recommend enrolling in Learn ESP32 with Arduino IDE course.
Great article! Thank you for presenting all sleep possibilities
Can you provide an advice on how to wake up an esp and reactivating the wifi?
Thanks in advance
Regards
Alain
Hi Alain.
Thank you for following our tutorials.
After wake-up, you can activate wifi with:
WiFi.connect()
Regards,
Sara
Sarah, at least on esp32-arduino v1.0.4 (the latest, as of now) there seems to be no WiFi.connect():
esp32_test_wifi_deepsleep.ino:114:10: error: 'class WiFiClass' has no member named 'connect'
WiFi.connect();
^
Hi.
Did you select an ESP32 board when uploading the code?
Regards,
Sara
Hi sara
thank you for sharing this wonderful tutorial.
But, now i have a small question, currently i am working on Zigbee project, ESP32-s3 connected to Zigbee module through UART communication ( RX and TX pins).
I set my ESP32-s3 as deep-sleep mode, i want to wake my esp32 from deep sleep through UART communications,
if i received any data through from UART, i want to wake up ESP32-s3 from deep sleep mode,
And also in deep sleep mode i want turn on RTC timer and RTC memory , how to turn off ULP co-processor and ULP sensor -monitored pattern.
actually i tried, but its not working
#include <esp_sleep.h>
#include <driver/uart.h>
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <HardwareSerial.h>
#include <ArduinoJson.h>
#define RX_PIN 18 //Zigbee Uart Pins
#define TX_PIN 17
#define I2C_SDA 15
#define I2C_SCL 4
TwoWire I2CBME = TwoWire(0);
Adafruit_BME280 bme;
void setup() {
Serial.begin(115200);
Serial1.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN);
// Initialize pins
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
delay(2000);
Serial.println(F(“BME280 test”));
I2CBME.begin(I2C_SDA, I2C_SCL, 100000);
bool status;
status = bme.begin(0x77, &I2CBME);
if (!status) {
Serial.println(“Could not find a valid BME280 sensor, check wiring!”);
while (1);
}
Serial.println(“– BME280 sensor found –“);
Serial.println();
// Create FreeRTOS tasks
xTaskCreatePinnedToCore(ZIGBEE_COMMANDS, “Task1”, 30000, NULL, 9, NULL, 0);
xTaskCreatePinnedToCore(printValues, “Task2”, 10000, NULL, 7, NULL, 0);
xTaskCreatePinnedToCore(WifiMode, “Task3”, 10000, NULL, 7, NULL, 0);
int wake_thresh = 3;
// uart_set_wakeup_threshold(UART_NUM_1, wake_thresh); // TO AVOID unecessary noice recived from uart ,
// Configure wake-up sources
esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0); // this format GPIO_NUM_X, in which X represents the GPIO number of that pin 1 = High, 0 = Low
esp_sleep_enable_timer_wakeup(20 * uS_TO_S_FACTOR);
esp_sleep_enable_uart_wakeup(UART_NUM_1); // UART (Serial1)
// Determine the wake-up reason
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
// Handle different wake-up causes
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println(“TIMER: Woke up from deep sleep.”);
//digitalWrite(RED_LED, LOW);
handleDeepSleepWakeUp();
pinMode(RED_LED, INPUT);
Serial1.flush();
break;
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("BUTTON: Woke up from deep sleep.");
digitalWrite(GREEN_LED, HIGH);
ButtonWakeUp();
Serial1.flush();
break;
case ESP_SLEEP_WAKEUP_UART:
Serial.println("UART: Woke up from deep sleep.");
digitalWrite(BLUE_LED, HIGH);
Serial1.flush();
UARTWakeUp();
break;
default:
Serial.println("wakeup_reason ");
Serial.println(wakeup_reason);
break;
}
Serial.println(“Set up: going to light sleep.”);
esp_deep_sleep_start();
}
void UARTWakeUp() {
readResponseFromZigbee();
delay(1000); // Delay for stability before going back to sleep
esp_deep_sleep_start();
//esp_light_sleep_start();
}
void loop() {
}
Excellent insight into the device. I tested the device for Touch Wakeup, and sleep – worked straight off . Good article.
Thanks 🙂
I am using the Heltec esp32 board, I do not see RTC pins listed on the pinout. Is there a different naming convention for this board?
Hi Andrew.
I think the RTC GPIOs should be the same of other ESP32 boards.
For example, GPIO 25 is RTC_GPIO6. See the GPIO reference guide: https://i1.wp.com/randomnerdtutorials.com/wp-content/uploads/2018/08/ESP32-DOIT-DEVKIT-V1-Board-Pinout-36-GPIOs-updated.jpg
Regards,
Sara
I think you can take help from documentation
Hi! Thanks for sharing, it is a very good compilation for the different available interrupt sources.
Thought, there’s also another very interesting and useful way of waking up our ESP32, and it’s on receiving serial data. Serial interrupt seems to be working only on light sleep, according to the API doc for the ESP32, but… what if we wanted to wake it up from deep sleep?
A solution I came up, which works for both deep and light sleeps, is:
0) First of all, the Rx serial pin is not an RTC pin (none of the other serials, either!) so, attaching directly to it an interrupt won’t work…
1) so, wire up (directly) from SERIAL_RX_PIN (=GPIO_NUM_3) to any free RTC GPIO, for example, GPIO_27.
2) We cannot do “esp_sleep_enable_ext1_wakeup(MULTIPLE_INT_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);” because SERIAL_RX_PIN pin is always HIGH when idle (and its signal is passed to our GPIO_27 because wired), so it will awake the ESP32 continuously.
3) We cannot use “esp_sleep_enable_ext1_wakeup(MULTIPLE_INT_BITMASK, ESP_EXT1_WAKEUP_ALL_LOW);” because we will probably want to awake the ESP32 from different independent sources, and not when having ALL of them LOW.
4) Solution: we can do “esp_sleep_enable_ext0_wakeup(GPIO_NUM_27, LOW);” and also having it combined with “esp_sleep_enable_ext1_wakeup(MULTIPLE_INT_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);” in case we have also other interrupt sources.
This will awake our ESP32 from deep_sleep on receiving any serial input.
5) Careful:
* Only RTC IO can be used as a source for external wake source: they are pins: 0,2,4,12-15,25-27,32-39
* ext0 uses RTC_IO to wake up thus requires RTC peripherals; to be on while ext1 uses RTC Controller so doesn’t need peripherals to be powered on.
* Note that using internal pullups/pulldowns also requires RTC peripherals to be turned on: this makes “esp_sleep_enable_touchpad_wakeup()” to NOT work! (docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/sleep_modes.html#_CPPv332esp_sleep_enable_touchpad_wakeupv), throwing an exception: “E (151) sleep: Conflicting wake-up trigger: ext0”
* So, if there are to use capacitive-pin interrupts in addtion to ext0 or ext1 interrupts, don’t use this. Instead, put all interrupts as ext1 masked.
* If we need to use touch_interrupts, ext0 must NOT to be used.
* We can NOT use instead ext1 again, defining a second macro ONLY for our copied RTC pin for SERIAL_RX_PIN, like: “esp_sleep_enable_ext1_wakeup(SERIAL_INT_BITMASK, ESP_EXT1_WAKEUP_ALL_LOW);”, because further definitions of ext1 will overwrite prior ones… same applies to ext0.
Hope this helps!
Thanks a lot for the explanations here.
I wonder if it would be feasible to use ext0 and ext1 at the same time and if for two pins used by ext1 the one could activate the ESP32 by a rising signal whereas the other would trigger the ESP on a falling signal?
Best regards
Hi.
I’ve never tried using ext0 and ext1 at the same time, so I don’t know if it will work or not.
You can learn more about ext0 and ext1 here: docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/sleep_modes.html#external-wakeup-ext0
Regards,
Sara
Dear Sara,
Thanks a lot for your information.
I checked the documentation and decided to make a little modification to my existing hardware so the reed relais is triggered the same way for both of the impulses.
But I’m still a bit stuck as now I have a fully working counting for the ext0 GPIO wake up but of course my timer is re-set by each of the GPIo wake ups (rain=ext0 impulse => timer re-set that usually broadcasts the data every 30minutes).
For a workaround that’s okay for a limited time. Let’s see if I manage to do the ULP coding by myself or if one nice guy or girl already had solved ‘my’ issue.
Regards
Thanks for sharing! This was also very helpful!
You’re welcome.
Regards,
Sara
Hi Sara!
Thank you so much for this tutorial!
It is extremely helpful.
I was wondering how can you define how long the board would stay awake on the timer-wake up example ?
And which part of the code would you consider to be After wake-up ?
Thank you in advance for your time and help,
Victoria
Hi Victoria.
When the ESP32 wakes up, it runs the whole code from the beginning.
It will came back to sleep once it reaches the line of code with the esp_deep_sleep_start(); function.
So, it will stay awake until running the esp_deep_sleep_start() function.
All your code should be placed before that function.
I hope this answers you question.
Thank you for your interest in our projects.
Regards,
Sara
Dear Sara,
Great article!
Unfortunateley the article did not cover the wake up source nr 4: the ULP co-processor.
We are very interested in this, searching the random nerd tutorials did not result in a hit.
Did you publish how to do this?
We are looking for clues how to wake the CPU from deep sleep by a change in weight on a load cell observed by the ULP. Once the CPU is woken it needs to advertise the new value by BLE.
The setup consists of ESP32Wroom, loadsensor (strain gauges), HX711 and LiPO battery.
Hope you have good news for us!
Best John
Hi Jonh.
Unfortunately, we don’t have any articles covering that subject.
Regards,
Sara
Thank you very much Sara, your article has helped me a lot.
A greeting.
Thanks for reading! I’m glad you found it helpful!
Regards,
Rui
Will this work on the ESP8266?
No.
You can find the ESP8266 deep sleep tutorial here: https://randomnerdtutorials.com/esp8266-deep-sleep-with-arduino-ide/
Regards,
Sara
Hi i am trying to wake up the esp32 by setting gpio 25 high and waking up by connecting to gpio 26 as the wakeup source. I have tried to say rtc_gpio_pullup_en(25); but get the error :
ExternalWakeUp:79:25: error: ‘rtc_gpio_pullup_en’ was not declared in this scope
rtc_gpio_pullup_en(25);
Do i have to invoke a particular library to get this to work do you have any insight into why it throws this error. Google does not seem to have many answers.
Hi.
Please read this discussion and see if it works for you. stackoverflow.com/questions/53324715/esp32-external-pin-wakeup-with-internal-pullup-resistor
Did you include this in your sketch?
#include “driver/rtc_io.h”
P.S. I haven’t tried this, so I’m not sure if this works.
Regards,
Sara
hi, do you know how long it takes for the ESP32 to enter deep sleep state once the command is given? i need to get one single sensor data every 2 seconds and go to sleep — very little power should be used — and then send the data once every 2 hours. i can’t use the ESP8266 because it takes 2 seconds to enter the deep sleep state once the command is given, so, effectively, my devices never sleeps :-D. wondering if the ESP32 is a better candidate. also, if all peripherals are disabled, how much current does it draw at boot? the ESP8266 is a power hog at bootup. thanks!
Hi Mahesh.
Unfortunately, I don’t have data to answer your questions.
If anyone here has done some tests about this subject, please share with us.
Regards,
Sara
Nice post!
Thanks 😀
i am a bit confused..esp32 has its own RTC that keep time even in sleep?
or i need to use an external RTC (like this https://www.aliexpress.com/item/2037934408.html?spm=a2g0o.productlist.0.0.137b6babA9KdKO&algo_pvid=a9be9184-f611-41ca-be3c-89b38353ae8b&algo_expid=a9be9184-f611-41ca-be3c-89b38353ae8b-0&btsid=7617fa26-ea84-4764-ac05-0b17b93bd630&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_52) and wake up with external sources?
Hello Sara
I have very little experience with sketching and thereby programming them. I have a very simple question that you could help me with. I have a Weather Station which takes its data from Open Weather Map via WiFi and is powered by ESP32 board and an OLED display which runs on battery operation.
To save power, I’d like Weather Station to start (Wake UP) at 0800 (08 AM), and switch off (Deep Sleep) at 2300 (11 PM). ESP32 should be in Deep Sleep for 9 hours. It must do this every day. I have seen many places explaining how to apply the Deep Sleep sketch contained in Examples under ESP32, but they only deal with changes within seconds.
• How do I insert into the Deep Sleep sketch the times mentioned above?
• Where do I put the revised (with times) Deep Sleep sketch into the Weather Station sketch. Does it have to put in front of the Weather Station sketch, or at the back?
I hope you can help me with this.
Yours sincerely
Georg Berthelsen
Hi Georg.
You should always write the lines to put the ESP32 in deep sleep after all the other commands. Otherwise, the ESP32 will go into deep sleep after going through the other lines of code.
You can set your ESP32 to sleep during 9 hours using a timer wake-up.
To determine whether your ESP32 should go into deep sleep or not, you can request the time from the internet. Check whether it is later than 11 PM, if it is, put the ESP32 in deep sleep for 9 hours.
To request the time from the internet with the ESP32, we have this tutorial that might help: https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/
I hope this helps.
Regards,
Sara
Hello Sara
Thank you for your response, with a suggestion for a timer from the internet with the ESP32. I’ve seen this tutorial through: https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/. As I wrote earlier, I have little knowledge of sketches, so I can only see, that it is a sketch that provides the correct time of day. I don’t see where to put the time to start (Wake UP) at 0800 (08 AM), and turn off (Deep Sleep) at 2300 (11 PM), thereby putting ESP32 into Deep Sleep for 9 hours each day.
Where in the sketch do I need to insert these times?
Yours sincerely
Georg
Hi, and what about the currents in the different sleep modes?
The results match with the datasheet or they are different?
Thanks!
Wim
Hi Wim.
The power consumption usually doesn’t match the datasheet because using an ESP32 development board like the one we’re using here (instead of a single chip) results in a higher power consumption when compared with the datasheet.
Regards,
Sara
Hi Sara,
I know that is why I hope you could offer a tutorial how to reach the 5uA deep sleep current because everybody is struggling with that.
It seems a struggle to get those low currents but becomes increasingly important with the IoT battery powered devices.
So please give my regards to Ruiz and maybe suggest to check the real currents and how to reach the 5uA?
As far as I understand it is more complicated then disconnect LED’s etc…
thx,
Wim
Hi Wim.
Yes, that’s definitely a challenge.
To reach those lower consumption values, you need to design your own board with the ESP32 chip so that you have only the essential. That’s something that we really want to build and test. But we still don’t know when we’ll do it.
We have this tutorial to save power, that might be useful in some applications: https://randomnerdtutorials.com/power-saving-latching-circuit/
Thanks for reaching out.
Regards,
Sara
Sara
I am trying to put a Lilygo ESP32 SIM800L in deep sleep mode, and send a message (SMS) whenever something happens (external trigger).
I have to admit I have little programming skills. I tried to understand the codes.
I have adjusted the code in a previous article, and the Lilygo ESP32 is sending a message when two buttons are connected. So far so good.
But I don’t know where I should insert or integrate the code of ‘external wakeup’, or which parts, in the code written here https://randomnerdtutorials.com/esp32-sim800l-send-text-messages-sms/
It is for a scientific project.
I hope you can help.
Regards
Diederik D’Hert
Hi.
When we’re doing something with deep sleep. Your code will just run once and then it will go to sleep.
So, all your code should go to the setup().
In the end of the setup(), you just need to add the lines to active external wake-up with buttons and the command to go to sleep:
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low //change this accordingly to the GPIOs you’re using to create the wake-up.
delay(1000);
esp_deep_sleep_start();
And that’s it.
I hope this helps.
Regards,
Sara
I think it not necessary to put deep sleep command only at end of setup() section. It can also put it in loop() section for example after IF statement. Then it can to loop script many times before enter deep sleep, if you understand me.
Btw your blog open over my focus of microcontrollers and many thanks for your work.
Richard
Hello,
I have a very important decision to take based in the wake up from deep sleep.
If ESP32, or ESP8266 can wake up from deep slep based on RX pin status, then i use ESP. If not i have to use a regular transceiver.
What is all about. I have an RFID reader connected to an NodeMcu – ESP8266 RX pin.
When i read a card, i send the numbers of the card to a second ESP.
I must use Deep sleep for ESP board as it is powered by batteries. I must wake up the ESP only when i do a read with the RFID reader, and this transmit the ID of the card to ESP RX pin.
Between that, full deep sleep. I do not need RTC, no Wifi, no nothing. Just the ESP sleeping.
Please help me on this.
Thank you
Hi Ion.
The ESP32 can only woke up from deep sleep using RTC pins.
The UART pins don’t have RTC properties.
So, these are not able to wake up the ESP32.
However, if you use light sleep, you can use any GPIO, but it won’t save as much energy.
Regards,
Sara
Thank you Sara
Connect RX pin with RTC GPIO pin and I think it be work.
Richard
Hi. Did you find a solution to this problem? I have to do the exact same thing for a project
Connect RX pin with RTC GPIO pin and I think it be work.
Richard
First of all, thank you Rui and Sara for putting together this website, very helpful.
I would like to add a small contribution. In my deep sleep project powered by battery, for some reason, when the battery was about half way depleted, RTC_DATA_ATTR was not keeping the stored data, and at the beginning of the next cycle the variables were being reinitialized with the values declared on the sketch, as if the ESP32 was starting from a reset or initial power up instead from deep sleep.
I was able to fix the undesired behavior by declaring the variables with RTC_NOINIT_ATTR attribute instead. I just thought it was good mentioning this solution so others that may be facing the same problem can find a lead.
Thank you, and keep on with the good work.
Hi Rodrigo.
Thank you so much for your contribution.
This will definitely useful for other readers.
Regards,
Sara
Hi Sara
I was wondering why all the examples call esp_deep_sleep_start from the setup and if this a requirement or can it be called from the main loop after the device has detected no user input?
I have an bluetooth ESP32 project where BLE enabled device will be used for an arbitrary period of time then go into deep sleep when it does not receive input for 2 mins, so I assume you would just call esp_deep_sleep_start() within the scope of the loop method when in the inactive state?
Thank you
Hi.
Usually, we call deep_sleep_start from the setup(), because the code will only run once and then it will go into deep sleep.
However, it depends on the project application.
And in your case, it seems that you have to call it in the loop(). You can do that without any problem.
Regards,
Sara
Hi,
In the Reid case is it possible to wake up the ESP32 via BLE?
Thanks
BR
José
hi sara
can i request the esp32 library link?
library that you use
Hi.
We don’t use any library.
All functions are included by default when you install the ESP32 board in your Arduino IDE.
For more information about the deep sleep functions, read: https://gitdemo.readthedocs.io/en/latest/api/system/deep_sleep.html
Regards.
Sara
Hi, love your website and the book I bought a few months back (just getting into it now).
Can you use ext1 and awaken from Deep Sleep upon GPIO CHANGE rather than ‘High’? As I am using two mercury switches one or the other is always turned on.
I am almost a complete novice to this before: I’ve never built a project on ESP32!
Thanks in advance,
Chris
Hi.
The only options for ext 1 are:
– Wake up the ESP32 if any of the pins you’ve selected are high;
– Wake up the ESP32 if all the pins you’ve selected are low.
Alternatively, you can try using the touch pins. See how they behave when there’s a signal and when there isn’t, and program the wake-up accordingly.
If you are one of our costumers, I recommend that you post your questions in the RNTLAB forum: https://rntlab.com/forum/
We check all the questions on the forum, but many times, we can’t answer all the comments here on the website.
Regards,
Sara
Great – thank you :). I always appreciate your expertise!
I didn’t know there was a forum so I’ll check it out now.
I’ve also not experimented with the touch pins yet – I might try this first.
Ok.
Any help that you need, please ask on the forum.
Regards,
Sara
Or you can negate your input pin with IC (7400 etc…) or transistor and resistor.
Richard
hi all,
I want my esp to sleep for 7 hours. this is a very long microSecond number.
“TIME_TO_SLEEP * uS_TO_S_FACTOR” (600*1000.000) for 10 minutes works fine.
but if I multiply this by 42 (to get 7 hours) problems start for me and deepsleep wont work.
so does anyone know how to store a number as big as 25.200.000.000?
or an other way to get 7 hours of deepsleep?
In C language you use 25200000000ULL constans. ULL mean Unsigned Long Long (64-bit value), up to 2^64-1.
Or put two loops inside one in other like in assembler.
Richard
I would like to put my esp32 into deep sleep with a timer. Currently esp 32 exposes an api which is called every 20 minutes. I would like to put him to sleep for 19 minutes, allow the bee to respond and then put him back to sleep. I’ve seen your example but it doesn’t use the loop method. In my loop method there is the server.handleClient () statement; and with the sleep timer it is never called. how can i solve? Thanks to those who will answer
You can put deep sleep command in loop() for example after IF statement.
Richard
When I add some code to the callback function in the touchWakeup sketch, like
void callback(){
digitalWrite(ledPin, HIGH); // turn the LED on (HIGH is the voltage level)
}
and ledPin = 2, I couldn’t see the blue LED on, even when I hold the pin15 for a while.
What did I do wrong?
Thanks
Hi Sara, Rui,
I have been trying out your code above, it is super helpful, and noticed the GPIO_reason was not working, not returning the GPIO pin number: “int GPIO_reason = esp_sleep_get_ext1_wakeup_status();”.
I referred to manual [https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/sleep_modes.html#_CPPv432esp_sleep_get_ext1_wakeup_statusv] and it says this:
“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.
Return
bit mask, if GPIOn caused wakeup, BIT(n) will be set”.
A minor change to above code fixed the issue, changing “int” to “uint64_t” to give: “uint64_t GPIO_reason = esp_sleep_get_ext1_wakeup_status();”
I’m not sure what the “_t” is for, other languages just write “uint64” so why different for this?
Cheers,
Alex Padgett
Hey Sara and Rui,
I was wondering if it is possible to call two different wakeup-timers in one sketch?
For example a regular 10 minutes deepsleep and a second one as “power-save-mode” for about a day or so in case of low battery.
So ESP32 should check after one day if battery has enough voltage again – if not return to power-save-mode again.
I defined two sleep timers (sleep_time = 600sec and power_save = 86400sec) but do not know how to tell the esp_deep_sleep_start(); when to use which of the two esp_sleep_enable_timer_wakeup(……..)
Or is there a way to use one of the other other wakeup reasons for that?
Thank you in advance,
Nico
Problem solved!
Three deepsleep timers for different situations.
– a short deepsleep timer if >= 5.0v is measured at the Vin powered by a solar panel
– a longer deepsleep timer if ESP runs only on battery
– and a long hibernation mode if battery is low (<= 3.0v)
Works perfect.
Just tried your examples from above.
Thank you RNT
Hi Nico!, how did you set up the hibernation mode?. Could the sistem wakes up later using that mode?. Regards!
In hibernation mode only an external source can wake up the ESP32 (as far as I know)
Hello Sarah, thanks for your very intsesting and well explained experiments
I have just a question: For power tests, do you know how to turn off the power led of the ESP devkit V1 – doit ?
Hello Sarah,
Thanks for the tutorial. Could you tell me if there is a way to have the ESP32 in Deep Sleep for a time say 2 hours and wake to send data by WiFi and back to sleep and at the same time watch for an interrupt if a door is opened.
In other words can you combine deep sleep timer and interrupt by switch? Thanks
Hello Sarah,
Good Article..!
I want to know if we can use Hall sensor to bring the ESP32 out of Deep Sleep?
It would be great help if you can provide update on this.
Thanks
Sameer
Hi,
I tried this tutorial with touch sensor to wake up my esp32 when I want to receive the data through Bluetooth, but callback function doesn’t work
void callback(){
//placeholder callback function
init_sensors(); //function which initialise sensors
float t = dht.readTemperature();
float h = dht.readHumidity();
float p = bmp.readPressure();
char tStr[10];
char hStr[10];
char pStr[10];
sprintf(tStr, "%4.4f", t);
sprintf(hStr, "%4.4f", h);
sprintf(pStr, "%4.4f", p);
temp_pCharacteristic->setValue(tStr);
temp_pCharacteristic->notify();
hum_pCharacteristic->setValue(hStr);
hum_pCharacteristic->notify();
pres_pCharacteristic->setValue(pStr);
pres_pCharacteristic->notify();
}
I have a empty value in nRF Connect.
Can you help me with this?
Hello everybody, can the esp32 cam get into deep sleep mode too?
I am following another tutorial for the esp32 cam pinout and I don’t see any reference for RTC pins that makes me wonder if this function is allowed on esp32 cam or if this is something specific to the esp32 ???
Thanks
Hi.
Yes, the ESP32-CAM can go into deep sleep too.
Regards,
Sara
Thank you for this good and clear article.
To push me in the right direction:
Would it be possible to wake up an ESP32 with an MPU-6050 Accel/Gyro of the analog ADXL335 with the movement of a pushbike?
So, when the bike is idle for x minutes go to sleep. with movement wake up.
Stay safe,
Hi.
I’m not sure.
Probably you can use the sensor’s INT (interrupt pin) for that. You have to try it.
Regards,
Sara
Thank you for your reply,
I had completely overlooked the int pin on the MPU-6050! That would indeed be the way to go.
Greeting,
Eric
Great tutorial!
I am using a 433Mhz transmitter, ssd1306 OLED screen and the esp32. Both the 433 and 1306 are connected to the 5V pin on the esp32. When the esp32 goes to sleep, is there still power to the 5V pin? I hope not.
Thanks,
Joe
It is power, as 5 volts pin for ESP32 it is an input pin connected to the 3.3 volts regulator.
This is not a function pin, so the ESP does not have control..
As long as you put power on it from somewhere, it will always be power.
Thanks for your response. Issue closed.
Hi.
The best way to be sure is to check with a multimeter.
Regards,
Sara
I think it be good to connect 5V for display and others pheriperials with a GPIO output pin to switch transistor connected to ESP32 and call this command after wakeup ESP. Then before deep sleep command put GPIO output of switch transistor to off command. This is for ESP development PCB version.
Richard
Hi,
I use #include <ESP32Time.h> to keep track of date/time.
My Esp32 goes to deep sleep and can wake up from:
-> esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
or
-> esp_sleep_enable_ext0_wakeup(GPIO_NUM_34, 0);
In the first case, before going to sleep I get Epoch time, than after time_to_sleep, I add that amount to epoch time, and it works.
What I do not know how to do is the following: if esp32 is waken up from external pin, how can I know how much time has elapsed? In this case, it is not a fixed amount of time.
Thanks!
Put before deep sleep actual time to RTC_DATA_ATTR non erase memory and after wake up compare it with actual time and count it. Actual time get it from NTP server for example.
Richard
Hi,
is there any way to wake up in the same place where it went to sleep (I mean in the loop ()), so it doesn’t need to restart esp and run setup() again? I’m working with scales, and it tare in setup, so after restart it won’t show any weitgth on it.
Hi.
When the ESP32 wakes up from deep sleep, it will always run the code from the start because it resets.
If you need to store permanent data that persists across resets you can use EEPROM, the Preferences library, or SPIFFS.
See our tutorials:
– https://randomnerdtutorials.com/esp32-flash-memory/
– https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
– https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/
Alternatively, you can use light sleep mode, which resumes the code where it has left it.
See this tutorial by one of our followers: https://m1cr0lab-esp32.github.io/sleep-modes/light-sleep-mode/
I hope this helps.
Regards,
Sara
thanks for fast answer, I’ll try to follow you advice.
Sara, it not to put his data to RTC_DATA_ATTR variable before deep sleep and in setup put IF statement to initialization scale variable with other RTC_DATA_ATTR variable of first boot like this?
RTC_DATA_ATTR int bootCount = 0;
setup() {
++bootCount;
IF bootCount = 1 {
Initialization scale variable ……
}
….
….
….
RTC_DATA_ATTR int scale_variables = xyz; //to use it in next wakeup
esp_deep_sleep_start();
}
void loop(){
//or the code above in setup can be here
….
….
….
IF something = something other {
RTC_DATA_ATTR int scale_variables = xyz; //to use it in next wakeup
esp_deep_sleep_start();
}
}
Richard
Hi! I love all your articles! I find them extremely useful, but now I’m having a problem. I’m working on a project using a AI Thinker ESP32-CAM. Since it is powered with batteries, I execute the routine and then put the ESP in deep sleep mode for a while. As I need to know when the code is executed, I use the RTC module DS3231 and also use it to wake up my ESP with the alarms feature the DS3231 has. My code uses HardwareSerial and the camera and it works perfectly. However, I tried to implement a timed deep sleep, so the ESP will wake up and execute even if the RTC fails (it is not ideal, but the device will work in very rough climate conditions, so it is possible it would fail). So, here comes the problem, when I implement the timed deep sleep, my Serial port stopped working. It doesn’t receive anything (it’s a read only device). I’m using the Serial2 port (IO16 in the board) Any ideas why this may be happening? (Sorry for bad english, not a native speaker)
Hi.
I’m not sure what the problem might be.
But it might be related to the fact that GPIO 16 is connected internally to PSRAM.
I don’t know how that issue could be solved.
Maybe you can try using other pins for Hardware serial and see if the problem goes away.
This video clearly explains how to use other serial pins: https://youtu.be/GwShqW39jlE
Regards,
Sara
Thanks Sara for your fast reply! Yes, maybe PSRAM is the problem… Is there a way to disable PSRAM by Software? I mean, not desoldering it, just deinitialize the PSRAM so I can use the Serial port normally? I can’t change the pin assignment because all the other pins already have something connected.
Hi.
I’m not sure how to do that.
But, if you have something as follows in your code:
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
Remove it. And simply use the following instead:
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
I’m not sure if this does any difference … But it’s easy to try.
Regards,
Sara
Hi Sara,
Your prompt effort to help on this forum is tremendous – thank you. Please I have tried the example for this deep sleep, because I have a project that uses esp32 and temp and moisture sensors, and after implementing the sleep code, the consumption of the battery before and after is still the same. If I may have your email so I can email you the code file please for fix. Thank you in advance.
Hi.
Do you think the problem is software-related?
Regards,
Sara
hi,
I’m using the “esp32 devkit v1 DOIT” card in deep sleep mode. My card consumes 10 mA but according to the data sheet it must consume some micro-amperes
Hi.
It will only consume micro-amperes if you’re using the bare chip.
With the full-featured development board, it will consume more.
Regards,
Sara
You’re right. Thank you very much
I have 2 minor questions here.
The first is that the serial monitor isn’t working it’s set at 115200 baud rate which is correct under the setup but nothing shows up it’s under the right com port which shows up in my case as COM3. What can I do to make something pop up?
My second question is how do you tell that your esp32 is successfully in deep sleep mode? Does the red led on the board still constantly lit up?
Thanks for your time
Hi Joseph.
Press the ESP32 on-board RST button with the serial monitor opened.
You can tell it is in deep sleep mode if you measure power consumption.
Regards,
Sara
Hi,
I want to wake my ESP 32 using three GPIOs. They are active low. I want esp to wake up when any of pins go LOW means What i want is ANY_LOW mode but its not available and i don’t want to go for hardware changes. Any suggestions?
Use transistors to negate your signals.
Richard
Hi,
I’m using an ESP32-C3 on a DevKitM-1, rumour has it this chip is able to maintain BLE connection during light sleep. Do you know how to establish this through the API? There doesn’t seem to be a call to enable BT as a wakeup source.
Hello, I am using esp32 cam and power module 1A/5v, all of which are packed in a case (I made a video doorbell with a visitor button), I found that the case is very hot after not using it for a long time. When there is no visitor, I want to use the esp32 cam, deep sleep (power saving), until the visitor presses the doorbell, the esp32 cam will be restarted, this is the code I am looking for, thank you
Hi.
I’m sorry, but we don’t create custom code for our readers.
Regards,
Sara
I will understand, but first thank you for providing the deep sleep code, I will add the important sleep code to the esp32 cam in the shell of the video visitor doorbell, after finishing, so that the temperature of the power module will not be very hot, the shell The temperature is normal.
I will understand, but first thank you for providing the deep sleep code, I will add the important sleep code to the esp32 cam in the shell of the video visitor doorbell, after finishing, so that the temperature of the power module will not be very hot, the shell The temperature is normal.
Hi Sara, these are great articles thank you.
I hope you are able to clarify a question about keeping ULP powered down.
I want to keep the ESP32 in deep sleep and use external wake up (ext1) triggered by an accelerometer.
Can this be achieved with only the RTC Controller running and therefore keep power consumption to 10uA.
If I have understood your articles and the ESP documentation, I believe that should be the case as the ULP is a RTC Peripheral and therefore can be shut down prior to entering deep sleep.
Kind regards
Simon
Hi, thanks for the post.
I have a question:
What happens if an ext0 pin receives a signal to wake up Esp32, but Esp32 is already awake, for some reason (a timer wake-up for example)? Will they stop everything and do the task for the ext0 event?
Many thanks by the way
Hi.
To be honest I’m not sure what happens.
I would say it would be ignored, but I’m not sure.
I recommend you test it youself to be sure.
Regards,
Sara
The ext0 pin just gets ignored if device is already awake. My concern was with power consumption while awake. The ESP32-PICO consumes 36mA at 80MHz. The ESP32-C3-MINI supposedly consumes 15mA at 80MHz. I’ll will test that in a few weeks.
Hi
Examples of deep sleep included timer, external, and touch, which worked very well with ESP32 S2 on ESP32-S3 had problems with the Touchwakeup example. Even if you don’t touch it, it wakes up as soon as you enter the deep sleep. Is there anyone else who has a problem like me?
Hi,
I am using the ESP32 with BLE.
Project is working fine.
Now, since the project is battery powered, I want to use light sleep.
However, once the module is waking up (timer based), BLE stays disconnected.
Any advise on how to restart BLE after a light (or deep) sleep ? Or anyway restart advertising ?
By the way, thanks for this interesting website !
Guy
Hi Sara,
Thanks a lot for your great tutorials that helped me much !
Is it possible to combine in the same sketch a Timer and an ext0 deep sleep modes ?
I’m studying a device which I need to wake-up locally with a push button to display a value on an OLED display and also automaticaly every 3 hours by sending its measure via LoRa.
Thanks!
I didn’t have the chance to get a reply so I asked my question to chatGPT. Here is the answer I got:
“Yes, it is possible to combine the two deep sleep modes (timed and ext0) in the same ESP32 code. You can use the
esp_sleep_enable_timer_wakeup
andesp_sleep_enable_ext0_wakeup
functions to enable these two wakeup modes.When the ESP32 is in deep sleep, it can be woken up either by the timer or by the input pin signal, depending on the first trigger event. After being woken up, the ESP32 resumes its normal execution.”
I did a test and can confirm that it works as expected !
Unfortunately, I must come back on my previous comment. I’m using an ESP32-WROOM-32D with a RFM95 868MHz LoRa module and set the timer to 10 seconds in combination with an Ext0 function. I noticed that the ESP hangs after a certain amount of reboots that can vary from 20 to more than 600. This never happens if my code only uses a Timer deep sleep. I don’t know what is wrong but this is not acceptable for my project that requires a better reliability.
I saw a tip that was given in another article that suggests to add a yield(); command to avoid that the ESP hangs. I don’t understand how this command acts and didn’t find any tutorial about this.
If that could be a solution to avoid that the ESP hangs, can someone explain me how to use it in that case ?
Thanks!
Hi.
What do you mean when you say the ESP32 hangs?
What happens exactly? Do you get any information on the Serial monitor or debugging window?
Regards,
Sara
Hi Sara,
The ESP32 hangs after the message “Going to deep sleep” on the serial monitor, but in fact it doesn’t go to deep sleep. I can confirm that because I put a command that switches off my OLED display before the ESP goes to deep sleep. But neither the OLED switches off nor the LoRa module continues to send messages. It hangs in that state.
Can you share the relevant parts of your code?
Otherwise, it’s very difficult to find out what might be wrong.
Regards,
Sara
Hi Sara,
is it OK to put : esp_deep_sleep_start(); and
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1);
into loop() instead of setup()?
If I like to stream ESP32CAM which need repeated data transfer, how to set deep sleep after 10 seconds stream please?
Thanks
Summer
Cómo se puede producir una exitacion externa sin tener que usar botones es decir por software
Hi,
Thanks for this tutorial. It has been a great help, I have related code running on ESP32-S boards with no problem.
However, on trying to switch to ESP32-S2 boards (Lolin/ Wemos S2 mini), the same code does not work. Waking from deep sleep using the timer works, but the EXT1 no longer does.
It seems possible that there are (platformIO) menuconfig settings that are unavailable via the Arduino framework.
If anyone knows a way through it would be appreciated. Otherwise please take this as a bit of a warning(!).
Hi.
What exactly happens when you try to use EXT1?
Regards,
Sara
Hi Sara,
When I try using EXT1 wake mechanism from deep sleep: the sensor (button or PIR) gets ignored – in short, nothing happens!
The same code works on an ESP32S and on ESP32-WROOM so this was a surprise.
Having boiled the code down to a minimal proof it looks like this:
#include <esp_sleep.h>
#define SENSOR_GPIO 33
#define SENSOR_BITMASK ((uint64_t)0x200000000)
#define ONE_SECOND 1000
#define THIRTY_SECONDS (3010001000)
void setup(void)
{
Serial.begin(115200);
pinMode(SENSOR_GPIO, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop(void)
{
Serial.println(“Loop!”);
Serial.flush( );
digitalWrite(LED_BUILTIN, HIGH);
delay(ONE_SECOND);
digitalWrite(LED_BUILTIN, LOW);
delay(ONE_SECOND);
digitalWrite(LED_BUILTIN, HIGH);
delay(ONE_SECOND);
digitalWrite(LED_BUILTIN, LOW);
esp_sleep_enable_timer_wakeup(THIRTY_SECONDS);
esp_sleep_enable_ext1_wakeup(SENSOR_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);
esp_deep_sleep_start( );
}
// end of file
Apparently: wake up from deep sleep is available on different GPIO ranges on different members of the ESP32 family. Hopefully this will save someone from pain.
https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/system/sleep_modes.html#_CPPv428esp_sleep_enable_ext0_wakeup10gpio_num_ti
Upon boot, ESP32 on Arduino sends information via the serial console:
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
etc,etc…
I have also seen information about wake up and about panic reboot.
How can my sketch get that information? Is there a “boot reason” variable or function call?
Thanks, Jim
A relevant few lines of code would look something like this ….
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause( );
switch(cause)
{
case ESP_SLEEP_WAKEUP_EXT0 :
Serial.println(“Woken by EXT0”);
break;
case ESP_SLEEP_WAKEUP_EXT1 :
Serial.println(“Woken by EXT1”);
break;
case ESP_SLEEP_WAKEUP_TIMER :
Serial.println(“Woken by timer”);
break;
default:
Serial.println(“Woken by power on”);
}
There are examples of this stuff around, especially on RNT.
Hi.
There is a function in our example that prints the wake-up reason:
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println(“Wakeup caused by external signal using RTC_IO”); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println(“Wakeup caused by external signal using RTC_CNTL”); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println(“Wakeup caused by timer”); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println(“Wakeup caused by touchpad”); break;
case ESP_SLEEP_WAKEUP_ULP : Serial.println(“Wakeup caused by ULP program”); break;
default : Serial.printf(“Wakeup was not caused by deep sleep: %d\n”,wakeup_reason); break;
}
}
Regards,
Sara
Thanks for the replies!
Those examples are for “normal” wake-up reasons, things that we expect as normal operation.
I’m hoping to log the reboots that are due to a panic, or a stack overflow. I have seen both of those in the information that is sent to the terminal at boot. “Guru Meditation Error: Core 1 panic’ed” is an example. Those were during code development, where my code caused the error and it was repeatable.
I haven’t seen discussion of wakeup_reason from esp_sleep_get_wakeup_cause for reboots due to panic or stack overflow. Is there a complete list of the wakeup reasons that might include reasons like “Guru Meditation Error: Core 1 panic’ed”?
I have an ESP32 IOT app that reboots unexpectedly, but it is more than a week between crashes. It may be caused by something about an SMTP email being sent, which normally works fine, but there may be an exception caused by my email SMTP service. And I don’t have the ESP hooked to USB or a terminal to record what is being sent there.
Thanks, Jim
Hi.
Here’s an example with other reset reasons: https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/reset_reason.html
I hope this helps.
Regards,
Sara
Thanks Sara for the reference to the Espressif docs.
The rtc_get_reset_reason(0) technique shows more (and different) after-boot information than the esp_sleep_get_wakeup_cause() technique. Most useful might be the flagging of a reset due to brown out. (case 15 below)
I tweaked and tested the code shown in that doc with positive results, sketch snippits below. These were logged in my TinyFS log upon boot, showing the rtc_get_reset_reason(0) function is working:
23:23:48 Booted – CPU0 reset reason: 12 ~~ SW_CPU_RESET Software reset CPU
23:25:14 Booted – CPU0 reset reason: 1 ~~ POWERON_RESET Vbat power on reset (or ESP reset pin)
23:27:20 Booted – CPU0 reset reason: 5 ~~ DEEPSLEEP_RESET Deep Sleep reset digital core
But after a reboot, the Medition Guru and Stack Overflow error evidence is still elusive, except that it is printed to the console at boot.
Guru Meditation Error is discussed in Fatal Errors~~Panic Handler:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/fatal-errors.html
Those exceptions can be directed to the console output before the ESP resets, but don’t seem to be “remembered” after reboot. The reboot process after those Fatal Errors may not provide for “remembering” the cause after reboot.
I notice that case 2 is not included in the Espressif example code, perhaps something can be learned there… If nothing else, it’s fun digging into the less-obvious operation of the ESP.
Thanks,Jim
——————————- (ESP WROOM 32 module)
#include “esp32/rom/rtc.h” // For rtc_get_reset_reason(0);
…
String S_IntReason_Verbose; // String for Reset reason texts
String S_IntReason; // String version of “reason”
in Setup:
Serial.begin( 115200 ); // Init serial port0 console
…
verbose_get_reset_reason(rtc_get_reset_reason(0)); // function to fill in the string var reset reasons
Serial.println (“>>> CPU0 reset reason: ” + S_IntReason + ” ~~ ” + S_IntReason_Verbose);
…
void verbose_get_reset_reason(int reason) { // Populate global string vars S_IntReason and S_IntReason_Verbose with results from rtc_get_reset_reason(0)
rtc_get_reset_reason(0); // requires #include “esp32/rom/rtc.h”
S_IntReason = String(reason);
switch (reason) {
case 1 : S_IntReason_Verbose = “POWERON_RESET Vbat power on reset (or ESP reset pin)”;break;
case 2 : S_IntReason_Verbose = “UNKNOWN This reason is not published?”;break;
case 3 : S_IntReason_Verbose = “SW_RESET Software reset digital core”;break;
case 4 : S_IntReason_Verbose = “OWDT_RESET Legacy watch dog reset digital core”;break;
case 5 : S_IntReason_Verbose = “DEEPSLEEP_RESET Deep Sleep reset digital core”;break;
case 6 : S_IntReason_Verbose = “SDIO_RESET Reset by SLC module, reset digital core”;break;
case 7 : S_IntReason_Verbose = “TG0WDT_SYS_RESET Timer Group0 Watch dog reset digital core”;break;
case 8 : S_IntReason_Verbose = “TG1WDT_SYS_RESET Timer Group1 Watch dog reset digital core”;break;
case 9 : S_IntReason_Verbose = “RTCWDT_SYS_RESET RTC Watch dog Reset digital core”;break;
case 10 : S_IntReason_Verbose = “INTRUSION_RESET Instrusion tested to reset CPU”;break;
case 11 : S_IntReason_Verbose = “TGWDT_CPU_RESET Time Group reset CPU”;break;
case 12 : S_IntReason_Verbose = “SW_CPU_RESET Software reset CPU”;break;
case 13 : S_IntReason_Verbose = “RTCWDT_CPU_RESET RTC Watch dog Reset CPU”;break;
case 14 : S_IntReason_Verbose = “EXT_CPU_RESET for APP CPU, reseted by PRO CPU”;break;
case 15 : S_IntReason_Verbose = “RTCWDT_BROWN_OUT_RESET Reset when the vdd voltage is not stable”;break;
case 16 : S_IntReason_Verbose = “RTCWDT_RTC_RESET RTC Watch dog reset digital core and rtc module”;break;
default : S_IntReason_Verbose = “NO_MEAN Default for unspecified reason”;break;
}
}
High,
I have set a bitmask for the pins 12-15 and 25-27 following your instruction. All the pins show the right number by interrupt except pin 14, which shows pin 27. What could be the reason?
Hello ,thank you for your teaching.
I have a question, i understand that i can use timer sleep time to set to sleep mode for an amount of time in seconds, the question is for how long it will stay on before it goes again in sleep time?
I need that it stay on for example for 5 seconds every time it awake from sleep time.
How can be done?
Carmine
Hi.
It will depend on your code. It depends of when you call the function to put the ESP32 into sleep again.
Regards,
Sara
Hello sara i have a question, in modern sleep mode the wifi access is possible or not ? if possible, i want to control that sleep mode by mobile web page which is open by default ip address of that esp32 after connected to that wifi? please gave me solution for this problem
Deafault ESP32 mode is active? If not, how I can disable power saving mode?
Regards
Norbert
Hi
If you want to avoid resetting and that the program execution starts from the beginning again.
I think light sleep is the better alternative as the program resumes the code processing from where it left off.
especially on the newer esp32 c3 and c6 where the power consumption is very low
Hi.
Thanks for your feedback. I have to take a look at light sleep. We haven’t covered it yet in our blog.
Regards,
Sara
Thanks for your reply Sara.
It would be great to have a tutorial on that topic.
I have good long-term experiences with light sleep
logging data from a weather station.
Very good article.
As for using the ULP, (which as you said is beyond the scope of yr article) it is not really sensible to only use the ULP for a wake up as the powersaving. It’s use in powersaving only comes from the fact it can already gather data while the ESP32 is asleep and pass this on to the ESP32 after wake up.
For maximum powersaving, especially if you want the ESP32 to sleep long and you do not need the RTC to retain any data, a good option is to send the ESP32 into hibernation (5uA consumption) and to use an external RTC to wake up the esp32 periodically.
A good choice would be the DS3231. AFAIK this can generate an SQW/INT signal, even if just on a button cell (so just Vbat connected, not Vcc). Powerconsumption of the DS3231 is only 1uA if solely on battery back up, so you would save 4uA
correction :
not really sensible to only use the ULP for a wake up as the powersaving IS MINIMAL.
Yes, that’s true.
I’m thinking about a tutorial using the DS3231 to wake-up the ESP32… let’s see.
Regards,
Sara
Hi Sara, I’ve run the TimerWakeUp sketch on an ESP32-C6 Zero and now I can’t stop it or reprogram it from the Arduino IDE. I’ve tried resetting with the reset button and the sketch keeps restarting. Any help would be appreciated. Thanks
Hi!
Unfortunately I can’t find an approach.
Can the ESP be woken up from deep sleep with the following configuration?
– 4 reed contacts or switches
– each at H or L (whenever the status changes)
Regards Peter
Hi, would it be possible to make something similar to this component (https://www.sparkfun.com/products/25365), for an ESP32 powered by Lipo?
The idea is to turn on and off an Arduino or ESP32 board, one press turns it on, a long press (x seconds) turns it off.