When your IoT project is powered by a wall adapter, you don�t care too much about power consumption. But if you�re going to power your project from a battery, every mA counts.

ESP32 can be a relatively power hungry device depending on what state it is in. It typically draws around 75mA for normal operations and around 240mA when transmitting data over WiFi.

The solution here is to reduce the ESP32�s power usage by taking advantage of Deep Sleep Mode.

To learn more about ESP32�s other sleep modes and their power consumption, please visit the tutorial below.

ESP32 Deep Sleep

In deep sleep mode, the CPUs, most of the RAM and all digital peripherals are powered off. The only parts of the chip that remain operational are:

  • ULP Coprocessor
  • RTC Controller
  • RTC Peripherals
  • RTC fast and slow memory

The chip consumes around 0.15 mA (if the ULP coprocessor is on) to 10�A.

ESP32 Deep Sleep Functional Block Diagram & Current Consumption

During deep sleep mode the main CPU is shut down, while the Ultra�Low�Power (ULP) Coprocessor can take sensor readings and wake up the CPU whenever necessary. This sleep pattern is known as the ULP sensor-monitored pattern. This is useful for designing applications where the CPU needs to be woken by an external event, or timer, or a combination of both, while maintaining minimal power consumption.

Along with the CPU, the main memory of the chip is also disabled. As a result everything stored in that memory is erased and cannot be accessed.

Because RTC memory is kept on, its contents are preserved even during deep sleep and can be retrieved after the chip is woken up. This is why the chip stores Wi-Fi and Bluetooth connection data in RTC memory before entering deep sleep.

If you want to use the data after reboot, store it in RTC memory by defining a global variable with RTC_DATA_ATTR attribute. For example, RTC_DATA_ATTR int myVar = 0;

After coming out of deep sleep the chip restarts with a reset and starts program execution from the beginning.

ESP32 supports running a deep sleep wake stub when coming out of deep sleep. This function runs immediately as soon as the chip wakes up � before any normal initialization, bootloader, or ESP-IDF code has run. After the wake stub runs, the chip can go back to sleep or continue to start ESP-IDF normally.

Unlike other sleep modes, the system cannot automatically go into deep-sleep mode. The esp_deep_sleep_start() function is used to enter deep sleep immediately after configuring wake-up sources.

ESP32 Deep Sleep Wake-up sources

The ESP32 can be woken from deep sleep mode using multiple sources. These sources are:

  • Timer
  • Touch pad
  • External wakeup(ext0 & ext1)

Multiple wake-up sources can be combined, in which case the chip will wake up when one of the sources is triggered.

Warning:

It is possible to put the ESP32 into deep sleep with no wake-up sources configured, in which case the chip remains in deep sleep mode indefinitely until an external reset is applied.

ESP32 Wake-up Source : Timer

The ESP32 RTC controller has a built-in timer that you can use to wake up the ESP32 after a predefined amount of time.

This feature is especially useful in a project that requires time stamping or daily tasks while maintaining low power consumption.

The esp_sleep_enable_timer_wakeup(time_in_us) function is used to configure the timer as a wakeup source. This function accepts an amount of time in microseconds (?s).

Example Code

Let�s see how it works, using an example from the library. Open your Arduino IDE, and navigate to File > Examples > ESP32 > Deep Sleep, and open the TimerWakeUp sketch.

This sketch demonstrates the most basic deep sleep example with a timer as the wake-up source and how to store the data in RTC memory to use it after a reboot.

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

Once the sketch is uploaded, open your serial monitor, set the baud rate to 115200 bps.

The ESP32 wakes up every 5 seconds, prints the wake up reason and bootCount on the serial monitor and goes into deep sleep again.

esp32 deep sleep timer wakeup output

Now try resetting the ESP32 by pressing the EN button, it should reset the bootCount to 1 again indicating that the RTC memory is completely wiped.

Code Explanation:

These first two lines of code define the time for which ESP32 will be asleep.

