In this tutorial, I will cover the essentials on how to invoke deep sleep on a ESP32 board and subsequently wake, using the ESP-IDF framework.
Most systems do not require to be operating at 100% core usage 24/7, as this has many disadvantages in terms of power, hardware degradation and excess heat generation.
Due to this many embedded systems have sleep modes which allow for a device to remain on and functioning but with limited capabilities and lower power consumption.
Specifically to the ESP32, there is two sleep modes, light and deep.
Light Sleep Mode:
Sets most peripherals, CPU and RAM to run on the high of a Clock signal. Meaning some functionality but only on the enable of a clock signal.
This state powers down any components that cannot be run through a clock signal including the wireless peripherals.
Deep Sleep Mode:
Sets most peripherals, CPU and RAM off. Disability all functionality of the chip apart from the RTC controlled sections.
Full descriptions can be found on Espressif Programming Docs
RTC - Real Time Clock, a section on the ESP32 SoC that is semi isolated from the rest of the system.
RTCs can be found within most electronics, they are small localised subsystems with a primary focus on maintaining time for the overall system, regardless of external power cuts. Common examples being the CMOS battery powered RTCs on most motherboards.
RTC are critical in most electronic circuits, they control system time and clock pulses, which are used on components to synchronise together allowing serial protocols to send data in the form of bits. (a good more detailed write-up is found here.)
Electrical circuits maintain time and clock pulses through oscillating circuits which use the resonance of a vibrating crystal to keep constant frequency and by extension time. (a good explanation of the concept here)
Within the ESP32, there is two of these circuits, one providing a 150kHz Clock (default), another providing a 8.5 MHz Clock.
The ESP32 RTC subsystem is more expansive than most, containing access to its own memory, IO pins and even ultra low power co-processor (ULP).
As the RTC subsystem is critical and should never be off, deep states leave the RTC subsystem mostly functional, hence we will use this subsystem to control the ESP32 during sleep.
Before delving into sending the device to sleep, it is key to decided and cover how to awaken the device from its slumber.
There is two main ways to wake the ESP32 once it has entered a sleep mode.
Time controlled- the RTC controller counts down from a set period, upon reaching 0 the device is woken. This leaves only the controller powered on during sleep.
IO pin controlled- the ULP CPU monitors for change in logic to pins, causing a trigger of wakeup. This leaves the controller, ULP CPU,RTC IO pins powered on during sleep.
Example 1.A The very simplest of these contain only 2 lines of function code.
This is a crude but simple solution, with app_main() working in a constant loop, utilising the esp_system.h and esp_sleep.h libraries.
Initial condition to wake up after 2,000,000 uS or 2 Seconds using esp_sleep_enable_timer_wakeup() . Followed by the deep sleep start function instruction.
Example 2. A - absolute simplest GPIO interupt wake example.
In Example 2.A - We are setting the wake condition to esp_sleep_enable_ext0_wakeup(). Followed by the deep sleep start function. Notice we have added the gpio header file to allow GPIO assignments. This example is still very simplistic but not best practise.
Example 2.B - Added into freeRTOS task and using better practises for the code.
In Example 2.B - We are adding in the headers for freeRTOS, taking our sleep configuration and sleep start and placing within their own sleep function.
This is allows us to call the freeRTOS task at various points in futher code without requiring to copy and paste thus repeating code and not sticking to DRY principles (Don't repeat yourself). We are also using a Macro to let us use HIGH instead of 1. This is a useful feature of the preprocessor in C that allows us to increase readability in our code. For this reason i have also created a wake_pin variable.