Back to Blog
Embedded Systems

ESP32 Deep Sleep Mastery: Cutting Power Consumption from 240mA to 10µA

The ESP32 has five power modes ranging from 240 mA active to 10 µA deep sleep. Understanding each mode, the wake-up sources, RTC memory persistence, and the ULP coprocessor is essential for any battery-powered IoT device.

May 15, 2024
14 min read
ESP32Deep SleepPower ConsumptionBattery Life

ESP32 Deep Sleep Mastery: Cutting Power Consumption from 240mA to 10µA

The ESP32 is a powerful chip — which means it consumes significant power when running at full tilt. WiFi transmission peaks at 240 mA. But deep sleep brings this to 10 µA, a 24,000× reduction. For battery-powered devices, the difference between getting this right and getting it wrong is the difference between a one-year battery life and a three-day battery life.

This guide covers every ESP32 sleep mode, all wake-up sources, RTC memory usage, and the ULP coprocessor for advanced low-power sensing.

ESP32 Power Mode Overview

| Mode | CPU | WiFi/BT | RTC Memory | Current | |---|---|---|---|---| | Active (WiFi Tx) | Running | On | Retained | 160–240 mA | | Modem Sleep | Running | Off | Retained | 3–20 mA | | Light Sleep | Paused | Off | Retained | 0.8 mA | | Deep Sleep | Off | Off | Retained | 10–150 µA | | Deep Sleep + ULP | Off | Off | Retained | 150 µA | | Hibernation | Off | Off | Lost | 2.5 µA |

For most IoT devices, deep sleep is the target mode between active periods.

Modem Sleep: WiFi Off, CPU Running

Modem sleep disables the WiFi/BT radio while keeping the CPU running. The RTOS continues running, timers fire, peripherals work. Use this when you need the CPU active (processing sensor data continuously) but do not need WiFi every second.

#include "esp_wifi.h"

// Enable automatic modem sleep — WiFi turns off between DTIM beacons esp_wifi_set_ps(WIFI_PS_MAX_MODEM);

// Or disable modem sleep for lowest latency (highest power) esp_wifi_set_ps(WIFI_PS_NONE);

Current drops from 160 mA to 3–20 mA depending on DTIM interval. Not sufficient for multi-year battery operation.

Light Sleep: CPU Paused, State Retained

Light sleep halts the CPU clocks and most peripherals. FreeRTOS tasks are paused. The system wakes on timer, GPIO, UART, or other sources, then resumes exactly where it left off — stack intact, task states intact. Wake latency is ~5 ms.

// Configure automatic light sleep in FreeRTOS idle hook
// Enable in sdkconfig: CONFIG_PM_ENABLE=y, CONFIG_FREERTOS_USE_TICKLESS_IDLE=y

// The tickless idle automatically enters light sleep when all tasks are blocked // No code changes required — just enable in sdkconfig

Current: ~0.8 mA. Better, but still 80× higher than deep sleep for long idle periods.

Deep Sleep: The Primary Battery-Saver

In deep sleep, the main CPU cores and most RAM are powered off. Only the RTC domain (RTC memory, RTC peripherals, RTC controller) remains powered. Wake causes a full reboot — app_main runs from the beginning.

#include "esp_sleep.h"

#define SLEEP_DURATION_SEC 60

