ESP32. Arduino code for Deep Sleep and wake-ups (Timer, Touch Pad, GPIO …)

esp32 deep sleep wakeup gpio ext timer
Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp

The ESP32 makes it possible to manage very finely the power supply of the various components of the processor to optimize the lifespan for the projects of connected objects operating on battery. In this tutorial, we will learn how to put the processor into Light Sleep or Deep Sleep as well as the main methods of waking up. Timer (Timer), tactile (Touch Pad), external wake-up using one (ext0) or more (ext1) RTC pins.

 

Unlike the ESP8266 which requires special wiring to activate Deep-Sleep mode, everything can be done by programming with the ESP32.

The different power supply modes of the ESP32

It is possible to finely optimize the power supply of each function of the ESP32 to save battery. For this, the ESP32 has 5 operating modes as follows.

Active normal operating mode

GPIOWiFiBluetoothCPUULPRTCConsumption*
gpiowifibluetoothcpucpurtc95  ~ 240 mA

Modem Sleep Mode the processor is operational. The Wi-Fi and Bluetooth radio functions are deactivated. It is possible to reduce consumption by limiting to a single Core and lowering the CPU frequency to 80MHz.

Use the following methods to interrupt Modem functions

  • Stop the Bluetooth modem: esp_bluedroid_disable() or esp_bt_controller_disable()
  • Stop the WiFi modem esp_wifi_stop()

GPIOWiFiBluetoothCPUULPRTCConsumption*
gpiowifibluetoothcpucpurtc20  ~ 68 mA

Light Sleep Mode the processor is paused. RTC memory and RTC devices (list), as well as the ULP coprocessor are working. Any event (MAC, host, RTC timer or external interrupts) can wake up the chip.

The esp_light_sleep_start() method allows the processor and peripherals to be lightly put to sleep according to this scheme.

GPIOWiFiBluetoothCPUULPRTCConsumption*
gpiowifibluetoothcpucpurtc0,8 mA
RTC uniquement

Deep sleep Mode only RTC memory and RTC devices (list) are powered on. The Wi-Fi and Bluetooth connection data is stored in the RTC memory. The ULP coprocessor is functional.

The esp_deep_sleep_start() method is used to put the processor and peripherals to deep sleep according to this scheme.

GPIOWiFiBluetoothCPUULPRTCConsumption*
gpiowifibluetoothcpucpurtc10 ~ 150 μA
RTC uniquement

Hibernation The RTC recovery memory is powered off. Only one RTC timer on the slow clock and some RTC GPIOs are active. The RTC timer or RTC GPIOs can take the chip out of Hibernation mode.

GPIOWiFiBluetoothCPUULPRTCConsumption*
gpiowifibluetoothcpucpurtc1 μA
RTC uniquementx1

The modes are available for the following versions of the ESP32 SoCs: ESP32-D0WD-V3, ESP32-D0WDQ6-V3, ESP32-D0WD, ESP32-D0WDQ6, ESP32-D2WD, ESP32-S0WD and ESP32-U4WDH.

(*) Indicative energy consumption. The consumption strongly depends on the CPU load (what the program does), the frequency and the use of radio functions (WiFi, Bluetooth).

You can compare the five different modes on the following table in the ESP32 Espressif datasheet.

esp32 Power Consumption by Power Modes

Energy consumption depending on the power supply mode, page 23 of the technical documentation.

When Active Mode is selected (default operation), table 15 gives an estimate of the energy consumption according to the type of communication (WiFi or Bluetooth) transmitting or receiving.

Obviously, it is a rough envelope which strongly depends on the project.

esp32 RF Power-Consumption Specifications

Average power consumption depending on the type of communication (in reception and transmission). Table 15 of the technical documentation.

Notes on WiFi and bluetooth

Before going into deep sleep or light sleep, apps should turn off WiFi and BT using appropriate calls (esp_bluedroid_disable(), esp_bt_controller_disable(), esp_wifi_stop()). WiFi and BT connections will not be kept in deep standby or light standby even if these functions are not called.

