AVR microcontrollers provide six sleep modes, controlled via the avr/sleep.h and avr/power.h headers. Each mode shuts down progressively more hardware.
| 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).
#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
}
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.
The ESP32 has more sophisticated power management, handled by the IDF power management framework (which Arduino-ESP32 exposes).
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 |
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);
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
The main CPU and most peripherals are powered off. Only the RTC module, RTC memory, and optionally the ULP co-processor remain active.
setup() — use RTC_DATA_ATTR variables to persist state#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
}
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.
| 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);
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 |