Chapter 5: Power Modes

Arduino (AVR) Sleep Modes

AVR microcontrollers provide six sleep modes, controlled via the avr/sleep.h and avr/power.h headers. Each mode shuts down progressively more hardware.

The Six Modes

Mode CPU I/O Clk Flash Timer ADC Watchdog Wake Sources
Idle Off On On On On On Any interrupt
ADC Noise Reduction Off Off On Off* On On ADC complete, TWI, INT0, watchdog
Power-save Off Off Off Timer2 only Off On Timer2, TWI, INT0/1, watchdog
Power-down Off Off Off Off Off On TWI addr, INT0/1, watchdog
Standby Off Off Off Off Off On INT0/1, watchdog (oscillator stays running)
Extended standby Off Off Off Timer2 only Off On As Power-save

Power-down is the deepest and most commonly used sleep mode. It stops almost everything and reduces current to ~0.1–1 µA (plus leakage).

Using Sleep on AVR

#include <avr/sleep.h>
#include <avr/interrupt.h>

void goToSleep() {
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sei();                 // enable interrupts (wake source)
    sleep_cpu();           // enter sleep — execution stops here
    sleep_disable();       // execution resumes here after wake
}

// External interrupt on INT0 (pin 2) to wake
ISR(INT0_vect) {
    // just wake, no action needed
}

Reducing Current Further

Even in Power-down mode, the Brown-Out Detector (BOD) and the ADC can consume current. Disable them before sleeping:

#include <avr/power.h>

// Disable ADC
ADCSRA &= ~(1 << ADEN);

// Disable BOD during sleep (must be done right before sleep_cpu)
MCUCR |= (1 << BODS) | (1 << BODSE);
MCUCR &= ~(1 << BODSE);
sleep_cpu();

With BOD and ADC disabled, an ATmega328P in Power-down can draw as little as 0.1 µA at 3.3 V.


ESP32 Power Modes

The ESP32 has more sophisticated power management, handled by the IDF power management framework (which Arduino-ESP32 exposes).

Active Mode

All cores running at full speed (up to 240 MHz). WiFi/BT radio active.

Configuration Current
CPU 240 MHz + WiFi TX ~240 mA
CPU 240 MHz, WiFi idle ~80 mA
CPU 80 MHz, no radio ~20 mA

Modem Sleep

The radio is shut down between DTIM beacon intervals. The CPU keeps running. Useful when WiFi is needed but not continuously.

// Enable modem sleep (Arduino-ESP32)
WiFi.setSleep(true);

Light Sleep

The CPU is halted. RAM and peripheral state are preserved. Wake latency is ~1 ms.

#include "esp_sleep.h"

// Wake after 5 seconds
esp_sleep_enable_timer_wakeup(5000000ULL);  // microseconds
esp_light_sleep_start();
// execution continues here after wake

Deep Sleep

The main CPU and most peripherals are powered off. Only the RTC module, RTC memory, and optionally the ULP co-processor remain active.

#include "esp_sleep.h"

RTC_DATA_ATTR int bootCount = 0;

void setup() {
    Serial.begin(115200);
    bootCount++;
    Serial.printf("Boot #%d\n", bootCount);

    // Sleep for 30 seconds
    esp_sleep_enable_timer_wakeup(30 * 1000000ULL);
    esp_deep_sleep_start();
    // never reaches here
}

ULP Co-Processor

The Ultra-Low Power (ULP) co-processor is a small FSM-based processor that runs from RTC Slow Memory during deep sleep. It can:

This allows the main CPU to stay in deep sleep while the ULP monitors a sensor — consuming only ~100 µA total.


Wake-Up Sources (ESP32)

Source Light Sleep Deep Sleep Notes
Timer (RTC) Yes Yes Most common
ext0 (single GPIO) Yes Yes One GPIO, any level
ext1 (multiple GPIO) Yes Yes Multiple GPIOs, any-high or all-low
Touch sensor Yes Yes Capacitive touch pads
ULP program Yes Yes ULP sets wake flag
UART Yes No Character received
I2C Yes No Address match
// Wake on GPIO 33 going HIGH (deep sleep)
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 1);

// Wake if GPIO 32 or GPIO 33 goes HIGH
esp_sleep_enable_ext1_wakeup((1ULL << 32) | (1ULL << 33),
                              ESP_EXT1_WAKEUP_ANY_HIGH);

Determining Wake Cause

After waking from deep sleep, identify why:

esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
switch (cause) {
    case ESP_SLEEP_WAKEUP_TIMER:   Serial.println("Timer"); break;
    case ESP_SLEEP_WAKEUP_EXT0:    Serial.println("EXT0 GPIO"); break;
    case ESP_SLEEP_WAKEUP_EXT1:    Serial.println("EXT1 GPIO"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Touch"); break;
    default: Serial.println("Power-on or reset"); break;
}

Previous: ROM and Flash Storage Next: Power Optimization Home