This example uses the conversion factor from microseconds to seconds, so you can set the sleep time in seconds in the TIME_TO_SLEEP variable. Here the ESP32 is put into deep sleep mode for 5 seconds.

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

As specified earlier you can save data in the ESP32�s RTC memory (8kB SRAM) which is not erased during deep sleep. However, it is erased when the ESP32 is reset.

To save data on RTC memory, you just need to add RTC_DATA_ATTR attribute before defining a variable. In this example the bootCount variable is saved in the RTC memory. It will count how many times ESP32 has woken up from deep sleep.

RTC_DATA_ATTR int bootCount = 0;

Next, the print_wakeup_reason() function is defined that prints the reason by which ESP32 has been woken 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;
  }
}

In the setup, we first initialize the serial communication with the PC.

Serial.begin(115200);

The bootCount variable is then incremented by one and printed to the serial monitor to show the number of times the ESP32 has woken up from deep sleep.

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

Then the print_wakeup_reason() function is called, but you can call any function you want to perform the desired task, for example, reading the value of a sensor.

print_wakeup_reason();

Next we configure the timer wake up source using the esp_sleep_enable_timer_wakeup(time_in_us) function. Here the ESP32 is set to wake up every 5 seconds.

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

Finally the ESP32 is put to sleep by calling the esp_deep_sleep_start() function.

esp_deep_sleep_start();

In this sketch the ESP32 enters deep sleep in the setup() function itself, so it never reaches the loop() function. Hence the loop() function is left blank.

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

ESP32 Wake-up Source : Touch Pad

You can wake ESP32 from deep sleep using the following touch pins.

esp32 touch pins

Enabling the ESP32 to wake up using the touch pin is simple. In Arduino IDE you just need to use esp_sleep_enable_touchpad_wakeup() function.

Wiring

Let�s wire a cable to GPIO#15 (Touch#3) which will act as the touch wake-up source. You can attach any conductive object like wire, aluminum foil, conductive cloth, conductive paint etc. to the touch sensitive pin and turn it into a touchpad.

connecting wire to esp32 for touch wakeup source

Example Code

Let�s see how it works, using an example from the library. Open your Arduino IDE, and navigate to File > Examples > ESP32 > Deep Sleep, and open the TouchWakeUp sketch.

This sketch demonstrates the most basic deep sleep example with touch as the wake-up source and how to store the data in RTC memory to use it after a reboot.

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

Once the sketch is uploaded, open your serial monitor, set the baud rate to 115200 bps.

Now when the pin is touched, the ESP32 will display the boot count, wake up reason, and which GPIO was touched on the serial monitor.

esp32 deep sleep touch wakeup output

Code Explanation:

The first line of code sets the threshold value for the touch pin to 40. The higher the threshold value, the higher the sensitivity. You can change this value according to your project.

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

As specified earlier you can save data in the ESP32�s RTC memory (8kB SRAM) which is not erased during deep sleep. However, it is erased when the ESP32 is reset.

To save data on RTC memory, you just need to add RTC_DATA_ATTR attribute before defining a variable. In this example the bootCount variable is saved in the RTC memory. It will count how many times ESP32 has woken up from deep sleep.

RTC_DATA_ATTR int bootCount = 0;

After this a variable named touchPin of type touch_pad_t (type enum) is defined which will later help us to print the GPIO by which ESP32 is woken up from sleep.

touch_pad_t touchPin;

Next, the print_wakeup_reason() function is defined that prints the reason by which ESP32 has been woken 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 print_wakeup_touchpad() function is also defined that prints the GPIO number by which ESP32 has been woken up from deep 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;
  }
}

Next a callback() function is defined. This is nothing but an Interrupt Service Routine (ISR), which will be called every time a touch interrupt is triggered. But unfortunately this function is not executed if ESP32 is in deep sleep. Therefore this function is left blank.

void callback(){
  //placeholder callback function
}

In the setup, we first initialize the serial communication with the PC.

Serial.begin(115200);

The bootCount variable is then incremented by one and printed to the serial monitor to show the number of times the ESP32 has woken up from deep sleep.

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

