Boards & DIY · intermediate

How do you run an ESP32 on batteries?

ESP32 power modes and datasheet currents, wake sources, the ULP coprocessor, why boards draw more than chips, brownouts and estimating battery life.

Three lithium cells on a table

Photo: Deepak Rastogi / Unsplash

After reading this article you will be able to:

  • Read the ESP32 power-mode table and know what stays powered in light sleep, deep sleep and hibernation
  • Explain why a development board draws far more than the chip and what causes a brownout reset
  • Estimate battery life from wake time, wake current and sleep current with a simple formula
On this page
  1. What power modes does the ESP32 have?
  2. What can wake an ESP32 from deep sleep?
  3. What does the ULP coprocessor do?
  4. Why does a development board draw more than the chip?
  5. What does “Brownout detector was triggered” mean?
  6. How do you estimate battery life?
  7. Where to go next

An ESP32 runs on batteries by spending almost all of its time in deep sleep, where the classic chip draws 10 µA with only its RTC timer and RTC memory powered, according to the ESP32 datasheet, and waking briefly to measure and transmit. The radio is the expensive part: Wi-Fi reception alone takes 95 to 100 mA. Battery life is therefore decided less by the sleep current than by how often the device wakes, how long it stays awake and what else on the board keeps drawing current while the chip sleeps.

This guide walks through the power modes, the ways to wake the chip, the ultra-low-power coprocessor, the gap between chip and board, the brownout message that puzzles many first designs, and a method to estimate battery life without guessing.

What power modes does the ESP32 have?

The classic ESP32 datasheet defines five modes. Each one switches off more of the chip and needs more work to get back to running code.

ModeWhat keeps runningTypical current (ESP32 datasheet)
ActiveCPU and radio95 to 100 mA receiving, up to 240 mA transmitting 802.11b at full power
Modem-sleepCPU, radio off20 to 68 mA depending on clock and cores
Light-sleepCPU paused, RTC and ULP running0.8 mA
Deep-sleepRTC timer, RTC memory, optionally the ULP10 µA, or 150 µA with the ULP powered
HibernationOne RTC timer and some RTC GPIOs5 µA

With the chip powered off through its enable pin, the datasheet gives 1 µA. When Wi-Fi is enabled, the chip moves between active and modem-sleep on its own, which is why a connected ESP32 never drops to the light-sleep figure unless the application configures automatic light sleep.

ESP32 power modes and typical current Five power modes of the classic ESP32, from Active to Hibernation, with what stays powered in each and the typical current from the ESP32 datasheet on a logarithmic scale: 95 to 100 mA receiving and up to 240 mA transmitting, 20 to 68 mA in modem-sleep, 0.8 mA in light-sleep, 10 microamps in deep-sleep and 5 microamps in hibernation. MODE WHAT STAYS ON TYPICAL CURRENT, LOG SCALE Active CPU and radio on, transmitting or receiving 95-100 mA RX up to 240 mA TX Modem-sleep CPU on, radio off, clock 80 to 240 MHz 20-68 mA Light-sleep CPU paused, state kept, RTC and ULP running 0.8 mA Deep-sleep RTC timer and memory, ULP optional (150 µA) 10 µA Hibernation One RTC timer and some RTC GPIOs 5 µA Each step down cuts the current and makes waking up slower: deep sleep restarts the firmware. Typical values for the chip alone (ESP32 datasheet v5.3); a development board adds its own consumption.
ESP32 power modes from the classic ESP32 datasheet: each step down switches off more of the chip, cuts the current and makes waking up more expensive.

Newer chips have lower floors. The datasheets give deep-sleep currents of 5 µA for the ESP32-C3, 7 µA for the ESP32-C6 and ESP32-H2, 7 to 8 µA for the ESP32-S3 and 12 µA for the ESP32-C5, all with the RTC timer and low-power memory kept on.

What can wake an ESP32 from deep sleep?

The ESP-IDF sleep modes documentation lists the wake sources for the classic ESP32: the RTC timer, a single RTC GPIO at a chosen level (ext0), several RTC GPIOs combined (ext1), the touch sensor, the ULP coprocessor and, through a separate GPIO wake-up call, pins in the RTC power domain. UART wake-up works only from light sleep.

