Quick Cap
Low-power design at the system level is about making every microamp count so a battery-powered device lasts months or years instead of days. This page covers the firmware engineer's toolkit for power optimization -- power budgeting, duty cycling, peripheral management, and sleep-current auditing. (MCU-level sleep modes and clock configuration are covered in the mcu-cores-and-clocking topic.) Interviewers test system-level power thinking to see whether a candidate can translate a "2-year battery life" requirement into concrete firmware decisions.
Key Facts:
- Power budget formula:
Battery life (hours) = Battery capacity (mAh) / Average current (mA)-- the entire design starts here - Duty cycling is the most powerful technique: sleeping at 2 uA for 59 seconds and waking at 15 mA for 1 second yields an average of only ~252 uA
- Peripheral management -- unused peripherals (ADC, UART, timers) should have their clocks gated and analog blocks powered down; leaving them on wastes hundreds of microamps
- Wake-up sources include RTC timers, GPIO edge interrupts, and accelerometer motion interrupts -- choosing the right one affects both latency and standby power
- Floating pins are a hidden current drain -- unconnected GPIOs with neither pull-up nor pull-down can oscillate, causing CMOS input stages to draw excess current
- Communication protocol choice dominates IoT power budgets -- a single WiFi transmission can consume more energy than a week of BLE advertising
Deep Dive
At a Glance
| System-level power concern | Why it matters |
|---|---|
| Power budget analysis | Determines whether the battery can meet the lifetime target before writing any code |
| Duty cycling | Reduces average current by orders of magnitude by maximizing time in sleep |
| Peripheral power management | Each unnecessary enabled peripheral adds tens to hundreds of uA |
| Wake-up source selection | Determines standby power and response latency |
| Communication protocol power | Often the single largest energy consumer in an IoT node |
| Sleep current audit | Finds the hidden leakage paths that kill battery life in production |
Power Budget Analysis
Every battery-powered design begins with a power budget. The calculation is straightforward but requires accurate current measurements for each operating state.
Battery lifetime formula:
Average current = (I_active x T_active + I_sleep x T_sleep) / T_totalBattery life (hours) = Capacity (mAh) / Average current (mA)Example -- LoRa sensor node with CR2032 (230 mAh):Active: 15 mA for 2 seconds (wake, measure, transmit)Sleep: 3 uA for 598 seconds (deep sleep with RTC)Period: 600 seconds (10-minute cycle)Average I = (15 x 2 + 0.003 x 598) / 600= (30 + 1.794) / 600= 0.053 mA = 53 uABattery life = 230 / 0.053 = 4340 hours = ~181 daysTo hit 2 years (17520 hours):Target average = 230 / 17520 = 13.1 uA--> Must reduce active time, active current, or both
Datasheet battery capacities (like 230 mAh for CR2032) assume a specific discharge rate and temperature. Real-world capacity can be 30-50% lower at high pulse currents or cold temperatures. Always derate the battery capacity in your power budget.
Duty Cycling Patterns
The most effective system-level power technique is spending as much time as possible in the lowest-power sleep state. A typical IoT duty-cycling pattern:
Time --->|-- T_wake --|------------ T_sleep --------------|| | |+-+ +--+ + +-+ +--+| | | | | Deep Sleep | | | || | | | | (2-5 uA) | | | || | | | | | | | |+-+ +--+ +------------------------------------+-+ +--+--Wake Meas TX Wake Meas TX(init (ADC (radio (init (ADC (radioclks) read) burst) clks) read) burst)1ms 50ms 200ms 1ms 50ms 200ms
Optimizing each phase:
- Wake-up -- keep initialization minimal. Cache calibration values in retained RAM so the ADC and radio do not need full recalibration every cycle.
- Measure -- power the sensor only during the measurement window. Use the MCU's internal reference instead of an external reference IC if precision allows.
- Transmit -- batch multiple readings into one transmission. Transmitting once with 10 readings uses far less energy than transmitting 10 times with one reading each.
- Sleep -- verify the deep-sleep current with a real measurement. Datasheets quote 2 uA, but a real board with debug circuitry may draw 200 uA.
Peripheral Power Management
Peripherals left enabled in sleep modes are a common source of unexpectedly high standby current.
| Peripheral | Typical active current | Action when unused |
|---|---|---|
| ADC (analog block) | 200-800 uA | Disable analog reference and comparator |
| UART (with level shifter) | 50-500 uA | Disable UART clock; power-gate external level shifter |
| SPI flash | 15-25 uA standby | Issue deep-power-down command before sleeping |
| Accelerometer | 2-10 uA | Use motion-detect mode (sub-uA) instead of continuous sampling |
| Voltage regulator (LDO) | 5-50 uA quiescent | Choose a low-Iq LDO; consider a load switch to cut power to unused subsystems |
| External sensors | 0.1-5 mA | Use a GPIO-controlled MOSFET load switch to cut power entirely |
Load switches: for sensors or modules that have no low-power standby mode, use a P-channel MOSFET or dedicated load-switch IC controlled by a GPIO to cut power entirely. This guarantees zero leakage through the powered-off subsystem.
Wake-Up Source Strategies
The choice of wake-up source directly affects standby power and response time:
| Wake-up source | Standby cost | Wake latency | Best for |
|---|---|---|---|
| RTC timer (internal) | Included in deep-sleep current | ~1 ms | Periodic sampling at fixed intervals |
| RTC timer (external, e.g., PCF8563) | 0.25 uA | ~1 ms | When MCU RTC is not available in lowest sleep state |
| GPIO edge interrupt | Near zero (if pin is pulled) | ~1 us | Button press, door sensor, external trigger |
| Accelerometer interrupt | 0.5-3 uA (motion detect mode) | ~10 ms | Activity-triggered wakeup (wearables, asset trackers) |
| Comparator (analog watchdog) | 1-5 uA | ~10 us | Threshold-based wake (voltage drop, temperature alarm) |
| Radio (BLE advertising) | 5-15 uA average | ~3 ms | Remote commands from phone/gateway |
Communication Protocol Power Comparison
For IoT devices, the radio is often the dominant power consumer. Choosing the right protocol is a system-level design decision with enormous impact on battery life.
| Protocol | Typical TX current | TX time per packet | Energy per packet | Range | Best use case |
|---|---|---|---|---|---|
| BLE (advertising) | 8-15 mA | 1-3 ms | ~30 uJ | 10-50 m | Short data bursts, phone connectivity |
| LoRa (SF7) | 25-40 mA | 50-100 ms | ~2000 uJ | 2-15 km | Long range, low data rate, outdoor |
| WiFi | 150-350 mA | 50-200 ms | ~30000 uJ | 30-100 m | High throughput, mains-powered preferred |
| Cellular (LTE-M) | 200-500 mA | 100-2000 ms | ~200000 uJ | km+ | Wide-area, firmware OTA, high reliability |
| Zigbee | 15-25 mA | 5-15 ms | ~200 uJ | 10-100 m | Mesh networking, home automation |
A single WiFi association + TCP handshake + data TX can consume as much energy as 1000 BLE advertisement packets. If your IoT device only sends a few bytes every few minutes, BLE or LoRa will extend battery life by orders of magnitude compared to WiFi.
Voltage Scaling (DVFS)
Dynamic Voltage and Frequency Scaling (DVFS) reduces power during active periods when full CPU performance is not needed. Since dynamic power scales as P = C x V^2 x f, halving both voltage and frequency reduces power by 8x. Many modern MCUs offer multiple performance levels:
| Performance level | Frequency | Voltage | Relative power |
|---|---|---|---|
| Full speed | 80 MHz | 1.2 V | 1.0x |
| Medium | 20 MHz | 1.0 V | ~0.09x |
| Low power | 4 MHz | 0.9 V | ~0.01x |
In firmware, DVFS is implemented by switching clock prescalers and voltage regulator modes before and after computationally intensive tasks. The key constraint: always raise voltage before raising frequency (to avoid the CPU running too fast for its supply voltage), and lower frequency before lowering voltage.
Sleep Current Audit
When the measured sleep current exceeds the datasheet value, a systematic audit finds the leakage paths:
- Measure baseline -- power the board with only the MCU, no external peripherals connected. If sleep current matches the datasheet, the MCU is configured correctly.
- Add peripherals one at a time -- reconnect each external IC and re-measure. The one that causes a jump is the culprit.
- Check floating pins -- any GPIO left as a high-impedance input without a defined voltage level (pull-up or pull-down) can oscillate due to noise, causing the CMOS input buffer to draw current. Set unused pins to output LOW or enable internal pull-downs.
- Check debug circuitry -- SWD/JTAG pull-ups, debug LEDs, and USB-UART bridges often draw 100+ uA.
- Check voltage dividers -- resistive voltage dividers for battery monitoring draw continuous current. Use a GPIO-controlled switch to disconnect the divider during sleep, or use very high-value resistors (10 MOhm range).
- Check level shifters -- some bidirectional level shifters draw quiescent current even when idle.
Debugging Story: Battery Life 3 Months Instead of 2 Years
A team designed a battery-powered asset tracker expected to last 2 years on a 1000 mAh LiPo. In field testing, batteries died after only 3 months. The power budget spreadsheet predicted 12 uA average, which should have given over 9 years -- clearly something was wrong.
Connecting a precision ammeter in deep sleep showed 340 uA instead of the expected 5 uA. The team disconnected peripherals one at a time:
- Accelerometer in motion-detect mode: added 2 uA (expected)
- SPI flash in standby: added 18 uA (expected 1 uA -- the deep-power-down command was not being sent before sleep)
- GPS module: added 0 uA (correctly powered off via load switch)
- Remaining 315 uA: traced to three floating GPIOs connected to a test header
The three floating GPIOs were configured as inputs with no pull-up or pull-down. Noise on the test header pins caused the CMOS input stages to oscillate, each drawing roughly 100 uA. Setting these pins to output LOW in the sleep-entry routine and sending the SPI flash deep-power-down command reduced sleep current to 7 uA, restoring the expected 2+ year battery life.
Lesson: always audit sleep current on the actual hardware, not just the datasheet. Floating pins and peripherals that were not properly put into their lowest-power state are the two most common culprits.
What interviewers want to hear: that you approach power optimization as a system problem -- starting with a power budget calculation, designing a duty-cycle pattern, managing every peripheral's power state, and validating with real measurements. They want to hear specific numbers (uA, mAh, duty cycle ratios) and that you know the difference between what the datasheet says and what the board actually draws.
Interview Focus
Classic Interview Questions
Q1: "How would you estimate battery life for a sensor that wakes up every 5 minutes, reads a sensor, and transmits via BLE?"
Model Answer Starter: "I would build a power budget by measuring current in each state. Say the MCU draws 3 uA in deep sleep, the wake/measure phase draws 5 mA for 100 ms, and the BLE transmit phase draws 12 mA for 3 ms. The average current is (0.003 x 299.897 + 5 x 0.1 + 12 x 0.003) / 300 = (0.900 + 0.500 + 0.036) / 300 = 4.8 uA. With a 230 mAh CR2032 derated to 180 mAh for pulse loads, battery life is 180 / 0.0048 = 37500 hours, or about 4.3 years. But I would validate with a real measurement -- floating pins, debug circuitry, or a leaky LDO could easily add 50 uA and cut life to under a year."
Q2: "What are the most common causes of higher-than-expected sleep current?"
Model Answer Starter: "The top three culprits I check first are: floating GPIO pins configured as inputs without pull-ups or pull-downs, which cause the CMOS input buffer to oscillate and draw 50-200 uA per pin; peripherals that were not explicitly put into their lowest-power state, like an SPI flash left in standby instead of deep-power-down mode; and debug circuitry left populated on the board, including SWD pull-ups, indicator LEDs, and USB-UART bridge ICs. I also check for always-on voltage dividers used for battery monitoring and bidirectional level shifters with quiescent current."
Q3: "How does duty cycling reduce average power consumption?"
Model Answer Starter: "Duty cycling exploits the huge ratio between active and sleep current. If a device draws 15 mA when active and 3 uA when sleeping, and it only needs to be active for 0.5 seconds out of every 60 seconds, the duty cycle is 0.83%. The average current is 15 x 0.5/60 + 0.003 x 59.5/60 = 0.125 + 0.003 = 0.128 mA, which is 128 uA -- over 100 times less than if it stayed active continuously. The key is minimizing active time by keeping initialization fast, batching sensor reads, and combining multiple data points into a single radio transmission."
Q4: "Why would you choose BLE over WiFi for a battery-powered IoT sensor?"
Model Answer Starter: "Energy per transaction is the deciding factor. A BLE advertisement carrying a sensor reading takes about 1-3 ms at 10-15 mA, consuming roughly 30 uJ. A WiFi transaction requires association, DHCP, TCP handshake, data transfer, and disassociation -- easily 100+ ms at 200+ mA, consuming 20000-50000 uJ. That is a 1000x difference in energy per packet. For a sensor sending a few bytes every few minutes, BLE gives years of battery life on a coin cell, while WiFi would drain it in weeks. WiFi only makes sense when the device needs high throughput or is mains-powered."
Q5: "Describe DVFS and when you would use it."
Model Answer Starter: "DVFS -- Dynamic Voltage and Frequency Scaling -- reduces power during active periods by lowering both the CPU clock frequency and supply voltage when full performance is not needed. Since dynamic power is proportional to voltage squared times frequency, reducing both has a dramatic effect. For example, running at half frequency and slightly lower voltage might cut active power by 4x. I would use DVFS during periods of light processing -- waiting for sensor data, parsing a small packet, updating a display -- and scale back up to full speed for compute-intensive operations like encryption or signal processing. The key implementation detail is to always raise voltage before raising frequency and lower frequency before lowering voltage."
Trap Alerts
- Don't say "just put the MCU in sleep mode" as your complete answer -- system-level power optimization requires managing every peripheral, sensor, and communication module, not just the CPU core
- Don't forget to derate battery capacity for temperature and pulse-load effects -- using the full datasheet capacity gives falsely optimistic lifetime estimates
- Don't ignore floating pins -- they are the most common and most overlooked source of excess sleep current, yet they are trivial to fix once identified
Follow-up Questions
- "How would you implement a power budget validation test that runs in CI?"
- "What firmware changes can reduce active-phase current without changing hardware?"
- "How does temperature affect both battery capacity and MCU leakage current?"
- "What is the trade-off between wake-up frequency and data freshness in a sensor network?"
Practice
❓ A device draws 10 mA for 200 ms and 5 uA for 9.8 seconds each cycle. What is the average current?
❓ Which communication protocol typically consumes the LEAST energy per data packet?
❓ A GPIO configured as a floating input (no pull-up, no pull-down) during deep sleep can cause:
❓ In DVFS, why must you raise voltage BEFORE raising frequency?
❓ Which technique is MOST effective for reducing average current in a battery-powered sensor node?
Real-World Tie-In
Agricultural soil-moisture sensor network: A farm deployed 200 battery-powered soil-moisture sensors, each expected to last 3 years on two AA batteries (3000 mAh). Field returns after 8 months revealed dead batteries. The power audit found two issues: (1) the LoRa radio's SPI chip-select line was left LOW during sleep, keeping the radio in active-receive mode at 12 mA instead of the expected 1 uA sleep, and (2) the soil moisture sensor was powered continuously instead of only during the 50 ms measurement window. Fixing the CS-line management and adding a MOSFET load switch for the sensor reduced average current from 410 uA to 11 uA, extending battery life to over 3 years.
Wearable health monitor: A wrist-worn heart-rate monitor needed 7 days of battery life from a 150 mAh LiPo. The initial firmware polled the heart-rate sensor at 100 Hz continuously, drawing 3.2 mA average. Redesigning the firmware to use the accelerometer's motion-detect interrupt (0.8 uA) as a wake source -- only enabling the heart-rate sensor when the wrist was in motion -- reduced the effective duty cycle from 100% to about 35% during a typical day. Combined with batching 60 seconds of readings into a single BLE transmission instead of streaming every sample, average current dropped to 0.9 mA, achieving 7 days of battery life with margin.