ESP32 Deep Sleep Mode and Wake Up Sources using Arduino IDE

In this tutorial, we will learn about ESP32 deep sleep mode and wake up sources using Arduino IDE. In this comprehensive guide, we will look at how to put the ESP32 development board into deep sleep mode. Furthermore, we will also discuss different wake up sources through which ESP32 can go from sleep to normal execution mode such as timer, external events, touch pins, etc. For the demo, we will explain it through different examples.

ESP32 deep sleep wake up sources arduino ide

Prerequisites

Before proceeding further, make sure you have the latest version of Arduino IDE installed on your system. Moreover, you should also install an ESP32 add-on in Arduino IDE. You can check this tutorial:

ESP32 Operating Modes

ESP32 core provides five different operating modes as follows:

  1. Active mode
  2. Modem Sleep mode
  3. Light Sleep mode
  4. Deep Sleep mode
  5. Hibernation mode

The following table lists which peripherals and units are either active or inactive during different modes. Maximum units remain in an inactive state in deep sleep and hibernation mode to save power consumption.

ESP32 operating modes

To see how these modes are useful in different applications, you can compare the power consumption of different operating modes listed in the table below:

ESP32 power consumtpion for different operating modes

What is Deep Sleep in ESP32?

To reduce power consumption and save battery life, deep sleep mode is implemented in ESP32. Generally, the module is very power-hungry and may pull up 75mA in normal consumption or inactive mode.

Esp32 Deep sleep micropython

But if WiFi is being used as well then the current consumption can go up to 240mA. Thus, if you are powering your ESP boards using batteries, it is not very convenient to use ESP32 in active mode when we want to perform some events after some specific duration only.

We can put the module into a deep sleep mode to reduce power consumption. When we have successfully activated deep sleep in ESP32, the current consumption would be in the range of micro Amperes (μA) and batteries will also last longer.

The table below shows the individual active units in ESP32 when it is set in deep sleep.

Peripherals and UnitsActive Units
ULP Co-processorON/OFF
RTC & RTC PeripheralsON
ESP32 Core & MemoryOFF
Wi-FiOFF
BluetoothOFF
PeripheralsOFF
RadioOFF

As shown in the above table, during the deep sleep mode only the RTC (real-time clock) controller, RTC peripherals, and RTC memories are in active mode. All the digital peripherals, most of the RAM, and the CPU is powered off.

Because only the RTC module is active. Therefore, the data will be lost which was not initially present in the RTC recovery memory. The current consumption goes down to 0.15mA – 10 µA if the ULP co-processor is turned on.

ESP32 Wake Up Sources

After activating the deep sleep mode of ESP32, there are several ways in which the ESP board can be woken up such as:

  1. Timer wake up
  2. Touch pin wake up
  3. External wake up

We’ll be focusing on all three methods in this tutorial comprehensively. We can also combine these sources together as well. Hence, whenever any one of them is triggered the ESP32 development board will wake up from deep sleep mode.

ESP32 Timer Wake Up and Example Sketch

With timer wake up, we can put ESP32 into sleep mode and wake up.

The real-time controller (RTC) has a built-in timer. We have to set a predefined amount of time, after it is over, the built-in timer wakes up the chip from deep sleep mode. This is achieved through a function. We will put the board in deep sleep mode for a specified amount of milliseconds.

We will use the esp_sleep_enable_timer_wakeup(sleep_time_in_us) function which is available in the Arduino IDE. The deepsleep() function has a single argument that denotes the sleeping time in microseconds. For example:

esp_sleep_enable_timer_wakeup(sleep_time_in_us)

Let’s have a look at a simple example demonstrating a timer wake up using the example from the library. We are going to show you a simple demonstration of how to use a timer to wake up. The ESP32 will remain in the active mode for 5 seconds and after that time is over, the ESP32 will be back in deep sleep mode. It will remain in deep sleep for 5 seconds. After that, it will again wake up and execute the same code.

Open your Arduino IDE and go to File > Examples > ESP32 > Deep Sleep > TimerWakeUp. The following sketch will open up.

/*
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
}

How the Code Works?

Defining Sleep Time

Firstly, the sleep time will be defined in the variable TIME_TO_SLEEP. It is set to 5 meaning the ESP32 board will remain in deep sleep for 5 seconds. Also, a micro second to second conversion factor is also defined which will be used later on in the program code.

#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) */

Saving Boot Count in RTC Memory

Now we will save the number of times our ESP32 board booted/woke up from deep sleep inside the variable ‘bootCount.’