The RTC and Touch GPIO pins allowing the ESP32 to wake up

Only certain pins allow the processor to be brought out of standby mode:

  • 18 pins marked RTC numbered and 0 to 17.
  • 10 pins for touch screens numbered from 0 to 9.

Only certain RTC pins are exposed depending on the development board used. The following table summarizes the list of RTC and Touch pins for the Espressif ESP32-DevKitC v4 (2020) and ESP32-DevKitC v2 (obsolete) development boards.

RTC Pin labelCapacitive Touch PadESP32-DevKitC version 4 Pinout (2020)ESP32-DevKitC V2 Pinout (obsolete)
Dev. Board PinCPU Pin (49 Pins)Dev. Board PinCPU Pin (39 Pins)
RTC_GPIO0VP5VP4
RTC_GPIO1Not exposed37Not exposed
RTC_GPIO2Not exposed7Not exposed
RTC_GPIO3VN8VN5
RTC_GPIO43410IO346
RTC_GPIO53511IO357
RTC_GPIO62514IO2510
RTC_GPIO72615IO2611
RTC_GPIO8Touch83313IO339
RTC_GPIO9Touch93212IO328
RTC_GPIO10Touch0244IO426
RTC_GPIO11Touch1230IO025
RTC_GPIO12Touch2222IO224
RTC_GPIO13Touch32115IO1523
RTC_GPIO14Touch42013IO1316
RTC_GPIO15Touch51812IO1214
RTC_GPIO16Touch61417IO1416
RTC_GPIO17Touch72716IO2712

As you can see, the pin registration is very different from version 2 to version 4.

Pinout of the ESP32-DevKitC version 4 (2020) kit

It’s easier to navigate with a diagram.

esp-vroom-32 pinout esp32 devkitc v4

Source: pinout of the official ESP32-DevkitC v4 kit according to the official Espressif documentation.

How to wake up a sleeping ESP32?

Unlike the ESP8266, it is necessary to configure in the code how you want to wake up the processor before putting it to sleep. For this, we have 7 sources (and methods) to wake up a sleeping ESP32

  • Timer The esp_sleep_enable_timer_wakeup() method allows you to program a timer which will wake up the ESP32 module at regular intervals.
  • Capacitive Touch Pad the esp_sleep_enable_touchpad_wakeup() method allows you to wake up the processor using a capacitive pin (a simple copper wire may suffice).
  • Interrupts There are two possibilities for an external wake-up call:
    • ext0 is used to wake up the chip with an RTC pin. Activate with the esp_sleep_enable_ext0_wakeup(RTC_PIN, MODE) method
    • ext1 allows to define multiple RTC pins to wake the chip. Activate with the esp_sleep_enable_ext1_wakeup(MASK, MODE) method
  • GPIO the esp_sleep_enable_gpio_wakeup() method can be used to wake up the processor using any pin.
  • Serial port (UART) the esp_sleep_enable_uart_wakeup() method is used to wake up the processor using another device
  • ULP The ULP coprocessor can wake up the ESP32 core by programming. Use the esp_sleep_enable_ulp_wakeup() method to activate this wake-up source.

Compatibility of wake-up methods depending on the type of sleep

Here is a summary table which makes it possible to verify that a method makes it possible to wake up the processor according to the type of sleep activated.

Wake up the ESP32 from standby using a Timer

The simplest method is to wake up the processor at regular intervals. This is typically the case with a data acquisition system which transmits its measurements at regular intervals.

This is for example the case of a weather station, monitoring the air quality, the light or sound atmosphere. No user interaction is necessary.

#include <Arduino.h> 

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5        /* Time ESP32 will go to sleep (in seconds) */