Then the print_wakeup_reason() and print_wakeup_touchpad() functions are called, but you can call any function you want to perform the desired task, for example, reading the value of a sensor.

print_wakeup_reason();
print_wakeup_touchpad();

Now the interrupt has to be attached to one of the touch pins with the desired sensitivity threshold. Here the interrupt is attached to touch pad 3 (GPIO15).

touchAttachInterrupt(T3, callback, Threshold);

Next we configure the touch wake up source using the esp_sleep_enable_touchpad_wakeup() function.

esp_sleep_enable_touchpad_wakeup();

Finally the ESP32 is put to sleep by calling the esp_deep_sleep_start() function.

esp_deep_sleep_start();

In this sketch the ESP32 enters deep sleep in the setup() function itself, so it never reaches the loop() function. Hence the loop() function is left blank.

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

ESP32 Wake-up Source : External Wake-up

There are two kinds of external triggers to wake ESP32 from deep sleep.

  • ext0 � Use this when you want to wake up the chip only by a specific GPIO pin.
  • ext1 � Use this when you want to wake up the chip using multiple GPIO pins.

If you want to use an interrupt pin to wake ESP32 from deep sleep then you have to use so called RTC_GPIO pins. These GPIOs are routed to the RTC low-power subsystem so they can be used when the ESP32 is in deep sleep.

The RTC_GPIO pins are:

esp32 rtc gpio pins

ext0 External Wake-up Source

The ESP32 can be configured to wake from deep sleep when one of the RTC_GPIO pins changes its logic level.

The esp_sleep_enable_ext0_wakeup(GPIO_PIN, LOGIC_LEVEL) function is used to enable this wake-up source. This function takes two parameters. The first is the GPIO pin number and the second is the logic level (LOW or HIGH) by which we want to trigger the wake-up.

Since ext0 uses RTC IO to wake up ESP32, the RTC peripherals are kept running during deep sleep.

And since the RTC IO module is enabled you can take advantage of the internal pullup or pulldown resistors. They need to be configured using the rtc_gpio_pullup_en() and rtc_gpio_pulldown_en() functions before esp_deep_sleep_start() is called.

Wiring

Let�s wire a push button to GPIO#33 using a 10K pull down resistor.

Connecting Button to ESP32 for ext0 External Wakeup Source

Example Code

Let�s see how it works, using an example from the library. Open your Arduino IDE, and navigate to File > Examples > ESP32 > Deep Sleep, and open the ExternalWakeUp sketch.

This sketch demonstrates the most basic deep sleep example with an ext0 as the wake-up source.

#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");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

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

Once the sketch is uploaded, open your serial monitor, set the baud rate to 115200 bps.

Now when you press the pushbutton, the ESP32 will display the boot count and wake up reason on the serial monitor. Try it several times and watch the boot count increase with each button press. Also notice that ext0 uses RTC IO to wake up the ESP32.

esp32 deep sleep ext0 wakeup output

Code Explanation:

The first line of code sets the bit mask. It�s not needed for ext0 external wake-up so you can ignore it for now. We will learn about this during the ext1 external wake-up code explanation.

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

As specified earlier you can save data in the ESP32�s RTC memory (8kB SRAM) which is not erased during deep sleep. However, it is erased when the ESP32 is reset.

To save data on RTC memory, you just need to add RTC_DATA_ATTR attribute before defining a variable. In this example the bootCount variable is saved in the RTC memory. It will count how many times ESP32 has woken up from deep sleep.

RTC_DATA_ATTR int bootCount = 0;

Next, the print_wakeup_reason() function is defined that prints the reason by which ESP32 has been woken 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;
  }
}

In the setup, we first initialize the serial communication with the PC.

Serial.begin(115200);

The bootCount variable is then incremented by one and printed to the serial monitor to show the number of times the ESP32 has woken up from deep sleep.

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

Then the print_wakeup_reason() function is called, but you can call any function you want to perform the desired task, for example, reading the value of a sensor.