This will be saved in the RTC Memory of the development board by using ‘RTC_DATA_ATTR’ before defining the bootCount variable.

RTC_DATA_ATTR int bootCount = 0;

print_wakeup_reason()

The following section of code shows the function print_wakeup_reason(). Through this function, the reason of our ESP32 waking up from deep sleep mode will get displayed on the serial monitor. As you can see there are various options including external wakeup using RTC_IO/RTC_CNTL, timer, touchpad, ULP program. For which ever reason the wake up will occur, it will get displayed.

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()

Inside the setup() function, we will open a serial connection at a baud rate of 115200 and add a delay of 1 second to open the serial monitor.

Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

Then we will increment the bootCount variable to 1 every time the ESP32 board wakes up from deep sleep. On the serial monitor, the number of times the ESP32 module booted will be displayed automatically.

++bootCount;
  Serial.println("Boot number: " + String(bootCount));

Now, we will call the print_wakeup_reason() function which was defined earlier to display the reason of the wake up. The message will be displayed on the serial monitor.

//Print the wakeup reason for ESP32
  print_wakeup_reason();

Using the following function, the ESP32 board wakes up from deep sleep mode. This function takes in the time in micro seconds as a parameter. Thus, we will pass TIME_TO_SLEEP (which is 5 seconds)* the conversion factor to insure that the argument inside the function is in micro seconds.

 esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

Also, display the following message on the Serial Monitor.

Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
  " Seconds");

Finally the ESP32 board goes to deep sleep when esp_deep_sleep_start() function is called.

Serial.println("Going to sleep now");
  Serial.flush(); 
  esp_deep_sleep_start();

loop()

The loop() function is empty because it never reaches this part of the program code. The ESP32 goes into deep sleep.

Demonstration

Make sure you choose the correct board and COM port before uploading your code to the board. Therefore go to Tools > Board and select ESP32 Dev Module.

select esp32 board

Then, go to Tools > Port and select the appropriate port through which your board is connected.

Selecting COM PORT ESP32

Click on the upload button to upload the code to ESP32 development board.

After you have uploaded your code to the ESP32, press its ENABLE button.

ESP32 enable reset button

In your Arduino IDE, open up the serial monitor and you will see the messages showing the boot count and the board going to deep sleep and waking up after every 5 seconds.

ESP32 Deep sleep timer wake up serial monitor
Serial Monitor

Pressing the ENABLE button on the ESP32 board will erase the RTC fast memory and the boot count will go back to zero.

Touch Wake Up & Example Sketch

Now, we will look into another type of wake up through which the ESP32 board can wake up from deep sleep. We will learn how to wake the board through touch wake up also known as wake up from touchpad. The wake up will occur when the user will touch one of the touch pins of the ESP32 board.

In our Arduino IDE, we will use the esp_sleep_enable_touchpad_wakeup() function to wake our ESP32 board from deep sleep via touch wake up.

esp_sleep_enable_touchpad_wakeup()

Touch sensor pins of Devkit

ESP-WROOM-32 provide on board 10 capacitive touch sensors. So you don’t need to use separate touch sensors in your project when you are using this development board. These capacitive touch sensors can be used to detect any electrical and magnetic waves around like magnetic field detection.

  • TOUCH0 – GPIO4
  • TOUCH1 – GPIO0
  • TOUCH2 – GPIO2
  • TOUCH3 – GPIO15
  • TOUCH4 – GPIO13
  • TOUCH5 – GPIO12
  • TOUCH6 – GPIO14
  • TOUCH7 – GPIO27
  • TOUCH8 – GPIO33
  • TOUCH9 – GPIO32

Attach a connecting wire to your ESP32 module as shown below. In this case we are using GPIO15 (Touch 3) because that is the touch pin used in the example code. You can use any suitable touch pin.

ESP32 Deep sleep touch wake up schematic diagram

Let’s have a look at a simple example demonstrating a touch wake up using the example from the library. We are going to show you a simple demonstration of how to use the touch pins to wake up. The ESP32 will remain in the active mode whenever the user will touch the wire which is connected to the touch pin otherwise it will be in deep sleep mode.

Open your Arduino IDE and go to File > Examples > ESP32 > Deep Sleep > TouchWakeUp. The following sketch will open up.

/*
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

This code is under Public Domain License.

Author:
Pranav Cherukupalli <[email protected]>
*/

#define Threshold 40 /* Greater the value, more the sensitivity */

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();

  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;
  }
}

void callback(){
  //placeholder callback function
}

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();

  //Setup interrupt on Touch Pad 3 (GPIO15)
  touchAttachInterrupt(T3, callback, Threshold);

  //Configure Touchpad as wakeup source
  esp_sleep_enable_touchpad_wakeup();

  //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
}

How the Code Works?

We will explain the parts where the touch wake up functionality is being incorporated. The rest of the code is similar to the one which we discussed before.

Defining Threshold

As we have to use the touch pins to awaken the ESP32 board from deep sleep thus, we will have to set a threshold value. This threshold value will be compared with the value read by the sensor when the user will touch the touch pin. If the read value is lower than the threshold which is 40 in this case then the ESP32 board will wake up. One thing to mention here is that, whenever the user touches the wire connected with the touch pin, the value read by the sensor will decrease.

#define Threshold 40

Interrupt

Another important part in the program code for the touch wake up is including interrupt for the respective touch pin. We will define the interrupt in the following line:

//Setup interrupt on Touch Pad 3 (GPIO15)
touchAttachInterrupt(T3, callback, Threshold);

The touchAttachInterrupt() function takes in three parameters. the first is the touch pin, the second is the callback function and the third is the threshold variable which we previously defined. Notice, that we are using GPIO15 (Touch3) as the touch pin thus we have used T3 as a parameter inside the function. For your particular touch pin specify the parameter accordingly e.g. T2 if using GPIO2. When the user will touch the touch pin (T3), the value on that particular pin will be lower than the threshold value, the ESP32 board wakes up. As a result, the callback function will be called then.

The callback function will only be called when the ESP32 module has woken up from deep sleep. This function is empty.

void callback(){
   //placeholder callback function
}

The following line of code will enable the touch wake up as the source of wake up for the module.

//Configure Touchpad as wakeup source
esp_sleep_enable_touchpad_wakeup()

Demonstration

Attach a connecting wire to GPIO15 of your ESP32 module. After uploading the code to your module, press its ENABLE button. Now open the serial monitor in your Arduino IDE. Touch the connecting wire attached T3 and the module will wake up. In the serial monitor, you will be able to view the boot count, the reason for wakeup, the GPIO pin which was touched and a message displaying that the board is going back to sleep.

ESP32 Deep sleep touch wake up serial monitor
Serial Monitor

External Wake Up & Example Sketches

As discussed earlier, we can also use an external interrupt to wake up the ESP32 from deep sleep. There is two external wake up resources available such as an ext0and ext1. External Wake up is the third type of wake-up method which we will be covering. When the state of a GPIO pin is changed, the ESP board will wake up from deep sleep. There are two types of external wake-ups in the ESP32.

  1. ext0: This is used when a single GPIO pin is being accessed.
  2. ext1: This is used when several GPIO pins are being accessed e.g. through different push buttons.

Note: Only Real-time clock or RTC input-output pins can be used as a wake up source. Therefore, to make use of this external wake up we need to make sure that during the deep sleep, the RTC peripherals are powered ON. Thus, we can only use the RTC GPIOs to induce the ext0, ext1 external wake-up.

The figure below shows the RTC GPIO pinout which we can use, highlighted in red:

ESP32 RTC GPIO pins as a wake up source from deep sleep mode

For ESP32 Devkit V1- DOIT we can use the following 14 GPIO pins:

  • RTC_GPIO0 : GPIO36
  • RTC_GPIO3: GPIO39
  • RTC_GPIO9: GPIO32
  • RTC_GPIO8: GPIO33
  • RTC_GPIO6: GPIO25
  • RTC_GPIO7: GPIO26
  • RTC_GPIO17: GPIO27
  • RTC_GPIO16: GPIO14
  • RTC_GPIO15: GPIO12
  • RTC_GPIO14: GPIO13
  • RTC_GPIO11: GPIO0
  • RTC_GPIO13: GPIO15
  • RTC_GPIO12: GPIO2
  • RTC_GPIO10: GPIO4

External Wake Up – ext0

In this section, we will see how to configure and use external wake up ext0 as a source to exit deep sleep mode. We will use the following function to wake our ESP32 board from deep sleep via ext0 wake up in Arduino IDE:

esp_sleep_enable_ext0_wakeup(GPIO_NUM_X, level)

esp_sleep_enable_ext0_wakeup(GPIO_NUM_X, level) function

The esp_sleep_enable_ext0_wakeup(GPIO_NUM_X, level) function defines how ext0 wakes up ESP32 from deep sleep. The first parameter is the RTC GPIO pin that will trigger the wakeup and the second parameter is the state (1 or 0) of that pin.