void go_to_deep_sleep(void) { ESP_LOGI("SLEEP", "Entering deep sleep for %d seconds", SLEEP_DURATION_SEC);

// Configure wakeup source: timer esp_sleep_enable_timer_wakeup((uint64_t)SLEEP_DURATION_SEC * 1000000ULL);

// Optional: enable GPIO wakeup (e.g., button press) esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0); // Wake on GPIO0 LOW

// Enter deep sleep — does not return esp_deep_sleep_start(); }

void app_main(void) { // Determine wake reason esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();

switch (wakeup_reason) { case ESP_SLEEP_WAKEUP_TIMER: ESP_LOGI("BOOT", "Woke from timer"); break; case ESP_SLEEP_WAKEUP_EXT0: ESP_LOGI("BOOT", "Woke from GPIO button press"); break; default: ESP_LOGI("BOOT", "Power-on reset or unknown wakeup"); }

// ... do work, then sleep again go_to_deep_sleep(); }

RTC Memory: Preserving State Across Sleep

Since app_main runs fresh on every wake, any state you need to preserve across sleep cycles must live in RTC memory. RTC SLOW memory (8 KB) and RTC FAST memory (8 KB) both survive deep sleep.

// RTC_DATA_ATTR places variable in RTC slow memory
RTC_DATA_ATTR uint32_t boot_count         = 0;
RTC_DATA_ATTR float    last_temperature   = 0.0f;
RTC_DATA_ATTR uint8_t  pending_batch[120] = {0};  // 30 readings × 4 bytes
RTC_DATA_ATTR uint8_t  batch_index        = 0;

void app_main(void) { boot_count++; // Persists across sleep cycles

float temperature = read_temperature_sensor(); pending_batch[batch_index++] = (uint8_t)(temperature * 2); // Compressed

if (batch_index >= 30) { // Upload all 30 readings, then reset upload_batch_to_cloud(pending_batch, batch_index); batch_index = 0; }

esp_sleep_enable_timer_wakeup(10ULL * 60 * 1000000); // 10 min esp_deep_sleep_start(); }

RTC memory limitation: 8 KB total. Store only what you need — sensor readings, counters, state flags, pending upload data. Do not try to fit large buffers or strings.

Wake Stubs: Code That Runs Before Full Boot

Deep sleep wake stubs are functions stored in RTC fast memory that execute immediately on wakeup — before the full ESP-IDF boot process runs. Use them to make ultra-fast wake/decision/sleep decisions without the ~300 ms boot overhead.

#include "esp_attr.h"

RTC_DATA_ATTR uint32_t stub_counter = 0; RTC_DATA_ATTR bool do_full_boot = false;

// Stored in RTC fast memory — runs immediately on wakeup void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { esp_default_wake_deep_sleep(); // Required: clears wakeup flags

stub_counter++; if (stub_counter >= 12) { // Full boot every 12 wakeups (2 hours if 10-min interval) do_full_boot = true; stub_counter = 0; return; // Proceed to full app_main }

// Otherwise, go back to sleep immediately — no full boot esp_sleep_enable_timer_wakeup(10ULL * 60 * 1000000); esp_deep_sleep_start(); }

The wake stub can reduce effective wake time from 300 ms to under 1 ms for cycles where you do not need full connectivity.

ULP Coprocessor: Sensing During Sleep

The ULP (Ultra-Low Power) coprocessor is an 8 MHz RISC processor that runs while the main CPU is in deep sleep, consuming only ~150 µA total. It can read GPIOs, communicate via I2C/SPI via bit-banging, and wake the main CPU only when a threshold is crossed.

// ULP program in ULP assembly (simplified concept)
// Reads ADC, stores result in RTC memory, wakes main CPU if threshold exceeded

#include "ulp_main.h"

RTC_DATA_ATTR uint32_t ulp_adc_result = 0; RTC_DATA_ATTR uint32_t ulp_threshold = 2048; // ~1.65V on 3.3V ref

void init_ulp_program(void) { // Load and start ULP binary (compiled from ULP assembly) ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));

// Set ULP wakeup period: sample every 1 second ulp_set_wakeup_period(0, 1000000); // 1 second in microseconds

// Start ULP — main CPU can now deep sleep ulp_run(&ulp_entry - RTC_SLOW_MEM); esp_sleep_enable_ulp_wakeup(); esp_deep_sleep_start(); }

The ULP enables truly event-driven wake — the main CPU only powers on when something interesting happens (a threshold crossed, a motion detected), not on a fixed timer.

Real Current Measurements

Measured on an ESP32-WROOM-32E with a Nordic PPK2 power profiler:

  • Active + WiFi Tx: 220 mA peak, 130 mA average during connection
  • Modem sleep: 15 mA
  • Light sleep: 0.9 mA
  • Deep sleep: 10–12 µA (verified, matches datasheet)
  • Deep sleep + ULP ADC sampling at 1 Hz: 145 µA
  • For the battery life calculation and a complete worked example showing how these numbers translate to multi-year operation, see our guide on [IoT battery life optimization](/iot-battery-power-optimization).

    [Contact Code Caracal](/contact) — we build production firmware for clients across 15+ countries.

    Written by CodeCaracal Engineering

    We write from production experience — every technique in our articles has been deployed to real clients. No academic theory.

    More Articles

    Business · 12 min read

    IoT Device Compliance: FCC, CE, and Product Certification Guide for Hardware Startups

    Business · 11 min read

    What to Look for When Hiring an IoT Development Partner: 8 Critical Criteria

    Business · 11 min read

    IoT MVP to Production: Realistic Timeline and Budget for Hardware Startups

    Business · 11 min read

    IoT Development Agency vs Building In-House: A Decision Framework for Founders

    IoT Dashboard · 13 min read

    Next.js IoT Analytics Dashboard: From Sensor Data to Production App

    Business · 11 min read

    How Much Does It Cost to Build an IoT Product in 2024? A Realistic Breakdown

    IoT Dashboard · 11 min read

    IoT Dashboard UX: Design Principles for Industrial Monitoring Interfaces

    IoT Dashboard · 12 min read

    Node.js WebSocket Server: The Real-Time Backend for IoT Dashboards

    Cloud & DevOps · 12 min read

    Containerizing IoT Backend Services with Docker: From Dev to Production

    IoT Dashboard · 14 min read

    Grafana + InfluxDB IoT Monitoring: Complete Production Setup Guide

    IoT Dashboard · 12 min read

    Building Real-Time IoT Dashboards with React and Recharts

    Cloud & DevOps · 13 min read

    CI/CD for Embedded Firmware: Automated Build, Test, and OTA Release Pipeline

    Mobile Development · 12 min read

    Flutter Offline-First IoT Apps: Hive + Sync Architecture That Works in the Field

    Cloud & DevOps · 14 min read

    Terraform for IoT Infrastructure: Provisioning AWS IoT Core, Lambda, and InfluxDB as Code

    Mobile Development · 10 min read

    Flutter IoT Alerts: Firebase Push Notifications for Device Events

    Cloud & DevOps · 12 min read

    Deploying IoT Backends on AWS: ECS Fargate vs Lambda vs EC2 Decision Guide

    Mobile Development · 11 min read

    Flutter + MQTT: Building Production IoT Mobile Apps That Scale

    Mobile Development · 13 min read

    Flutter BLE: Building a Bluetooth IoT Controller App from Scratch

    Cloud & DevOps · 13 min read

    AWS IoT Core vs Azure IoT Hub vs Google Cloud IoT: 2024 Honest Comparison

    IoT Engineering · 13 min read

    Kafka vs RabbitMQ for IoT: Choosing the Right Message Queue for High-Volume Telemetry

    IoT Engineering · 14 min read

    IoT System Testing: Unit, Integration, Hardware-in-the-Loop, and End-to-End

    IoT Engineering · 14 min read

    Predictive Maintenance with IoT Sensor Data: From Threshold to Machine Learning

    Embedded Systems · 14 min read

    IoT Bootloader Design: Secure Boot, A/B Partitions, and Reliable OTA Recovery

    IoT Engineering · 14 min read

    Multi-Tenant IoT Platform Architecture: Isolation, Scaling, and Data Partitioning

    Embedded Systems · 14 min read

    Memory Management in Embedded Firmware: Avoiding Heap Fragmentation and Stack Overflows

    IoT Engineering · 13 min read

    IoT Cost Optimization: How We Cut AWS IoT Bills by 60% Without Sacrificing Reliability

    IoT Engineering · 12 min read

    Edge Computing in IoT: When to Process On-Device vs In the Cloud

    IoT Engineering · 13 min read

    Digital Twins for IoT: Building a Virtual Mirror of Your Physical Devices

    IoT Engineering · 10 min read

    MQTT QoS 0, 1, and 2 Explained: Choosing the Right Level for IoT

    IoT Engineering · 14 min read

    IoT Monitoring and Observability: Metrics, Logs, and Distributed Tracing

    Embedded Systems · 14 min read

    Debugging Embedded Firmware: JTAG, GDB, Logic Analyzers, and Serial Tracing

    IoT Engineering · 12 min read

    WebSocket vs MQTT vs Server-Sent Events: Real-Time IoT Protocol Deep Dive

    Embedded Systems · 13 min read

    STM32 HAL vs Low-Level Drivers: When the Abstraction Costs You Too Much

    IoT Engineering · 13 min read

    IoT Data Pipeline: From Raw Sensor Reading to Live Dashboard in Under 100ms

    IoT Engineering · 13 min read

    Zero-Touch IoT Device Provisioning: Scaling from 10 to 100,000 Devices

    Embedded Systems · 13 min read

    UART vs SPI vs I2C: Choosing the Right Protocol for Sensor Integration

    IoT Engineering · 12 min read

    Real-Time IoT Alerting: From Simple Thresholds to ML Anomaly Detection

    Embedded Systems · 12 min read

    ESP32 Partition Table: Designing Flash Layout for Production Firmware

    IoT Engineering · 12 min read

    IoT Architecture Patterns: Hub-and-Spoke, Mesh, and Edge-Cloud Hybrid

    Embedded Systems · 13 min read

    IoT Battery Life Optimization: Engineering Devices That Last Years on a Single Charge

    IoT Engineering · 13 min read

    Time-Series Databases for IoT: InfluxDB vs TimescaleDB vs AWS Timestream

    Security · 14 min read

    Zero-Trust Security for Embedded IoT: Why Your Devices Are Probably Vulnerable

    Embedded Systems · 14 min read

    FreeRTOS on ESP32: Task Scheduling, Queues, and Resource Management for IoT

    IoT Engineering · 12 min read

    Building a Production IoT Gateway with Raspberry Pi and Node.js

    Embedded Systems · 13 min read

    ESP32 vs STM32: Choosing the Right Microcontroller for Your IoT Project

    Mobile Development · 10 min read

    Flutter + WebSocket: Building Real-Time IoT Dashboards That Don't Stutter

    IoT Engineering · 13 min read

    IoT Fleet Management at Scale: AWS IoT Core Device Registry and Provisioning

    IoT Engineering · 11 min read

    MQTT vs HTTP for IoT: Which Protocol Wins in Production?

    IoT Engineering · 12 min read

    ESP32 → MQTT → AWS IoT Core: The Production-Grade Architecture Guide

    Let's Build Together

    Got an IoT challenge?
    We've shipped it.

    Whether you need a fleet to track, a factory to monitor, or a farm to automate — our team has done it before and we'd love to build it with you. Typical response time: under 24 hours.

    No upfront commitment99.9% uptime SLANDA on requestFixed-price options