Waking from deep sleep is a restart. The CPU and most RAM were powered off, so the bootloader runs and the application starts from the top. Variables marked RTC_DATA_ATTR live in RTC memory and survive, which is how firmware keeps a counter, a buffer of readings or the last Wi-Fi channel between wakes. Wi-Fi and Bluetooth connections do not survive either light or deep sleep; the documentation says to stop the radio before sleeping and reconnect afterwards. A device that must stay associated with an access point uses modem-sleep with automatic light sleep instead, at a much higher average current.

One easy mistake: a GPIO with an internal pull-up connected to external circuitry can leak current through the sleep. The documentation recommends calling rtc_gpio_isolate() on such pins before entering deep sleep.

What does the ULP coprocessor do?

The ultra-low-power (ULP) coprocessor is a small processor that keeps running while the main cores sleep. It can read sensors and peripherals and wake the main CPU only when something interesting happens, such as a value crossing a threshold. The ULP documentation describes three generations: the ULP-FSM on the ESP32, S2 and S3, programmed in assembly; the ULP-RISC-V on the S2 and S3, programmed in C; and the LP core on the C5, C6 and P4, a RISC-V core with wider access to memory and peripherals.

The ULP is not free. On the classic ESP32, deep sleep with the ULP powered on rises from 10 µA to 150 µA, and the datasheet quotes 100 µA for a “sensor-monitored pattern” with the ADC at a 1% duty cycle. The ULP pays off when it saves wake-ups: checking a door contact or a water level a few times a second costs far less than booting the main CPU and the radio each time.

Why does a development board draw more than the chip?

The datasheet figures describe the chip alone. A development board adds parts that keep drawing current while the chip sleeps: a linear voltage regulator with its own quiescent current, a USB-to-UART bridge, a power LED, pull-up resistors and whatever sensors are attached. Memory counts too. The ESP32-S3 datasheet tells you to add the PSRAM’s own consumption to its light-sleep figure, for example 140 µA for 8 MB of octal PSRAM at 3.3 V.

The result is that a board that should sleep at 10 µA can draw many times that figure, and the battery estimate built on the datasheet number is off by an order of magnitude. For a battery product, choose or design a board with a low-quiescent regulator, no always-on LED and a USB bridge powered only from USB, and switch sensors off through a GPIO or a load switch. Then measure the whole board, with an instrument that resolves microamps and captures the short peaks of the wake phase.

What does “Brownout detector was triggered” mean?

The brownout detector watches the supply voltage and resets the chip when it falls below a safe level. The ESP-IDF fatal errors page says the chip prints “Brownout detector was triggered” and resets, and that the detector is enabled by default and configured through CONFIG_ESP_BROWNOUT_DET and CONFIG_ESP_BROWNOUT_DET_LVL_SEL.

The usual trigger is a supply that cannot follow the current peaks of Wi-Fi transmission. Espressif’s hardware design guidelines warn that the sudden current increase when the chip transmits can collapse the power rail, and ask for a 3.3 V supply of at least 500 mA with at least 10 µF of capacitance at the power entrance. Common culprits are long thin USB cables, weak USB ports, undersized regulators, batteries near the end of their charge and coin cells, which cannot deliver Wi-Fi peak currents. Fix the supply rather than disabling the detector, which only hides the symptom. For supplies that rise or fall slowly, such as solar or battery charging circuits, the same guidelines recommend a supervisor chip on the enable pin with a threshold around 3.0 V.

How do you estimate battery life?

Split the device’s cycle into a wake phase and a sleep phase, measure each on the real board, and average:

I_avg = (I_wake × t_wake + I_sleep × t_sleep) / (t_wake + t_sleep)
life (hours) = usable capacity (mAh) / I_avg (mA)

I_wake and t_wake cover everything from wake-up to sleep: boot, sensor reading, Wi-Fi association, DHCP, the TLS handshake and the MQTT publish. I_sleep is the whole-board sleep current, not the datasheet figure. “Usable capacity” is lower than the label: derate it for self-discharge, cold temperatures and the voltage at which your regulator stops working.

The formula shows where the effort should go. A full day of deep sleep at the datasheet’s 10 µA is 0.24 mAh, the same charge as about nine seconds of Wi-Fi reception at 100 mA. Once the board’s sleep current is under control, cutting the time awake matters most: send less often, batch several readings in RTC memory and transmit them together, avoid a full Wi-Fi scan on every wake, and keep the TLS session short. If the wake phase cannot shrink enough, the radio is the wrong one, and Bluetooth LE, Thread or LoRaWAN will do better than Wi-Fi.

Where to go next

Topics: ESP32, deep sleep, battery life, low power, hardware

Diagram