This tutorial shows how to put the ESP32 in deep sleep mode and wake it up with a timer after a predetermined amount of time. The ESP32 will be programmed with Arduino IDE.
Updated 8 October 2024.
To learn more about deep sleep and other wake-up sources, you can follow the next tutorials:
- [Complete Guide] ESP32 Deep Sleep with Arduino IDE and Wake Up Sources
- ESP32 External Wake Up from Deep Sleep
- ESP32 Touch Wake Up from Deep Sleep
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:
- First, configure the wake-up sources. This means configuring what will wake up the ESP32. You can use one or combine more than one wake-up source. This article shows you how to use the timer wake-up. Use the esp_sleep_enable_timer_wakeup() function and pass as argument time sleep time in microseconds.
- 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 handy 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 time is very straightforward. In the Arduino IDE, you just need to specify the sleep time in microseconds in the following function:
esp_sleep_enable_timer_wakeup(time_in_us)
Code
To program the ESP32 we’ll use Arduino IDE. So, you need to make sure you have the ESP32 core installed. Follow the next tutorial if you haven’t already:
Let’s see how deep sleep with timer wake-up works using an example from the ESP32 Arduino core. 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 1000000ULL /* 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");
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 bootCount to 1 again.
Wrapping Up
In summary, we’ve shown you how to use the timer wake-up source to wake-up the ESP32 in this unit.
- 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.
You can modify the provided example, and instead of printing a message, you can make your ESP32 do any other task.
The timer wake-up is useful to perform periodic tasks with the ESP32 without draining much power, as we do in the following projects:
Finally, we also have a tutorial about deep sleep with the ESP8266 that you might be interested in: ESP8266 Deep Sleep with Arduino IDE.
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.
Does this also apply to the Arduino UNO WiFi?
I can’t make the MAX72xx to work on it.
No, this guide is only compatible with the ESP32
I get an error when compiling in the Arduino IDE.
== Cut and Paste ==
Sleep_Wakeup_Modes:25: error: ‘RTC_DATA_ATTR’ does not name a type
RTC_DATA_ATTR int bootCount = 0;
== Done =========
I’m using a ESP32 -> DOIT ESP32 DevKit V1″ module.
Is there a header file that I need to include in this.
Shashi
Hi.
No, the code should work as it is – without the need to include anything else.
Honestly, I have no idea why you are getting that error :/
Sorry that I can’t help much.
Regards,
Sara
Google Search that error message. May be other people that have had that same error come up during projects.
Hi, any progress on this behaviour????
I get the same error, I use the timer wake-up sketch on a WiFi Lora 32(V2) board. The timer sketch, directly taken from the sample runs OK. Also when I re-compile it.
When I copy the first lines (up to and including the print_wakeup_reason() procedure into my own sketch, the compiler states: ‘RTC_DATA_ATTR’ does not name a type.
I thought that it could have something to do with the board still cycling the timer wake-up sketch, but as the original sketch compiles OK, this cannot be the cause.
Hi,
Problem solved by moving my include lines to the top of the code.
I did this after reading the comment of Sergi (add #include Arduino.h).
Still, it puzzles me: why does the site example not need to include Arduino.h ? And why does my own code need it??
Fred
Hi Kevin
I’ve got the same problem as you.
I’m using Atom, not Arduino IDE, and the same DOIT ESP32 DevKit V1 module
I’ve solved the problem including
#include
Regards
Sergi Fernández
Sorry 😉
#include
It seems the post page doesn’t owrk properly
You have to include the Arduino.h
Regards
excelentes tutoriales. ole, ole y ole !!!
My ESP32 only says “Wakeup caused by touchpad” when not touching it or anything (nothing connected at all).
Any ideas?
Hi.
But are you using touch wake up or only timer wake-up?
Regards,
Sara
anyone knows how to disable the timer function in the code?
(i have to use the eneble function earlier)
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 api 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
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 api 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
as i get a reboot from time to time (for no known reason, it’s reported as SW_CPU_RESET for both cores), i tried to put all data that should survive a reboot in rtc ram by defining them as globals with RTC_DATA_ATTR in front.
to check out if it works, i used ESP.restart() to force a reboot after data has been configured.
unfortunately, my data reads back as 0 instead of the previously configured value.
shouldn’t this work?
in the mean time, i found a solution:
using RTC_NOINIT_ATTR instead of RTC_DATA_ATTR does the job.
Hello, I would like to know whether it is possible to turn off the timer wake up once enabled (if the battery is too low, to not destroy it).
This will disable the wakeup time. Change the source for any other wake up trigger.
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
The deep sleep code works fine on a Seeed XIAOESP32-C3. The problem is how do I regain control of the ESP32? The com port appears every time it wakes up but almost instantly vanishes, leaving no time to upload new code