Skip to content

How to Use ESP32 Deep Sleep Mode

DodaTech Updated 2026-06-24 4 min read

In this tutorial, you'll learn about How to Use ESP32 Deep Sleep Mode. We cover key concepts, practical examples, and best practices.

The Problem

You put the ESP32 into deep sleep to save battery, but the power consumption is still too high, the device does not wake up, or it resets immediately after waking. Deep sleep configuration is error-prone and incorrect settings drain the battery unnecessarily.

Quick Fix

Fix 1: Basic Deep Sleep with Timer Wake

WRONG โ€” not keeping the wake stub in RTC memory:

void loop() {
    // (never called because setup runs, then deep sleep is entered)
}

void setup() {
    Serial.begin(115200);
    esp_deep_sleep_start();  // enters sleep immediately
}
// (wakes up and resets from setup, but no timer was configured)

RIGHT โ€” configure the wake timer first:

#include <esp_sleep.h>

void setup() {
    Serial.begin(115200);
    Serial.println("Woke up!");

    // Configure timer to wake after 10 seconds
    esp_sleep_enable_timer_wakeup(10 * 1000000);  // microseconds

    Serial.println("Entering deep sleep");
    Serial.flush();
    esp_deep_sleep_start();
}
// Output (repeated every 10 seconds):
// Woke up!
// Entering deep sleep

Fix 2: External Wake from GPIO

WRONG โ€” using any GPIO without checking RTC compatibility:

esp_sleep_enable_ext0_wakeup(GPIO_NUM_5, 1);  // GPIO 5 is not RTC-capable
// ESP_ERR_INVALID_ARG: GPIO is not an RTC GPIO

RIGHT โ€” use only RTC-capable GPIOs:

// ESP32 RTC GPIOs: 0, 2, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 37, 38, 39

esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 1);  // wake on HIGH at GPIO 33
// or
esp_sleep_enable_ext1_wakeup(1ULL << GPIO_NUM_33, ESP_EXT1_WAKEUP_ANY_HIGH);

Fix 3: Touch Wake

esp_sleep_enable_touchpad_wakeup();
// (touch sensor values must be calibrated first)

touch_pad_init();
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
touch_pad_config(TOUCH_PAD_GPIO4_CHANNEL, 0);

Fix 4: Power Consumption Still High

WRONG โ€” entering deep sleep without disconnecting peripherals:

esp_deep_sleep_start();
// (external sensors, LEDs, and voltage regulators still draw power)

RIGHT โ€” measure and minimize current draw:

# Expected deep sleep current:
# ESP32 (no peripherals): ~5-10 ยตA
# With touch wake: ~50 ยตA
# With ULP co-processor: ~150 ยตA

# To achieve the lowest power:
# 1. Disconnect all external components during sleep
# 2. Use GPIO pin to control external power via MOSFET
# 3. Disable internal pull-ups: gpio_pullup_dis(GPIO_NUM_X)
# 4. Set unused GPIOs to LOW: gpio_set_level(GPIO_NUM_X, 0)
// Reduce power further:
esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
// (turns off RTC memory, wake stub cannot run)

Fix 5: Wake from Deep Sleep Only (No Software Reset)

WRONG โ€” cannot distinguish wake source from a cold boot:

void setup() {
    // (same code runs on first boot and after wake)
}

RIGHT โ€” check the wake cause:

void setup() {
    Serial.begin(115200);
    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();

    switch (cause) {
        case ESP_SLEEP_WAKEUP_TIMER:
            Serial.println("Woke up by timer");
            break;
        case ESP_SLEEP_WAKEUP_EXT0:
            Serial.println("Woke up by external signal");
            break;
        case ESP_SLEEP_WAKEUP_TOUCHPAD:
            Serial.println("Woke up by touch");
            break;
        default:
            Serial.println("Cold boot (not a wake)");
    }
}

Fix 6: Keep ULP Processor Running During Sleep

// The Ultra Low Power (ULP) co-processor can run sensor reads in deep sleep
ulp_set_wakeup_period(0, 100000);  // run every 100ms
esp_sleep_enable_ulp_wakeup();

Use DodaTech's Power Profiler to measure ESP32 deep sleep current draw and optimize battery life for production deployments.

Prevention

  • Use only RTC GPIOs for external wake.
  • Disconnect or power off external peripherals during sleep.
  • Measure actual current with a multimeter.
  • Use wake cause detection to differentiate cold boot from wake.
  • Keep wake stub code minimal (runs from RTC memory).

Common Mistakes with deep sleep

  1. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  2. Using return to exit a function early instead of wrapping a pure value in the monad
  3. Mixing let bindings with <- bindings in do notation, producing type errors

These mistakes appear frequently in real-world ESP32 code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What is the difference between deep sleep and light sleep?

Deep sleep turns off the CPU and most RAM, keeping only RTC memory alive. Current ~10 ยตA. Light sleep pauses the CPU but keeps RAM powered, current ~0.5 mA. Deep sleep is for battery-operated devices with infrequent wake cycles.

Why does the ESP32 reset instead of waking from deep sleep?

The wake pin may be triggered by noise or the wake level was already high before sleep. Use esp_sleep_enable_ext0_wakeup with the opposite level, or debounce the wake signal externally with an RC circuit.

Can the ESP32 wake from deep sleep on a specific day/time?

The RTC timer wakes at precise intervals, not absolute time. For calendar-based wake, use an external RTC module (DS3231) with an alarm output connected to an RTC GPIO wake pin. The ESP32 does not maintain UTC time in deep sleep.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro