ESP32 External Wake Up from Deep Sleep

This article shows how to put the ESP32 in deep sleep mode and wake it with an external wake up, like a button press. We’ll use Arduino IDE to program the ESP32 and cover how to use ext0 and ext1 methods.

Throughout this article we’ll cover the following subjects:

  • how to put the ESP32 in deep sleep mode;
  • wake up the ESP32 by changing the value of one GPIO (with a pushbutton) using the ext0 method;
  • wake up the ESP32 using several GPIOs using the ext1 method;
  • identify which GPIO caused the wake up.

To learn more about deep sleep and other wake up sources, you can follow the next tutorials:

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:

  1. 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. In this article, we’ll show you how to use the external wake up source.
  2. 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.
  3. Finally, you use the esp_deep_sleep_start() function to put your ESP32 into deep sleep mode.

External Wake Up

External wake up is one of ways to wake up the ESP32 from deep sleep. This means that you can wake up the ESP32 by toggling the value of a signal on a pin, like the press of a button. 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.

This is our complete guide to program the ESP32 with Arduino IDE, including projects, tips, and tricks!  SIGN UP NOW »

This is our complete guide to program the ESP32 with Arduino IDE, including projects, tips, and tricks! SIGN UP NOW »

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)

This wake up source allows you to use multiple RTC GPIOs. You can use two different logic functions:

  • 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.

This wake up source is implemented by 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(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.

Note: with this wake up source, you can only use pins that are RTC GPIOs.

The following figure shows the ESP32 pinout and its RTC GPIOs highlighted in light orange color (for the ESP32 V1 DOIT board). You can also take a look at our ESP32 GPIO reference guide.

Parts Required

To follow this tutorial, you need the following parts:

Download our Free eBooks and Resources

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Code – External Wake Up

To program the ESP32 we’ll use Arduino IDE. So, you need to make sure you have the ESP32 add-on installed. Follow the next tutorials to install the ESP32 add-on, if you haven’t already:

To show you how to use the external (ext0) wake up source, we’ll 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 <cherukupallip@gmail.com>
*/

#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_33,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
}

View raw code

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

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(GPIO_NUM_33,1); //1 = High, 0 = Low

Instead of GPIO 33, you can use any other RTC GPIO pin.

Schematic

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.

(This schematic uses the ESP32 DEVKIT V1 module version with 30 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)

Note: only RTC GPIOs can be used as a wake up source. Instead of GPIO 33, you can 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 in each button press.

Using this method is useful to wake up your ESP32 using a pushbutton, for example, to make a certain task. However, with this method you can only use one GPIO as wake up source.

What if you want to have different buttons, all of them wake up the ESP, but do different tasks? For that you need to use the ext1 method.

ext1

The ext1 allows you to wake up the ESP using different buttons and perform different tasks depending on the button you pressed.

Instead of using the esp_sleep_enable_ext0_wakeup() function, you use the esp_sleep_enable_ext1_wakeup() function. In the code, that function is commented:

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

Uncomment that function so that you have:

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

The first argument of the 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.

In this example we’re using the variable BUTTON_PIN_BITMASK, that was defined at the beginning of the code:

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

This is only defining one pin as a wake up source, GPIO 33. You need to modify the bitmask to configure more GPIOs as a wake up source.

GPIOs Bitmask

To get the GPIOs bitmask, follow the next steps:

  1. Calculate 2^(GPIO_NUMBER). Save the result in decimal;
  2. Go to rapidtables.com/convert/number/decimal-to-hex.html and convert the decimal number to hex;
  3. Replace the hex number you’ve obtained in the BUTTON_PIN_BITMASK variable.

Mask for a single GPIO

For you to understand how to get the GPIOs bitmask, let’s go through an example. In the code from the library, the button is connected to GPIO 33. To get the mask for GPIO 33:

1. Calculate 2^33. You should get 8589934592;

2. Convert that number (8589934592) to hexadecimal. You can go to this converter to do that:

3. Copy the Hex number to the BUTTON_PIN_BITMASK variable, and you should get:

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

Mask for several GPIOs

If you want to use GPIO 2 and GPIO 15 as a wake up source, you should do the following:

  1. Calculate 2^2 + 2^15. You should get 32772
  2. Convert that number to hex. You should get: 8004
  3. Replace that number in the BUTTON_PIN_BITMASK as follows:
#define BUTTON_PIN_BITMASK 0x8004

Identifying the GPIO used as a wake up source

When you use several pins to wake up the ESP32, it is useful to know which pin caused the wake up. For that, you can use the following function:

esp_sleep_get_ext1_wakeup_status()

This function returns a number of base 2, with the GPIO number as an exponent: 2^(GPIO_NUMBER). So, to get the GPIO in decimal, you need to do the following calculation:

GPIO = log(GPIO_NUMBER)/log(2)

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;
  • use the esp_sleep_get_ext1_wakeup_status() function to get the GPIO that triggered wake up.

The next sketch has all those changes implemented.

/*
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 <cherukupallip@gmail.com>
*/

#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(){
  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);
}
  
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
}

View raw code

You define the GPIOs mask at the beginning of the code:

#define BUTTON_PIN_BITMASK 0x8004 // GPIOs 2 and 15

You create a function to print 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);
}

And finally, you enable ext1 as a wake up source:

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

Testing the Sketch

Having two buttons connected to GPIO 2 and GPIO 15, you can upload the code provided to your ESP32. Make sure you have the right board and COM port selected.

The ESP32 is in deep sleep mode now. 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.

You should get something similar on the serial monitor.

Wrapping Up

The ESP32 can be awaken from sleep using a timer, the touch pins, or an external wake up. In this article we’ve shown you how to wake up the ESP32 using an external wake up. This means that you can wake up the ESP32 when the value of a GPIO changes (from HIGH to LOW, or LOW to HIGH).

To learn more about deep sleep with the ESP32, take a look at our complete guide: ESP32 Deep Sleep with Arduino IDE and Wake Up Sources.

If you like ESP32, you may also like the following resources:


Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »

Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our weekly newsletter!

Leave a Comment

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.