void setup(){
  Serial.begin(115200);

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

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

void loop(){ 
}

How does this code work?

It is indicated that the processor must be woken up using a timer. The time must be indicated in microseconds

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

Then we can put the processor to sleep.

Light SleepDeep Sleep
esp_light_sleep_start();
esp_deep_sleep_start();

How to know the origin of the awakening?

It may be interesting to know the cause of the awakening in order to carry out a particular treatment. For example, when you press a button (tactile or not), you can trigger the sending of information to a third-party server. Useful for signaling a fault on a production line, increasing a counter, signaling that a task has just ended …

The method esp_sleep_get_wakeup_cause() allows to know the last cause of awakening and the associated constants:

  • ESP_SLEEP_WAKEUP_TIMER timer
  • ESP_SLEEP_WAKEUP_TOUCHPAD capacitive touch pad
  • ESP_SLEEP_WAKEUP_EXT0 or ESP_SLEEP_WAKEUP_EXT1
  • ESP_SLEEP_WAKEUP_ULP ULP coprocessor wake up
  • ESP_SLEEP_WAKEUP_GPIO any GPIO can wake up
  • ESP_SLEEP_WAKEUP_UART woken up by serial port

Here is a method that you can integrate at the start of your programs

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;
    case ESP_SLEEP_WAKEUP_GPIO : Serial.println("Wakeup caused by GPIO"); break;
    case ESP_SLEEP_WAKEUP_UART : Serial.println("Wakeup caused by UART"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

It is then sufficient to call when necessary the print_wakeup_reason() method to find out the origin of the alarm clock.

Waking the ESP32 from standby with a touch key

Connect a single copper wire to a touch pin. Here for example, we will simply plug a jumper on pin 14 which corresponds to Touch6.

esp32 touch pad wakeup

Create a new sketch and upload this code

#include <Arduino.h> 
/*
Wakeup ESP32 with Touch Pad 
====================================
http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
code inspired by Pranav Cherukupalli <cherukupallip@gmail.com>
*/

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

// Display touchpad origin
void print_wakeup_touchpad(){
  touch_pad_t touchPin;
  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;
  }
}

// Display wakeup origine
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;
    case ESP_SLEEP_WAKEUP_GPIO : Serial.println("Wakeup caused by GPIO"); break;
    case ESP_SLEEP_WAKEUP_UART : Serial.println("Wakeup caused by UART"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

// Execute this function when Touch Pad in pressed
void callback() {
  Serial.println("Do something when Touch Pad is pressed");
}

void setup(){
  Serial.begin(115200);

  print_wakeup_reason();
  
  //Print the wakeup reason for ESP32 and touchpad too
  print_wakeup_reason();
  print_wakeup_touchpad();

  //Setup interrupt on Touch Pad 6 (GPIO14)
  touchAttachInterrupt(T6, callback, Threshold);

  //Configure Touchpad as wakeup source
  esp_sleep_enable_touchpad_wakeup();
  
  //esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep until Touch Pad will be pressed");

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

void loop(){ 
}

How does this code work?

We start by attaching an interrupt for each touch key that we want to use. Here, we will monitor the Touch6 connected to the GPIO14.

touchAttachInterrupt(T6, callback, Threshold);

The touchAttachInterrupt() method takes 3 parameters:

    • T6 a constant that corresponds to the key in the form Tx where x varies from 0 to 9
  • callback a method that will be called immediately when the processor wakes up
  • Threshold is the threshold below which the processor is awakened. By default, the threshold is fixed at 40. It is possible to modify the sensitivity by adjusting the constant Threshold at the start of the program.
#define Threshold 40

We then activate the alarm clock

esp_sleep_enable_touchpad_wakeup();

Before putting the processor to sleep.

Light SleepDeep Sleep
esp_light_sleep_start();
esp_deep_sleep_start();

It is possible to know the key that caused the awakening in order to connect the appropriate treatment

void print_wakeup_touchpad(){
  touch_pad_t touchPin;
  
  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;
  }
}

External alarm clock (ext0 or ext1)

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

  • ext0 makes it possible to wake up the chip with an RTC pin.
  • ext1 allows to define multiple RTC pins to wake the chip

ext0: wake up the chip with an RTC pin

The RTC controller contains logic to trigger the wake-up call when a pin is activated. You must use an RTC compatible pin. They are marked RTC_GPIOX in the technical documentation. These are the pins listed in the previous previous paragraph: 39, 38, 37, 36, 35, 34, 33, 32, 27, 26, 25, 15, 14, 13, 12, 4, 2, 0.

Please note that not all pins are exposed. Check availability according to your ESP32 development board.

We activate the wake-up by a pin using the esp_sleep_enable_ext0_wakeup(GPIO_PIN, LOGIC_LEVEL) method which takes two parameters:

  • GPIO_PIN the RTC pin to choose from the list above.
  • LOGIC_LEVEL triggered when the button is pressed (1) or descending (0), when the button is released.

The pin should be specified as GPIO_NUM_X where X is the pin number on the ESP32 development board.

Then, as before, we activate the light or deep standby

esp_deep_sleep_start();

Circuit

Connect the output of the button to the input marked 34 on the ESP32 board. Place a pull-up resistor (10KΩ for example) between the output of the button and the GND.

ext0 esp32 deep_sleep wakup button gpio

Upload code ext0

Create a new sketch and upload the example below

#include <Arduino.h>

void print_wakeup_reason();

void setup(){
  Serial.begin(115200);

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

  //Reveille le processeur en appuyant sur un bouton connecte au GPIO34
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_34,1);

  //Go to sleep now
  esp_deep_sleep_start();
}

void loop(){}

//Function that prints 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 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case 3  : Serial.println("Wakeup caused by timer"); break;
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.println("Wakeup was not caused by deep sleep"); break;
  }
}

