The puzzle
The datasheet promises a sleep current of a few microamps. Your meter, in series with the board, reads 400 µA, and the battery that should last years is flat in months. Is the meter wrong, is the datasheet wrong, or is something on the board awake that nobody asked to be? Before you can reduce power you have to measure it, and measuring a current that swings from microamps to tens of milliamps a thousand times a day is harder than it looks.
STEP 1
Power, energy and charge
Three quantities get mixed up. Power is the rate of using energy, , in watts. Energy is power over time, , in joules or watt-hours. Charge is current over time, , in coulombs, and it is what a battery’s capacity rating counts: one milliamp-hour is C. A 1000 mAh cell holds 3600 C; its energy depends on the voltage at which that charge is delivered, roughly capacity times nominal voltage.
For a device fed from a regulator whose input current tracks its output current, charge is the natural bookkeeping unit, and battery life is simply capacity divided by the average current.
STEP 2
Average current from a profile
A battery-powered device spends almost all of its time in one state and briefly visits others. Over one repeating period , each phase draws a current for a time , and the average is
The numerator is the charge per period. Written this way it shows which phase to attack: the one with the largest , which is often the long, quiet sleep rather than the dramatic radio burst.
↑ This step uses the figure at the top of the page.
The life estimate is an upper bound. The charge a cell delivers depends on the current drawn and the temperature, the device stops when the voltage falls below what its regulator needs rather than when the cell is empty, and cells lose charge on the shelf. The datasheet of the cell gives those effects; the formula tells you where the device’s own charge goes.
STEP 3
Measuring the current
The standard method puts a small shunt resistor in the supply line and measures the voltage across it: . An ammeter does the same internally, so everything below applies to it too. Two limits pull the resistor in opposite directions. The sleep current must produce a voltage the instrument can resolve, so must be large enough; the active current must not drop so much voltage (the burden voltage) that the device misbehaves, so must be small enough:
A device that sleeps at 10 µA and transmits at 50 mA spans a ratio of 5000; many span far more.
The simplest current measurement puts a small resistor in the supply line and measures the voltage across it. The same resistor must give a readable voltage at a few microamps in sleep and must not drop so much voltage at tens of milliamps that the device browns out. The instrument floor (50 µV) and the allowed drop (3.3 V down to 3.0 V) are illustrative. When no resistor satisfies both, use range switching, two measurements, or an instrument built for the job.
Dedicated current-shunt monitors make the arithmetic concrete. Linux’s driver for the INA226 converts its signed 16-bit shunt-voltage register at 400 counts per millivolt, so one count is 2.5 µV and the register tops out at 32 767 × 2.5 µV ≈ 81.9 mV. That is a resolution, not an accuracy: offset and noise, which the chip’s datasheet specifies, are larger than one count. Tools built for profiling low-power devices switch ranges automatically or use several shunts; with ordinary instruments the practical answer is to measure the sleep and active phases separately.
Averaging is the other trap. A handheld meter typically updates a few times a second and produces some kind of average over its sampling window; a 10 ms, 20 mA burst once a minute may be missed entirely, or smeared in a way that depends on the meter. To see a pulsed profile, put an oscilloscope across the shunt (with a differential probe or a current probe), mark the firmware phases with a GPIO toggle as in unit 6, and integrate the current over a period to get the charge.
STEP 4
Finding the current nobody meant to draw
When sleep current is too high, measure it with the firmware held in its sleep state (a test build that sleeps and never wakes), then eliminate suspects one at a time:
- Pull-ups and pull-downs held against their input. A 10 kΩ pull-up with the switch closed draws 330 µA (unit 1, lesson 3); an internal pull-up held low costs tens of microamps (unit 7, lesson 3).
- Floating inputs. A CMOS input left between the logic levels has both input transistors partly on and draws current (unit 7, lesson 3).
- Outputs driving loads. An LED, a sensor’s supply pin or a pin driving against an external pull stays on in Sleep and Stop, where the STM32F4 keeps every pin in its run-mode state.
- Clocks and blocks left on. On the RP2040, the
CLOCKS_ENABLED0/1registers report the state of each clock enable; on the STM32F4 the flash can be powered down during Stop withHAL_PWREx_EnableFlashPowerDown(). - Other chips. Regulators, sensors and radios on the same rail have their own quiescent currents, often larger than the microcontroller’s.
STEP 5
Worked example: where does the charge go?
A node sleeps at 10 µA, wakes every 60 s to measure for 20 ms at 5 mA, and sends a 10 ms radio burst at 20 mA (illustrative numbers, the figure’s defaults). Per period:
| phase | current | time | charge |
|---|---|---|---|
| sleep | 10 µA | 59.97 s | 599.7 µC |
| measure | 5 mA | 20 ms | 100 µC |
| radio | 20 mA | 10 ms | 200 µC |
| total | 60 s | 899.7 µC |
This ignores the battery’s self-discharge and the loss of capacity at pulse loads; over years, self-discharge (expressed as an equivalent current, it can match or exceed 15 µA for some chemistries) decides whether 7.6 years is achievable at all. Sleep takes two-thirds of the charge even though it draws 2000 times less current than the radio. Now suppose the board really sleeps at the 400 µA from the opening: sleep charge becomes 23 988 µC per period, the average 404.8 µA, and the life about 2470 h, or 103 days. Halving the radio burst would change almost nothing; finding the 390 µA leak changes everything. Waking every 10 s instead of every 60 s with the original 10 µA sleep gives 399.7 µC per 10 s, 40.0 µA and about 2.9 years: there, the wake-ups dominate.
MYTHS AND FACTS
Common misconceptions
Battery life is capacity divided by the sleep current
It is capacity divided by the average current, which includes every wake-up.
The meter shows the average current
It shows what its own sampling and filtering make of a pulsed current, which can miss short bursts entirely.
Measuring does not change the circuit
The shunt or ammeter drops a burden voltage; at high currents that can brown out the device and change what you measure.
mAh is a measure of energy
It is charge. Energy needs the voltage as well.
Check yourself
Answer in your head, then open the card.
A device draws 2 mA for 50 ms every 5 s and 5 µA the rest of the time. What is the average current?
Charge per period: 2 mA × 0.05 s = 100 µC, plus 5 µA × 4.95 s = 24.75 µC, total 124.75 µC. Divided by 5 s: about 25 µA.
With a shunt monitor that resolves 2.5 µV per count and reads at most 81.9 mV, what shunt gives 10 counts at a 10 µA sleep current, and can it also measure 50 mA?
10 counts is 25 µV, so R = 25 µV / 10 µA = 2.5 Ω. At 50 mA that shunt drops 125 mV, beyond the 81.9 mV range; the largest shunt that keeps 50 mA in range is 81.9 mV / 50 mA ≈ 1.6 Ω. One shunt cannot do both: use two ranges or measure the phases separately.
Why can a board’s sleep current rise when a debug probe or a USB-to-serial adapter is connected?
Their signal lines can drive the microcontroller’s pins, or hold pulled-up lines low, so current flows through pins and pull resistors that would otherwise carry none. Measure with them disconnected, or at least account for them.
The radio burst takes 22 % of the charge per period and sleep 67 %. Which should you optimise first, and by how much can halving the radio burst improve battery life at most?
Sleep. Halving the radio’s charge removes 11 % of the total, so life improves by at most 1/0.89 ≈ 12 %; halving the sleep current would remove about a third of the charge.
Sources (4)
- Linux kernel, Documentation/hwmon/ina2xx.rst — “The INA226 is a current shunt and power monitor with an I2C interface. The INA226 monitors both a shunt voltage drop and bus supply voltage”; the shunt value is set in micro-ohms; sysfs channels for shunt voltage, bus voltage, current and power; the update interval is the conversion times “multiplied by the averaging rate”
- Linux kernel, drivers/hwmon/ina2xx.c — the shunt-voltage register is read as a signed 16-bit value and divided by shunt_div to give millivolts: shunt_div = 100 for the INA219 (10 µV per count) and 400 for the INA226 (2.5 µV per count); current_lsb = shunt_voltage_lsb / R_shunt
- Raspberry Pi Ltd, pico-sdk 1.5.1, rp2040/hardware_regs/include/hardware/regs/clocks.h — CLOCKS_ENABLED0/ENABLED1 “indicates the state of the clock enable” for each clock destination; SLEEP_EN0/1 and WAKE_EN0/1 reset to all enabled
- STMicroelectronics, stm32f4xx-hal-driver, Src/stm32f4xx_hal_pwr.c — “To minimize the consumption In Stop mode, FLASH can be powered off before entering the Stop mode using the HAL_PWREx_EnableFlashPowerDown() function”; in Sleep and Stop “all I/O pins keep the same state as in Run mode”