Maximizing Battery Life in Embedded Systems: It's Harder Than It Looks
Getting an embedded device to run for months or years on a coin cell requires more than putting the processor to sleep. Here is what the engineering actually looks like.
Every product manager has asked the question: can we get a year out of this battery? The answer is almost always yes — in theory. In practice, achieving multi-month or multi-year battery life in an embedded system requires disciplined engineering across hardware, firmware, and system architecture. It is one of those problems that looks straightforward until you actually measure what is happening, and then it becomes humbling.
This article is about what that engineering actually looks like — the tools, the tradeoffs, and the surprises that show up when you start chasing microamps.
Start With a Power Budget
Before writing a line of firmware, you need a power budget. This is a spreadsheet — or at minimum a back-of-envelope calculation — that estimates the average current draw of every component in the system across every operating mode, weighted by the fraction of time spent in each mode.
A typical battery-powered sensor node might spend 99.9% of its time in deep sleep, wake briefly to take a measurement, transmit a packet over BLE, and go back to sleep. If your processor draws 10 mA active and 2 µA in deep sleep, and you wake up for 10 ms every 10 seconds, your average current from the processor alone is roughly (10 mA × 0.001) + (2 µA × 0.999) = 12 µA. That is a reasonable number. But add a radio that pulls 15 mA for 5 ms per wake cycle, a sensor that needs 1 mA for 50 ms to stabilize, and a voltage regulator with 50 µA quiescent current, and your average quickly climbs past 100 µA — cutting your theoretical battery life by nearly an order of magnitude.
The power budget forces you to make these tradeoffs explicit before you have hardware to measure. It also tells you where to focus your optimization effort: fix the biggest contributors first.
Hardware Design: Making Sure Peripherals Can Actually Be Powered Down
Firmware optimization can only take you so far if the hardware design does not give the processor a way to cut power to external components. This is one of the most common and expensive mistakes in low-power product design — it gets discovered late, when the PCB is already built and the firmware team is trying to optimize a system the hardware was never designed to support.
The core principle is simple: every significant current consumer on the board needs a way to be disconnected from its supply when not in use. In practice this means designing load switches — small P-channel MOSFETs or dedicated load switch ICs — into the power rails feeding sensors, displays, radios, and other peripherals. The processor controls the gate of the switch via a GPIO, pulling the entire peripheral rail down to zero when it is not needed.
Load switch ICs from manufacturers like Texas Instruments (TPS22xxx series) and Maxim offer fast turn-on times, low on-resistance, and built-in soft-start to prevent large inrush currents from upsetting the supply rail. For multi-rail designs, a dedicated power sequencing IC can manage the order and timing of rail enable and disable automatically.
I2C and SPI sensors present a subtle problem that is easy to miss. Even when a sensor is nominally powered down, if the processor's GPIO pins remain driven (for example, an I2C SDA line held high), current can flow into the sensor through its ESD protection diodes and keep it partially alive. The solution is to either tristate the interface pins before cutting power, use open-drain interfaces that float when released, or route the interface through an I/O switch that breaks the connection entirely when the sensor rail is off. Failing to handle this correctly means your sensor never truly powers down, and your sleep current measurement will tell you something is wrong without making it obvious what.
Pullup resistors on I2C buses are another common current leak. A 4.7 kΩ pullup to 3.3 V draws about 700 µA continuously. If you have two such resistors and your bus is idle 99% of the time, that alone costs you 1.4 mA average — more than many processors draw in active mode. Consider switching I2C pullups through a GPIO, or use weaker pullups (47 kΩ or 100 kΩ) if your bus speed and capacitance allow it.
Crystal oscillators, LEDs (including status LEDs that seem harmless), and voltage reference ICs all need the same treatment. A status LED with a 1 kΩ series resistor at 3.3 V draws 3.3 mA — enough to flatten most coin cells in hours if left on during sleep. Map every component on your schematic, identify its sleep-mode current, and make sure there is a control mechanism to reduce it to zero or near-zero.
Measuring What Is Actually Happening
The biggest mistake in low-power development is relying on datasheet numbers instead of measuring your actual system. Datasheets give you typical values under specific conditions. Your system has different firmware, different peripheral states, different power supply noise, and different operating temperature. You need to measure.
The right tool depends on the current range you are trying to measure. A benchtop multimeter is useless for dynamic current profiling — its sample rate is too slow to capture the microsecond-scale current pulses of a BLE transmission. You need either a dedicated power analyzer or a shunt resistor with a fast oscilloscope or data acquisition system.
The Nordic Power Profiler Kit II (PPK2) has become a standard tool for this class of work. It measures current from around 200 nA up to 1 A at a 100 kHz sample rate, overlays the waveform with a timeline, and lets you zoom in on individual wake events to see exactly where current is being consumed. For STM32-based designs, the STM32CubeMonitor-Power tool provides similar capability with direct integration into the ST ecosystem. Infineon's PSoC platforms are well served by the CYPM1000 power monitor or third-party tools like the Otii Arc, which adds the ability to correlate current draw with UART log output — invaluable for diagnosing which lines of code are responsible for unexpected power consumption.
The Otii Arc deserves special mention for complex debugging scenarios. It simultaneously records current, voltage, and a UART stream, and lets you annotate the power trace with log events. When you see an unexpected current spike at 3 AM in a multi-day soak test, you can scroll back to the UART log and see exactly what the firmware was doing at that moment.
Keeping the Processor Asleep
Modern microcontrollers offer a hierarchy of sleep modes, each with different wakeup latency and power consumption. On the STM32L4 series, for example, you have Run mode at several milliamps, Sleep mode with the CPU halted but peripherals active, Stop mode with most clocks off and RAM retained, and Shutdown mode where nearly everything is powered down. The difference between Stop 2 and Run mode on an STM32L4 is roughly 1 µA versus 10 mA — a factor of 10,000.
The goal is to spend as much time as possible in the deepest sleep mode your application allows. Achieving this requires that every peripheral, every DMA channel, and every clock domain be explicitly disabled before entering sleep. This sounds obvious but is surprisingly easy to get wrong. Common mistakes include leaving a timer running in stop mode, forgetting to disable a GPIO that is driving a resistive load, leaving the ADC or UART in an active state, or allowing an external component to pull current through a GPIO that should be tristated.
On STM32 devices, the PWR_CSR registers and the HAL low-power APIs give you control over which domains are powered in each sleep state. On Infineon PSoC 6, the System Power Management (SysPm) driver provides a clean abstraction for transitioning between active, sleep, deep sleep, and hibernate modes, with callback hooks for peripherals to prepare themselves before the transition.
The Real Culprits: Clocks, Regulators, and Radios
The processor is rarely the dominant power consumer in a well-optimized system. The culprits are usually the supporting cast.
Voltage regulators have quiescent current — the current they consume just to stay active, regardless of load. A linear regulator with 100 µA quiescent current will dominate the power budget of any system targeting single-digit µA sleep current. Choose LDOs specifically rated for low quiescent current (some achieve under 1 µA), or use a switching regulator in pulse-frequency modulation (PFM) mode for light loads.
Crystal oscillators for RTC functions are another common surprise. A 32.768 kHz crystal with a poorly tuned drive level can consume 5-10 µA by itself. Check your oscillator drive strength setting — most microcontrollers allow you to reduce it once the crystal is confirmed stable, cutting the oscillator current by half or more.
Radios — BLE, 802.15.4, LoRa — are typically the largest active-mode power consumers in wireless sensor applications. The key is minimizing time in Tx and Rx. On BLE, connection interval, advertising interval, and packet payload size all directly affect the energy cost per communication event. A device advertising at 100 ms intervals uses ten times the radio energy of one advertising at 1000 ms. If your application can tolerate latency, use it.
Firmware Architecture for Low Power
Low-power firmware is fundamentally event-driven rather than loop-driven. A device that sits in a while(1) loop polling sensors is burning CPU cycles and preventing the processor from sleeping. A properly structured low-power application does work in interrupt handlers and callbacks, then returns to a sleep loop that immediately re-enters the deepest allowable sleep mode.
This architecture requires that all time-critical operations complete quickly and that long-running tasks are broken into deferred chunks. It also requires careful attention to interrupt latency and the wakeup overhead of deep sleep modes — if your Stop mode wakeup takes 500 µs and your useful work takes 100 µs, you are spending 83% of your active time just waking up. In that case, a shallower sleep mode with faster wakeup might give better total energy efficiency.
Soak Testing and Real-World Validation
Once your firmware is optimized and your bench measurements look good, you need to validate in real-world conditions over time. Current draw is not always constant — it can change with temperature, battery voltage, firmware state, and RF environment. A device that measures 8 µA average on the bench at room temperature may draw 15 µA at -20°C because the crystal oscillator drive circuit behaves differently, or because the BLE stack retries more often due to RF interference.
A multi-day soak test with continuous current logging is non-negotiable before committing to a battery life specification. Instrument your test setup to log not just average current but also peak current and waveform shape over time. Unexpected current spikes — even rare ones — can be the difference between a two-year battery life and a six-month one.
Battery life optimization is iterative and sometimes frustrating work, but it is also one of the most satisfying problems in embedded engineering. When you finally see that average current drop below your target and the math says your device will last three years on a CR2032, it makes all the oscilloscope time worthwhile.
At SiGenix, low-power embedded design is one of our core competencies. We have optimized battery life across a range of platforms including STM32L4/L5 and Infineon PSoC 6, for applications ranging from wearable medical devices to industrial wireless sensors. If you are working on a battery-powered product and want a second set of eyes on the architecture or the power budget, reach out to our team.