ext1: wake up chip with multiple RTC pins

In ext1 mode multiple RTC pins can wake up the chip. For this, we must indicate in the form of a mask the pins to be monitored.

Circuit

Add a second button on entry 35.

esp32 deep_sleep wakup ext1 button gpio

How to create the ext1 mask?

The highest pin mark is 39. Open a spreadsheet and create a table consisting of 40 columns. GPIO0 counts as one column. The GPIO39 takes place in the first column, GPIO0 in the 39th column.

Then fill in with 0’s except 1 below pin GPIO34 and GPIO35.

GPIO39GPIO38GPIO35GPIO34GPIO33GPIO2GPIO1GPIO0
0001100000

Which gives the following binary digit

000011000000000000000000000000000000000

All that remains is to convert to hexadecimal using an online converter such as this or with a calculator, which gives in hexa.

0x600000000

convertisseur binaire-hexa-esp32 esp_sleep_enable_wakeup

Upload to wake up ESP32 chip with multiple RTC pins

Create a new sketch and upload the code below

#include <Arduino.h>

// Only GPIO35 and GPIO34 can wakeup ESP32 chip
// 000011000000000000000000000000000000000
#define BUTTON_PIN_BITMASK 0x600000000

void print_wakeup_reason();

void setup(){
  Serial.begin(115200);

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

  //Configure mask as ext1 wake up source for HIGH logic level
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  esp_deep_sleep_start();
}

void loop(){}

//Function that prints 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 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case 3  : Serial.println("Wakeup caused by timer"); break;
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.println("Wakeup was not caused by deep sleep"); break;
  }
}

How does this code work?

We add a new variable which contains the mask that will trigger the waking of the chip. The mask must be in hexadecimal format.

#define BUTTON_PIN_BITMASK 0x600000000

The esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK, MODE) method takes two parameters:

  • BUTTON_PIN_BITMASK Pin mask
  • MODE the wake-up mode. Two constants available ESP_EXT1_WAKEUP_ANY_HIGH or 1 ESP_EXT1_WAKEUP_ANY_LOW or 0

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);

The rest of the code is the same as the previous examples

Updates

10/09/2020 Publication of the article

 

Click to rate this post!
[Total: 0 Average: 0]

Are you having a problem with this topic?

Maybe someone has already found the solution, visit the forum before asking your question
Ask your question

Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp

Did you like this project ? Don't miss any more projects by subscribing to our weekly newsletter!

We will be happy to hear your thoughts

      Leave a Reply

      DIY Projects