Deep Sleep Power Optimization
Deep Sleep Power Optimization
Overview
Section titled “Overview”This section covers ESP32 deep sleep mode configuration and optimization for achieving ultra-low power consumption in battery-powered IoT button applications. By the end of this section, you will be able to:
- Understand ESP32 power modes and their current consumption
- Configure deep sleep with wake-on-button-press
- Measure and optimize sleep current
- Explain the sleep/wake cycle for button applications
Prerequisites
Section titled “Prerequisites”Before starting this section, please ensure:
- Completed 04-04. Button Circuit Design
- Basic understanding of ESP32 power management features
- Access to a multimeter for current measurements
Key Concepts
Section titled “Key Concepts”ESP32 Power Modes
Section titled “ESP32 Power Modes”The ESP32 offers multiple power modes with significantly different current consumption:
| Mode | Current (ESP32-C3) | Description | Use Case |
|---|---|---|---|
| Active (WiFi on) | ~60-80 mA | CPU running, WiFi connected | Normal operation |
| Active (WiFi off) | ~15-25 mA | CPU running, no radio | Local processing |
| Modem Sleep | ~3-5 mA | CPU running, WiFi idle | Brief pauses |
| Light Sleep | ~0.5-1 mA | CPU paused, can wake quickly | Short idle periods |
| Deep Sleep | ~5-10 µA | CPU off, RTC peripheral only | Extended idle |
| Hibernation | ~2.5 µA | RTC memory off, only RTC timer | Maximum savings |
For the IoT button, deep sleep is the key mode — the device spends nearly all its life in this state, waking only briefly to send a message when the button is pressed.
Deep Sleep Architecture
Section titled “Deep Sleep Architecture”In deep sleep mode:
- CPU is powered off
- Most RAM loses content (RTC slow memory retains data)
- WiFi/BT are powered off
- RTC peripherals remain active (GPIO, timer, ULP coprocessor)
- Wake-up sources remain monitored (GPIO, timer, touch sensor)
┌─────────────────────────────────────────────────────────┐│ Deep Sleep State ││ ││ ┌──────────────────┐ ┌──────────────────────────┐ ││ │ CPU (OFF) │ │ WiFi/BT (OFF) │ ││ └──────────────────┘ └──────────────────────────┘ ││ ││ ┌──────────────────┐ ┌──────────────────────────┐ ││ │ RTC Memory │ │ RTC Peripherals │ ││ │ (Retains data) │ │ (GPIO wake, Timer) │ ││ └──────────────────┘ └──────────────────────────┘ ││ ││ ┌──────────────────────────────────────────────────┐ ││ │ Main Memory (SRAM) — Content lost │ ││ └──────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────┘Wake-Up Sources for Button Application
Section titled “Wake-Up Sources for Button Application”| Wake-Up Source | Configuration | Button Applicability |
|---|---|---|
| EXT0 | RTC GPIO → level change | ✅ GPIO 2 → LOW wakes (button press) |
| EXT1 | Multiple RTC GPIOs → pattern | ⚠️ For multiple buttons |
| Timer | RTC timer → time elapsed | ✅ Periodic wake for status check |
| Touch | Capacitive touch sensor | ❌ Not needed for button |
| ULP | Ultra-low-power coprocessor | ❌ Overkill for simple button |
Implementation Steps
Section titled “Implementation Steps”Step 1: Configure Deep Sleep with GPIO Wake-Up
Section titled “Step 1: Configure Deep Sleep with GPIO Wake-Up”#include <esp_sleep.h>
// Pin definitionsconst int BUTTON_PIN = 2; // GPIO 2 for button (wake source)const int LED_PIN = D10; // Built-in LED (GPIO 10 on XIAO)
void setup() { Serial.begin(115200); delay(100); // Allow serial to initialize
// Check wake-up reason esp_sleep_wakeup_cause_t wake_reason = esp_sleep_get_wakeup_cause();
switch (wake_reason) { case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Woke by button press"); break; case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Woke by timer (should not happen in button mode)"); break; default: Serial.println("First power-on or unknown wake source"); break; }
// Brief LED indication pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, HIGH); delay(200); digitalWrite(LED_PIN, LOW);
// Execute button action performButtonAction();
// Go back to sleep Serial.println("Going to deep sleep..."); Serial.flush(); delay(100); // Allow serial output to complete
// Configure wake source esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, 0); // LOW = pressed
// Enter deep sleep esp_deep_sleep_start();}
void loop() { // Never reaches here}
void performButtonAction() { // Connect to WiFi and send MQTT message // This function will be detailed in sections 04-07 and 04-08 Serial.println("Button action executed");}Step 2: Configure RTC GPIO for Wake-Up
Section titled “Step 2: Configure RTC GPIO for Wake-Up”Not all GPIOs can wake the ESP32 from deep sleep. Compatible RTC GPIOs on XIAO ESP32-C3:
| GPIO | RTC Wake Compatible | Recommended For |
|---|---|---|
| GPIO 0 | Yes | BOOT button (not recommended) |
| GPIO 1 | Yes | Button |
| GPIO 2 | Yes | Button (recommended) |
| GPIO 3 | Yes | Button |
| GPIO 4 | Yes | Status LED |
| GPIO 5 | Yes | Status LED |
Step 3: Current Measurement Verification
Section titled “Step 3: Current Measurement Verification”To verify deep sleep current:
void setup() { // ... normal setup ...
// Measure and report before sleeping Serial.println("--- Power Report ---"); Serial.print("Active current: ~60-80 mA (WiFi on)\n"); Serial.print("Deep sleep current target: < 10 µA\n"); Serial.println("--------------------");
delay(50); esp_deep_sleep_start();}Measurement method:
- Set multimeter to µA range
- Disconnect power
- Connect multimeter in series between battery + and XIAO VIN
- Press button to wake; observe current during active period
- Wait for deep sleep; read µA value on multimeter
Expected measurement sequence:Time 0s: Wake → 60-80 mA (WiFi connect + MQTT publish)Time 3-5s: Action complete → preparing sleepTime 5s+: Deep sleep → ~5 µAPower Optimization Techniques
Section titled “Power Optimization Techniques”1. Disable Unused Peripherals
Section titled “1. Disable Unused Peripherals”void maximizePowerSaving() { // Disable WiFi before sleep (if not needed for next wake) WiFi.disconnect(true); WiFi.mode(WIFI_OFF);}2. Reduce Active Time
Section titled “2. Reduce Active Time”The most impactful optimization is minimizing the time spent in active mode:
// Fast path — minimize delays in active modevoid optimizedButtonAction() { unsigned long startTime = millis();
connectWiFi(); // ~1-3 seconds publishMQTT(); // ~500ms delay(10); // Allow MQTT to flush WiFi.disconnect(true);
Serial.print("Active time: "); Serial.print(millis() - startTime); Serial.println(" ms");
// Immediate deep sleep — no unnecessary delays}3. Use GPIO Pull-Down in Sleep
Section titled “3. Use GPIO Pull-Down in Sleep”For minimum sleep current, configure the button pin to avoid floating:
- Internal pull-up is sufficient for most cases
- For extremely low leakage, add a 10kΩ external pull-up resistor
4. Voltage Regulator Quiescent Current
Section titled “4. Voltage Regulator Quiescent Current”The XIAO’s onboard regulator has a quiescent current of approximately 2-3 µA. This is included in the total sleep current measurement and cannot be eliminated.
Verification
Section titled “Verification”- Deep sleep current measures < 10 µA
- Button press reliably wakes the device
- Active time is minimized (< 5 seconds per press)
- Device returns to deep sleep after action
- No spontaneous wake-ups without button press
Troubleshooting
Section titled “Troubleshooting”Issue 1: Higher Than Expected Sleep Current
Section titled “Issue 1: Higher Than Expected Sleep Current”Symptom: Sleep current > 50 µA
Possible Causes:
- GPIO floating (not configured as INPUT_PULLUP or OUTPUT)
- Serial monitoring enabled (some boards keep USB active)
- External components drawing current
- Capacitors leaking
Solution:
// Check all GPIOs are properly configured before sleepgpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT);gpio_set_level(GPIO_NUM_4, 0); // Set LOW to minimize leakage
gpio_set_direction(GPIO_NUM_5, GPIO_MODE_OUTPUT);gpio_set_level(GPIO_NUM_5, 0);Issue 2: Device Does Not Wake
Section titled “Issue 2: Device Does Not Wake”Symptom: Device in deep sleep, button press does nothing
Possible Causes:
- Wrong GPIO number for wake source
- Button connected to non-RTC GPIO
- Level configuration reversed (waking on HIGH instead of LOW)
Solution: Verify GPIO is in RTC wake range and test with:
// Temporarily test with timer wake-up insteadesp_sleep_enable_timer_wakeup(10 * 1000000); // Wake every 10 secondsBest Practices
Section titled “Best Practices”- ✅ Minimize active time — connect WiFi, publish MQTT, sleep immediately
- ✅ Disconnect WiFi before entering deep sleep
- ✅ Use RTC GPIO pins for wake sources
- ✅ Add serial flush before sleep to ensure complete output
- ❌ Do not use
delay()in setup unless necessary - ❌ Avoid leaving GPIO pins unconfigured
Summary
Section titled “Summary”- Deep sleep reduces current to ~5 µA — the key to 100+ day battery life
- GPIO EXT0 wake-up allows the button press to wake the ESP32 instantly
- Minimizing active time is the most critical optimization
- Regular current measurement verifies power optimization is working
- All peripherals should be disabled before entering deep sleep
References
Section titled “References”Target Audience: Alibaba.com IoT Pre-sales Engineers
Status: ✅ Completed