Chapter 269: Low-Power Features Comparison
Chapter Objectives
By the end of this chapter, you will be able to:
- Understand the different power-saving modes available in the ESP32 ecosystem (Active, Modem-Sleep, Light-Sleep, Deep-Sleep).
- Describe the various wake-up sources that can bring an ESP32 out of a sleep state.
- Explain the function of key low-power hardware, including the RTC controller and the Ultra-Low-Power (ULP) co-processor.
- Compare and contrast the power consumption profiles and low-power features of different ESP32 variants.
- Implement a practical application that utilizes deep-sleep mode to drastically reduce power consumption.
- Troubleshoot common issues related to power management in ESP32 projects.
Introduction
In the Internet of Things, many devices are not plugged into a wall outlet. They operate on batteries for months or even years, deployed in remote or hard-to-reach locations. For these applications, power efficiency is not just a feature; it is the most critical design constraint. A device that drains its battery in a day is fundamentally unusable for its intended purpose.
The ESP32 family was designed with this reality in mind. Every variant includes a sophisticated set of power management features that allow developers to minimize energy consumption. However, not all ESP32 chips are created equal. Newer variants, particularly those designed for specific use cases like low-power mesh networking, offer significant advantages in efficiency. This chapter will explore the power-saving architecture of the ESP32 family, provide a detailed comparison across the variants, and show you how to leverage these features in your own projects.
Theory
Power Consumption States
The ESP-IDF Power Management framework allows a device to be in one of several states, each offering a different trade-off between performance and power consumption.
%%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans'}}}%% graph TD subgraph "Power States (Highest to Lowest Consumption)" A["<b>Active Mode</b><br>CPU & Peripherals ON<br>Radio Active<br><i>~100-300+ mA</i>"] B["<b>Modem-Sleep</b><br>CPU ON, Wi-Fi Modem sleeps between beacons<br><i>~15-30 mA</i>"] C["<b>Light-Sleep</b><br>CPU Paused, RAM Off<br>Fast Wake-up<br><i>~0.2-1 mA</i>"] D["<b>Deep-Sleep</b><br>CPU & Main RAM OFF<br>Only RTC part is ON<br><i>~5-20 µA</i>"] end A --> B B --> C C --> D %% Styling classDef high fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; classDef mid fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E; classDef low fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF; classDef lowest fill:#D1FAE5,stroke:#059669,stroke-width:1px,color:#065F46; class A high; class B mid; class C low; class D lowest;
- Active Mode: This is the full-power state. The main CPUs and all peripherals are running. The radio (Wi-Fi/Bluetooth) can be actively transmitting or receiving. Power consumption is at its highest, typically ranging from 100 to 300 mA or more during radio transmission.
- Modem-Sleep Mode: This is an automatic power-saving state for applications connected to a Wi-Fi network. The CPU is running, but the Wi-Fi modem is periodically shut down between DTIM beacon intervals. This significantly reduces the average power consumption while maintaining a Wi-Fi connection, with consumption often in the range of 15-30 mA.
- Light-Sleep Mode: In this mode, the main CPUs are paused (
clock-gated
), and most peripherals are shut down. The main system RAM is powered down, but the device can be woken up very quickly (in microseconds) by a configured wake-up source. The Wi-Fi/BLE connection can be maintained. This mode is useful for applications that need to respond to events with low latency but can sleep between them. Power consumption is typically under 1 mA. - Deep-Sleep Mode: This is the most power-efficient state. The CPUs and most of the RAM and peripherals are completely powered off. Only the RTC (Real-Time Clock) controller and its associated RTC peripherals and memory remain active. Waking up from deep sleep is slower (milliseconds) because it triggers a full device reboot. However, the power consumption is extremely low, often in the single-digit microampere range, making it the go-to mode for battery-powered devices.
Wake-up Sources
A sleeping device is only useful if it can wake up to perform its function. The ESP32 can be woken from sleep by several sources, configured before entering the sleep state.
%%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans'}}}%% mindmap root((ESP32 Wake-up<br>Sources)) Timer After a set duration External (GPIO) ext0_(single pin) ext1_(multiple pins) Touch Pad Capacitive touch ULP Co-processor Wake on ULP program condition Light-Sleep Only UART GPIO
- Timer: Wake up after a predefined amount of time. This is the most common wake-up source for periodic tasks like sensor readings.
- External (GPIO): Wake up when a specific GPIO pin changes state (e.g., a button press).
ext0
allows waking on a single pin, whileext1
allows waking on a combination of RTC-capable GPIO pins. - Touch Pad: Wake up when a capacitive touch sensor is triggered (on variants that have them).
- ULP Co-processor: Wake up based on a condition detected by the Ultra-Low-Power co-processor program.
- UART/GPIO (Light-Sleep only): Wake up on incoming data or specific pin activity.
Key Low-Power Hardware
Two core hardware blocks are central to the ESP32’s low-power capabilities.
1. The RTC Controller
The Real-Time Clock controller is the “manager” of the low-power system. It remains powered on even in deep-sleep mode. Its responsibilities include:
- Keeping track of time for timer-based wake-ups.
- Monitoring RTC GPIOs for external wake-up events.
- Powering the RTC memory (a small amount of SRAM, typically 8KB or 16KB) that persists through deep sleep. This is crucial for storing state information (e.g., a boot count) between wake-up cycles.
- Controlling the ULP co-processor.
2. The ULP (Ultra-Low-Power) Co-processor
Found on certain ESP32 variants (see table below), the ULP is a tiny, simple secondary processor that can run while the main CPUs are in deep sleep. Its purpose is to perform simple operations—like polling a sensor or checking for a specific condition—without waking the power-hungry main CPUs. It can perform a task and then decide whether to wake the main system or let it continue sleeping. There are two types:
- FSM ULP: Found on ESP32, ESP32-S2, and ESP32-S3. This is a Finite-State Machine that is programmed with a special assembly-like language.
- RISC-V ULP: Found on ESP32-S2 and ESP32-S3. This is a more powerful and easier-to-use ULP based on the standard RISC-V instruction set, which can be programmed in C.
Low-Power Feature Comparison Across Variants
The choice of ESP32 variant has a massive impact on the power profile of a project. Newer chips, especially those built on more advanced process nodes or designed for low-power radios, are significantly more efficient.
Feature / Variant | ESP32 | ESP32-S2/S3 | ESP32-C3 | ESP32-C6 | ESP32-H2 |
---|---|---|---|---|---|
Deep-Sleep Current | ~10-20 µA | ~7-15 µA | ~5 µA | ~7 µA | ~3-5 µA |
Light-Sleep Current | ~800 µA | ~200-500 µA | ~130 µA | ~150 µA | ~30 µA |
ULP Co-processor | ✔ (FSM) | ✔ (FSM & RISC-V) | ✘ | ✘ | ✘ |
Primary Radios | Wi-Fi 4, BT, BLE | Wi-Fi 4, BLE | Wi-Fi 4, BLE 5.0 | Wi-Fi 6, BLE 5.0, 802.15.4 | BLE 5.0, 802.15.4 |
Best For Low-Power… | General purpose, Legacy Projects | Wi-Fi applications needing ULP | Cost-effective Wi-Fi applications | Multi-protocol gateway/router | Battery-powered mesh end-devices |
Key Observations:
- RISC-V Advantage: The RISC-V based chips (C3, C6, H2) generally achieve the lowest deep-sleep currents, making them excellent choices for battery-powered applications.
- H2, The Efficiency King: The ESP32-H2, lacking a power-hungry Wi-Fi radio, is optimized for low-power mesh protocols and boasts the best deep-sleep and light-sleep performance. It is the ideal choice for a battery-powered Zigbee or Thread sensor.
- ULP for Complex Sensing: The ESP32-S2 and S3 are the champions for applications that need to perform complex sensing or data filtering while in deep sleep, thanks to their advanced ULP co-processors.
- C6, The Versatile Choice: The ESP32-C6 offers a compelling blend. It has excellent low-power performance and the unique ability to handle Wi-Fi 6, BLE, and 802.15.4 radios, making it perfect for power-conscious gateways.
Practical Example: Deep Sleep with a Timer Wake-up
This example demonstrates the fundamental deep-sleep cycle. The device will wake up, print how many times it has booted, increment the count, and go back to sleep for 10 seconds. We will use the RTC memory to preserve the boot count across deep-sleep cycles.
%%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans'}}}%% graph TD A(Start / Power-On Reset) --> B{Read 'boot_count'<br>from RTC Memory}; B --> C[Increment 'boot_count']; C --> D{Write 'boot_count'<br>back to RTC Memory}; D --> E[Print boot count &<br>wake-up reason]; E --> F["Configure wake-up source<br><i>(e.g., Timer for 10s)</i>"]; F --> G(Enter Deep Sleep); G -- 10 seconds later --> H(Timer Wake-up); H --> I{Device Reboots}; I --> B; %% Styling classDef start fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6; classDef process fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF; classDef rtc fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E; classDef sleep fill:#D1FAE5,stroke:#059669,stroke-width:1px,color:#065F46; class A,H,I start; class C,E,F process; class B,D rtc; class G sleep;
1. Code Implementation
Create a new project and place the following code in your main/app_main.c
file.
/* main/app_main.c */
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/rtc_io.h"
static const char *TAG = "DEEP_SLEEP_EXAMPLE";
// Use RTC_DATA_ATTR to place data in RTC memory.
// This memory persists across deep-sleep cycles.
RTC_DATA_ATTR int boot_count = 0;
void app_main(void)
{
// Increment the boot count and print it.
boot_count++;
ESP_LOGI(TAG, "Woke up! Boot count: %d", boot_count);
// Check the reason for waking up
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
ESP_LOGI(TAG, "Wakeup caused by: %s",
wakeup_cause == ESP_SLEEP_WAKEUP_TIMER ? "Timer" : "Other");
// --- Configure the next wake-up ---
const int deep_sleep_sec = 10;
ESP_LOGI(TAG, "Entering deep sleep in 2 seconds for %d seconds.", deep_sleep_sec);
// Enable wake-up from the timer
esp_sleep_enable_timer_wakeup(deep_sleep_sec * 1000000);
// Short delay to allow log messages to be sent
vTaskDelay(pdMS_TO_TICKS(2000));
// Enter deep sleep mode. The device will now reboot after the timer expires.
esp_deep_sleep_start();
}
2. Build, Flash, and Run
- Configure, Build, and Flash: Use the standard process. No special
menuconfig
options are needed for this basic example.idf.py build flash -p /dev/ttyUSB0
- Monitor the Output: Open the ESP-IDF monitor.
idf.py monitor -p /dev/ttyUSB0
- Observe the Cycle: You will see the following sequence repeat every 10 seconds. Notice how the
boot_count
increments each time, proving that its value is being preserved in RTC memory.
I (310) DEEP_SLEEP_EXAMPLE: Woke up! Boot count: 1
I (310) DEEP_SLEEP_EXAMPLE: Wakeup caused by: Other // "Other" is the cause for the very first power-on boot
I (320) DEEP_SLEEP_EXAMPLE: Entering deep sleep in 2 seconds for 10 seconds.
ets_main.c: ... // Device goes to sleep, connection is lost
// --- 10 seconds later ---
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
...
I (310) DEEP_SLEEP_EXAMPLE: Woke up! Boot count: 2
I (310) DEEP_SLEEP_EXAMPLE: Wakeup caused by: Timer
I (320) DEEP_SLEEP_EXAMPLE: Entering deep sleep in 2 seconds for 10 seconds.
Common Mistakes & Troubleshooting Tips
Mistake / Issue | Symptom(s) | Troubleshooting / Solution |
---|---|---|
High Deep-Sleep Current | Battery drains much faster than expected. Measured current is in mA instead of µA. |
– Check for floating GPIOs. Configure unused pins as disabled or with pull-ups/downs. – Use rtc_gpio_isolate() for specific pins. – Ensure external sensors/modules are also in their low-power modes. |
Fails to Wake from GPIO | Device enters sleep and never wakes up from a button press or external trigger. |
– Verify you are using an RTC-capable GPIO. Check your board’s pinout. – Ensure the wake-up level (e.g., HIGH/LOW) is correct. – Check external circuit for proper pull-up/down resistors to prevent floating states. |
State Lost After Wake-up | Variables (like counters or flags) reset to their default values after waking from deep sleep. |
– Remember: Deep sleep is a reboot. All data in main RAM is lost. – Store persistent data in RTC memory using the RTC_DATA_ATTR macro. – For larger data, use NVS (Non-Volatile Storage) in flash. |
Inaccurate Current Measurement | Multimeter shows 0 µA or a wildly incorrect value during deep sleep. |
– You cannot measure µA-level current through a USB port. – Power the board directly via its 3.3V and GND pins. – Place a high-precision multimeter (in µA or mA mode) in series with the 3.3V line. |
Exercises
- Wake Up with a Button: Modify the practical example to wake up from an external button press instead of a timer. Use
esp_sleep_enable_ext0_wakeup()
and connect a push button to a valid RTC GPIO pin. The device should sleep indefinitely until the button is pressed. - Power Consumption Measurement: If you have access to a multimeter with a µA range, set up the deep-sleep project and measure the actual current consumption of your specific ESP32 board. Power the board directly on its 3.3V pin. Compare your measured value to the datasheet value.
- Conditional Wake-Up Logic: Combine the timer and GPIO wake-up sources. Configure the device to wake up either every 5 minutes OR when a button is pressed, whichever comes first. In the
app_main
, useesp_sleep_get_wakeup_cause()
to log which event triggered the wake-up.
Summary
- Effective power management is essential for battery-operated IoT devices.
- ESP-IDF provides four main power states: Active, Modem-Sleep, Light-Sleep, and Deep-Sleep, with deep sleep offering the lowest power consumption.
- Data can be preserved across deep-sleep cycles by storing it in RTC memory.
- Devices can be woken by various sources, including timers, GPIOs, and the ULP co-processor.
- Newer RISC-V-based variants (C3, C6, H2) generally offer the best deep-sleep performance.
- The ESP32-H2 is the most power-efficient variant for low-power mesh networking, while the ESP32-S2/S3 are ideal for applications requiring ULP processing.
Further Reading
- ESP-IDF Power Management Documentation: The official and most detailed guide.
- ESP32 Variant Datasheets: Always consult the official datasheet for the most accurate power consumption figures for your specific chip.
- ULP Co-processor Programming Guide: For advanced applications on S2/S3.