This function takes in the following parameters:

The first argument is the RTC GPIO pin. This is the object which denotes the GPIO which would be set up as the wake-up source. Additionally, the last argument is the trigger level. This trigger level defines the state of the GPIO pin as a source of wake up. It can be one of the following types:

1: Wake up process is triggered when the GPIO is in a high state.

0: Wake up process is triggered when the GPIO is in a low state.

Example Sketch ext0

Let’s have a look at a simple example demonstrating the external wake up ext0 using the example from the library. We are going to show you a simple demonstration of how to use the push button to trigger the wake up. The ESP32 will remain in the active mode whenever the user will press the push button which acts as a wake up source otherwise it will be in deep sleep mode.

ESP32 with push button ext0

We will need the following components.

Required Components

  • ESP 32 Devkit board
  • One Push button
  • One 10k ohm resistor
  • Breadboard
  • Connecting Wires

Schematic Diagram

Assemble the following components with ESP32 as shown in the schematic diagram below:

ESP32 Deep sleep external wake up ext0 schematic diagram

As we can see from the diagram, we connected the push button with any RTC GPIO pin which was stated above. We have used GPIO14 for this purpose. The 10k ohm pull-down resistor is also connected and grounded. One terminal of the push button is powered by 3.3 V and the other one is connected with GPIO14 to sense a change in logic level.

Open your Arduino IDE and go to File > Examples > ESP32 > Deep Sleep > ExternalWakeUp. The following sketch will open up. This example sketch has set GPIO33 as the triggering pin although in our case the push button is connected with GPIO14. Thus, we will change the GPIO pin which will cause the trigger for the wake up inside the sketch. You can use any suitable input GPIO pin but remember to replace it appropriately in the program code.

/*
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 14 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]>
*/

#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex

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 doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_14,1); //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  //esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //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 the Code Works?

This example sketch shows both types of external wake up i.e. ext0 and ext1. In this section we will explain the parts related to ext0. The parts for ext1 have been commented inside the code. Most of the program code is the same which we previously discussed for the other wake up types.

Inside the setup() function, we will open a serial connection at a baud rate of 115200 and add a delay of 1 second to open the serial monitor.

Serial.begin(115200);
delay(1000);

Then we will increment the bootCount variable to 1 every time the ESP32 board wakes up from deep sleep. On the serial monitor, the number of times the ESP32 module booted will be displayed automatically.

++bootCount;
Serial.println("Boot number: " + String(bootCount));

Now, we will call the print_wakeup_reason() function which was defined earlier to display the reason of the wake up. The message will be displayed on the serial monitor.

print_wakeup_reason();

Now, we will use the following function to wake the ESP32 board from deep sleep via ext0. The first argument is GPIO pin number which is connected with the push button. In our case, it is GPIO14. You can use any appropriate RTC GPIO pin to trigger ext0 wake up. The second parameter is 1 which shows that the wake up will be triggered when the push button is in a high ‘1’ state.

esp_sleep_enable_ext0_wakeup(GPIO_NUM_14,1); //1 = High, 0 = Low

Demonstration

To see the demonstration of the above code, upload the code to Arduino. Before uploading the code, make sure to select the ESP32 board from Tools > Board and also select the correct COM port to which the ESP32 board is connected from Tools > Port.

Once the code is uploaded to ESP32, open the serial monitor of Arduino IDE and set the baud rate to 115200. Press the pushbutton and notice the ESP32 board waking up from deep sleep. you can view the messages on the serial monitor showing the boot count, wake up reason, and going back to sleep message.

ESP32 Deep sleep ext0 wake up serial monitor
Serial Monitor

External Wake Up – ext1

Now let’s have a look at ext1. This is used when we want to have more than one GPIO pin as a source to initiate the external wake-up. Only the RTC controller is powered on during deep sleep. Therefore, we can only use the RTC GPIOs which we previously stated. We will use the following function to wake our ESP32 board from deep sleep via ext1 wake up in Arduino IDE:

esp_sleep_enable_ext1_wakeup(bitmask, mode)

esp_sleep_enable_ext1_wakeup(bitmask, mode) function

The esp_sleep_enable_ext1_wakeup(bitmask, mode) function defines how ext1 wakes up ESP32 from deep sleep.

This function takes on the following parameters:

The first argument is the bitmask of the GPIO pin number which will trigger the wakeup. The second argument is the mode used to wake up the development board. This shows the state of the GPIO pin. It can be one of the following:

  • ESP_EXT1_WAKEUP_ANY_HIGH: Wake up process is triggered when ANY GPIO is in a high state.
  • ESP_EXT1_WAKEUP_ALL_LOW: Wake up process is triggered when ALL the GPIOs are in a low state.

ext1 Example sketch

Now we are going to demonstrate how we will be using ext1 external wake-up with the help of two push buttons using the same sketch which we used for ext0. The push buttons will act as wake up sources for the ESP board. We will be needing the following components.

ESP32 with two push buttons ext1

Required Components

  • ESP 32 Devkit board
  • Two Push buttons
  • Two 10k ohm resistors
  • Breadboard
  • Connecting Wires

Schematic Diagram

Assemble the following components with ESP32 as shown in the schematic diagram below:

ESP32 Deep sleep external wake up ext1 schematic diagram

As we can see in the schematic both terminals of the push buttons have been commonly grounded through the two resistors and connected through GPIO2 and GPIO15. The other terminal for both is powered through 3.3V.

We will use the same sketch we did for ext0. We will uncomment the lines of code for ext1 in the sketch and comment the parts where ext0 is being used. Also we will convert GPIO15 and GPIO2 in bit mask numbers. This is already done in the program code given below:

/*
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]>
*/

#define BUTTON_PIN_BITMASK 0x8004 // GPIOs 2 and 15

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;
  }
}

/*
Method to print the GPIO that triggered the wakeup
*/
void print_GPIO_wake_up(){
  uint64_t 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);
}
  
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();

  //Print the GPIO used to wake up
  print_GPIO_wake_up();

  /*
  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 doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  //esp_deep_sleep_enable_ext0_wakeup(GPIO_NUM_15,1); //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial.println("Going to sleep now");
  delay(1000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

How the Code Works?

We will explain the parts which are different in ext1 as compared to the previous sketches.

Defining BUTTON_PIN_BITMASK

Firstly, we will use bit mask values for the GPIO pins which we are using as wake up sources. As you already know, for ext1 we will use the esp_sleep_enable_ext1_wakeup() function. This takes in two parameters. For the first parameter we will have to specify the bit mask value for GPIO15 and GPIO2.

Bitmask for single GPIO

To find the GPIO bitmask we will follow the steps given below.

  • First, calculate 2^GPIO_Pin_Number. Save this number.
  • Now, go to an online decimal to hexadecimal number converter like this. Convert the number which you obtained above in hexadecimal.
  • If using single GPIO pin then this is the value which you will use when defining the BUTTON_PIN_BITMASK variable. However, we are using two push buttons each attached to a different GPIO pin i.e. GPIO15 and GPIO2. We will have to perform additional steps for this purpose.

Bitmask for multiple GPIOs

  • For GPIO15 and GPIO2 follow the steps below:
    Calculate 2^15 + 2^2
  • Now convert the value obtained into hexadecimal. It will be 8004.
  • This is the value which we will define as ‘BUTTON_PIN_BITMASK.’
#define BUTTON_PIN_BITMASK 0x8004

If you increase the number of GPIOs just include it in the first step e.g. 2^GPIO_X + 2^GPIO_Y + 2^GPIO_Z + …

print_GPIO_wake_up()

We will use the print_GPIO_wake_up() function to determine which GPIO pin caused the ESP32 board to wake up from deep sleep. Inside this function we will call the esp_sleep_get_ext1_wakeup_status() function and save the value it returns in the variable ‘GPIO_reason.’ This value will be equal to 2^GPIO_PIN_NUMBER. To display the GPIO pin number in decimal we will use an appropriate conversion and print it in the serial monitor.

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);
}

Enabling ext1

We will use the following function to enable ext1 as the wake up source for our ESP32 module. This will cause GPIO15 and GPIO2 to act as triggering sources whenever their state is high.

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

Demonstration

Once the code is uploaded to ESP32, open the serial monitor of Arduino IDE and set the baud rate to 115200. Press the pushbuttons and notice the ESP32 board waking up from deep sleep. You can view the messages on the serial monitor showing the boot count, wake up reason, the GPIO which triggered the wake up, and then going back to sleep message.

ESP32 Deep sleep ext1 wake up serial monitor
Serial Monitor

Conclusion

In conclusion, we have learned comprehensively about the ESP32’s deep sleep mode and wake up sources such as timer, touch pins, and external wake up. We can use a single wake-up source or combine them together to wake the ESP32 module. These included timer wake up, touch pin wakes up, and external wake up.

Related tutorials:

Leave a Comment