print_wakeup_reason();

Now the ext0 external wake-up source is configured by using the esp_sleep_enable_ext0_wakeup(GPIO_PIN, LOGIC_LEVEL) function. This function takes two parameters. The first is the GPIO pin number and the second is the logic level (LOW or HIGH) by which we want to trigger the wake-up. In this example the ESP32 is configured to wake up when the logic level of GPIO#33 becomes HIGH.

esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1);

Finally the ESP32 is put to sleep by calling the esp_deep_sleep_start() function.

esp_deep_sleep_start();

In this sketch the ESP32 enters deep sleep in the setup() function itself, so it never reaches the loop() function. Hence the loop() function is left blank.

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

ext1 External Wake-up Source

The ESP32 can be configured to wake from deep sleep using multiple pins. Remember those pins must be among the RTC GPIO pins.

Since the ext1 wake-up source uses an RTC controller, it does not require RTC peripherals and RTC memory to be powered on. In this case the internal pullup and pulldown resistors will not be available.

In order to use the internal pullup or pulldown resistors, we need to request the RTC peripherals to be kept on during sleep, and configure the pullup/pulldown resistors using the rtc_gpio_pullup_en() and rtc_gpio_pulldown_en() functions before entering sleep.

The esp_sleep_enable_ext1_wakeup(BUTTON_PIN_MASK, LOGIC_LEVEL) function is used to enable this wake-up source. This function takes two parameters. The first is a bit mask that tells the ESP32 which pins we want to use and the second parameter can be one of the two logic levels mentioned below to trigger the wake-up:

  • Wake up if one of the selected pins is HIGH (ESP_EXT1_WAKEUP_ANY_HIGH)
  • Wake up if all selected pins are LOW (ESP_EXT1_WAKEUP_ALL_LOW)

Bitmask

The easiest way to understand the bit mask is to write it in binary format. You can see that the bit numbering is based on the normal GPIO numbering. The least significant bit (LSB) represents GPIO#0 and the most significant bit (MSB) represents GPIO#39.

ext1 pin bit mask representation in binary
  • 0 represents masked pins
  • 1 represents pins that will be enabled as a wake-up source

So if you want to enable a GPIO to wake up you must write a 1 to its corresponding location and a 0 to each of the remaining pins. And finally you have to convert it to HEX.

For example, if you want to use GPIO#32 and GPIO#33 as external wake-up sources, the bitmask would be like this:

ext1 External Wakeup Source Pin Bit Mask Representation in Binary

Wiring

Let�s wire the two push buttons to GPIO#33 and GPIO#32 using 10K pull down resistors.

Connecting Multiple Buttons to ESP32 for ext1 External Wakeup Source

Example Code

Let�s see how it works using the same ExternalWakeUp example from the library. Once again open your Arduino IDE, and navigate to File > Examples > ESP32 > Deep Sleep, and open the ExternalWakeup sketch.

Let�s make three changes to the sketch to make it work for us:

  1. Change the BUTTON_PIN_BITMASK constant
  2. Comment the code for ext0
  3. Uncomment the code for ext1

Changes to the sketch are highlighted ingreen.

#define BUTTON_PIN_BITMASK 0x300000000

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");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

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

Once the sketch is uploaded, open your serial monitor, set the baud rate to 115200 bps.

Now when you press the pushbutton, you will get something similar on the serial monitor. Also notice that ext1 uses the RTC controller to wake up the ESP32.

esp32 deep sleep ext1 wakeup output

Code Explanation:

This code is identical to ext0�s code except for two changes.

At the beginning of the code, the bit mask is defined. Since we�re using pins GPIO#32 and GPIO#33 in the example, the mask has 1�s at their respective positions, with 32 0�s on the right and 6 0�s on the left.

00000011 00000000 00000000 00000000 00000000 BIN = 0x300000000 HEX

#define BUTTON_PIN_BITMASK 0x300000000

And finally, ext1 is enabled as wake up source.

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

Login
ADS CODE