Power supply design rarely gets the same attention as wireless stacks or firmware architecture, yet in my experience it accounts for more field failures than both combined. An IoT sensor node that works perfectly on the bench can brown out during a LoRa transmission, reset when the battery gets cold, or slowly drift out of ADC accuracy as its LDO heats up inside a sealed enclosure. I have debugged all of these. The difference between a prototype that passes and a product that survives for five years in the field is not a more expensive regulator — it is a deliberate power tree, component choices matched to real load profiles, and layout decisions that respect current paths and heat flow. This article walks through the three pillars you need to get right for battery-powered embedded systems: LDOs, buck converters, and battery management, and how to tie them together without creating new problems.
Why Embedded Power Rails Fail in the Field Before the Firmware Does
In my experience, most power-related failures do not show up as a dead board. They show up as intermittent resets, corrupted flash writes, or radio packets that fail at the edge of the temperature range. The root cause is usually a rail that looked fine on a multimeter but collapsed for 20 microseconds under load.
The Three Failure Signatures I See Most Often
First, the transmit burst sag. A typical LTE-M or LoRa module draws 10-20 uA in sleep, then 300-500 mA for 50-200 ms during transmission. If your 3.3V rail is fed by an LDO from a Li-ion battery at 3.6V, you have almost no headroom and the LDO will drop out. If it is fed by a buck converter without enough output capacitance or with slow transient response, the rail dips to 2.9V and the MCU hits its brown-out reset threshold.
Second, the cold battery collapse. A Li-ion cell at 0°C can have double the internal resistance it has at 25°C. Under a 500 mA pulse, a cell that reads 3.7V open-circuit can momentarily deliver only 3.3V at its terminals. I have seen designs where the buck converter's UVLO was set to 3.4V for efficiency, which meant the entire system shut off at 30% state-of-charge when deployed outdoors in winter.
Third, the slow thermal drift. Linear regulators and even some bucks will enter thermal limiting inside a small IP67 enclosure at 60°C ambient. The part does not fail outright — it current-limits, the rail droops, and the system starts throwing I2C NACKs or ADC errors that look like software bugs. You will not catch this without a thermal chamber and a long soak test.
Defining Your Power Tree Before You Pick Parts
Before opening a distributor search, I map every rail, its nominal voltage, tolerance, max and sleep current, noise requirement, and sequencing need. For a recent asset tracker, that table looked like this: 3.3V MCU + sensors (1.8V-3.6V tolerant, 120 mA peak, 8 uA sleep, low noise not critical), 3.3V radio (3.1V-3.5V tolerant, 450 mA peak, noise sensitive), 1.8V accelerometer always-on (5 uA), and 3.0V analog for a soil moisture front-end (noise < 50 uVrms). That immediately tells me I cannot share a single noisy buck for the analog rail, and I need a dedicated LDO or filtered rail for it. Drawing this tree early prevents the classic mistake of adding regulators as an afterthought, which almost always creates sequencing and ground loop issues. If you are still defining your board stackup and placement strategy, it helps to review PCB Design Basics with KiCad: Schematic to Board Layout alongside the power tree, so footprint choices and copper planning happen together.
LDO Selection and Layout: When Efficiency Takes a Back Seat to Noise
LDOs are often dismissed as inefficient, but for low-current, noise-sensitive rails they are still the right tool. The key parameters are dropout voltage, quiescent current (Iq), power supply rejection ratio (PSRR), output noise, and thermal performance — and they all interact.
Calculating Power Dissipation and Junction Temperature
The first check I do is thermal. An LDO's dissipation is simple but unforgiving: Pd = (Vin - Vout) * Iload + (Vin * Iq). At 500 mA from 4.2V to 3.3V, that is 0.45W plus a few milliwatts. In a small SOT-23-5 with thetaJA of 150°C/W on minimal copper, that is a 67°C rise above ambient. Inside a 45°C enclosure, junction temperature hits 112°C, close to the 125°C limit for many parts, and reliability drops sharply long before that.
For that reason I derate heavily. I like LDOs in DFN or SOT-223 packages with an exposed thermal pad when currents exceed 150 mA, and I pour copper on both layers with thermal vias under the pad. A part like the TLV755P or NCP171 handles 500 mA with 15-30 uA Iq and 70 dB PSRR at 1 kHz, but only if you give it copper. The datasheet's thetaJA assumes a JEDEC test board that looks nothing like your 4-layer IoT board with cutouts for antennas. For thermal planning, the guidance in Thermal Management in PCB Design: Heat Sinks, Copper Pours and Thermal Vias applies directly to regulators — especially via placement under the pad.
// Simple LDO thermal check I run in firmware build scripts
// pd = (vin - vout) * i_load + vin * iq
#include <stdio.h>
float ldo_junction_temp(float vin, float vout, float i_load_A, float iq_A, float theta_ja, float t_ambient) {
float pd = (vin - vout) * i_load_A + vin * iq_A;
return t_ambient + pd * theta_ja;
}
int main() {
// Example: 4.2V -> 3.3V at 300mA, TLV755P, 70C/W with good copper
float tj = ldo_junction_temp(4.2f, 3.3f, 0.30f, 25e-6f, 70.0f, 55.0f);
printf("Tj = %.1f C\n", tj); // Should be < 100C for margin
return 0;
}
PSRR and Output Noise for RF and ADC Rails
When powering an ADC reference or an RF transceiver's analog supply, PSRR and integrated output noise matter more than dropout. A buck converter switching at 1-2 MHz will leave 10-30 mV ripple on its output. An LDO with 60-70 dB PSRR at 100 kHz can attenuate that to tens of microvolts, but only if you give it headroom. PSRR collapses when Vin - Vout approaches the dropout voltage, so I keep at least 300 mV across the LDO when filtering a switcher, or 500 mV if the load is dynamic.
Output noise is often specified as 20-50 uVrms over 10 Hz - 100 kHz. For a 12-bit ADC with a 3.0V reference, 1 LSB is 732 uV, so 50 uVrms is fine. For a 16-bit front-end, it is not. In that case I add an RC or ferrite bead + capacitor filter after the LDO, or choose a low-noise LDO like the ADP165 or TPS7A20 series that specifies 10 uVrms. Always place the LDO's input and output capacitors within 2-3 mm of the pins with a solid ground return, and do not share that ground return with switching currents.
Buck Converter Design for IoT Loads: From Microamp Sleep to Amp-Level Bursts
For any rail where Vin is much higher than Vout or load current exceeds 200-300 mA, a buck converter pays for itself in battery life. The challenge in IoT is not peak efficiency — it is efficiency across four decades of load, from 5 uA in sleep to 500 mA during transmit, and staying stable through those transitions.
Inductor and Capacitor Selection Beyond the Datasheet Table
Datasheets give you a table of 2.2 uH inductors and 10 uF capacitors, but they assume a continuous 1A load. IoT loads are bursty and often discontinuous. I select inductors based on saturation current (Isat) at least 1.5x the peak current limit, and DC resistance (DCR) low enough that I2R losses do not dominate at light load. For a 3.6V to 1.8V buck at 600 mA peak, an inductor with Isat of 1.2A and DCR under 150 mOhm is a good balance. Shielded inductors are worth the extra 0.10 USD — unshielded types spray magnetic field into nearby trace antennas and magnetometers. This is one of the reasons I coordinate regulator placement early when following PCB Antenna Design for IoT: Trace Antennas, Matching Networks and Layout Rules; a buck inductor 5 mm from a 868 MHz trace antenna will detune it and add spurious emissions.
For capacitors, I use X7R or X5R ceramics with a voltage rating at least 2x the rail voltage, because capacitance drops 40-60% under DC bias. A 10 uF 6.3V capacitor on a 3.3V rail is effectively 4-5 uF. I always parallel 2x 10 uF + 1x 0.1 uF at the output, placed symmetrically around the inductor node with a tight loop. The switching node itself should be as small as possible in copper area to reduce EMI, but large enough to handle current without excessive temperature rise.
Handling 10 uA to 500 mA Load Transients Without Overshoot
The critical spec for IoT is light-load efficiency and transient response, not just peak efficiency at 1A. Modern bucks like the TPS62840, nPM1100, or XC9276 include a power-save or PFM mode that keeps efficiency above 80% even at 100 uA by switching in bursts and then sleeping. The trade-off is higher output voltage ripple in PFM — 20-50 mV — which is acceptable for digital rails but not for analog.
Transient response is set by the control loop, output capacitance, and the feedforward capacitor across the upper feedback resistor. Without enough bulk capacitance, a 0 to 300 mA step will droop 100-150 mV before the loop recovers. I size output capacitance so that C * deltaV > Istep * tresponse. For a 300 mA step with a 10 us loop response, I need at least 30 uF effective capacitance to keep droop under 100 mV. I verify this with an electronic load pulsing at 10 kHz while watching the rail on a scope with 20 MHz bandwidth limiting and a short ground spring — not a long ground lead that adds ringing.
# Buck feedback divider calculation - check with E96 resistor values
# Vout = Vref * (1 + R1/R2) -> R1 = R2 * (Vout/Vref - 1)
VREF = 0.6 # e.g., TPS62840
VOUT = 3.3
R2 = 100e3 # choose 100k for light load efficiency
R1 = R2 * (VOUT / VREF - 1)
print(f"R1 ideal = {R1/1e3:.1f} k")
# Pick nearest E96: 453k for R1 with R2=100k gives 3.318V
R1_E96 = 453e3
VOUT_ACTUAL = VREF * (1 + R1_E96/R2)
print(f"Actual Vout with 453k/100k = {VOUT_ACTUAL:.3f} V")
# Always add 10-22pF feedforward cap (Cff) for transient response
Switching frequency is a trade-off. 2 MHz allows a smaller 1 uH inductor but increases switching losses and EMI. 1 MHz is quieter and slightly more efficient at moderate loads. For sub-GHz and GPS boards I often choose 1 MHz or 1.5 MHz and keep the switcher's harmonics away from the receiver's IF. If you push to 2 MHz for size, be meticulous with the layout and shielding.
Battery Management Realities: Charging, Fuel Gauging and Protection for Li-Ion and LiPo
Most IoT products use a single-cell Li-ion or LiPo because energy density is unmatched, but the management around it determines whether the product is safe, accurate, and long-lived. A charger, a fuel gauge, and a protection circuit are three different jobs, and combining them badly is a common mistake.
Charger IC Selection: Linear vs Switching Charger
For charge currents under 500 mA with a 5V USB or 6V solar input and a single cell, a linear charger like the MCP73831 or BQ24073 is simple, small, and cheap. Its dissipation is (Vin - Vbatt) * Icharge, so at 5V in and 3.7V battery at 400 mA, that is 0.52W — manageable with copper. Above 800 mA or when charging from a higher voltage, a switching charger like the BQ24295 or MP2625 is more efficient and avoids thermal throttling that stretches charge time.
In my experience, the critical feature is not charge current but termination and JEITA compliance. JEITA reduces charge voltage and current at cold and hot temperatures to prevent plating and swelling. If your device charges outdoors or on a dashboard, you must have an NTC thermistor on the cell and a charger that implements the JEITA profile — otherwise you will degrade the cell in a single summer. Also, ensure the charger supports power-path management if the system must run while charging. Without power-path, the charger terminates early because it sees system load as battery current, or it cycles between charge and discharge.
Implementing Accurate State-of-Charge Without Wasting Power
Voltage alone is a poor indicator of state-of-charge for Li-ion. The discharge curve is flat between 20% and 80%, so a 50 mV error translates to 20% SOC error, and that error shifts with load and temperature. For products that report battery percentage to users or make low-battery decisions, I use a dedicated fuel gauge.
There are two approaches. Voltage-based gauges like the MAX17048 use a sophisticated model (ModelGauge) and work with just voltage and temperature sensing, drawing 20-50 uA. Coulomb-counting gauges like the BQ27441 or MAX17260 measure current across a small sense resistor (5-10 mOhm) and integrate over time, which is more accurate under variable load but adds cost and requires calibration. For most IoT nodes that sleep 99% of the time, a voltage-based gauge with occasional temperature correction is accurate to 3-5% and consumes far less power than keeping a sense amplifier alive.
Protection is non-negotiable. Even if your charger has over-voltage protection, you need a secondary protector like the AP9101 or S-82A1 that permanently opens a dual MOSFET if the cell exceeds 4.30V or drops below 2.4V, or if current exceeds 2-3A. I place the protection MOSFETs and the sense resistor close to the battery connector with a short, wide trace — not across the board — and I never route this high-current path through a narrow neck or a single via.
/* Zephyr RTOS: reading MAX17048 fuel gauge over I2C with power save */
#include <zephyr/drivers/i2c.h>
#include <zephyr/kernel.h>
#define MAX17048_ADDR 0x36
static const struct i2c_dt_spec fuel_gauge = I2C_DT_SPEC_GET(DT_NODELABEL(max17048));
int read_battery_soc(uint8_t *percent, int16_t *voltage_mv) {
uint8_t reg_vcell = 0x02;
uint8_t buf[2];
int ret;
// Wake gauge only when needed - keep I2C bus powered down in sleep
ret = i2c_write_read_dt(&fuel_gauge, ®_vcell, 1, buf, 2);
if (ret != 0) return ret;
uint16_t vcell_raw = (buf[0] << 8) | buf[1];
*voltage_mv = (int16_t)((vcell_raw >> 4) * 125 / 100); // 1.25mV per LSB
uint8_t reg_soc = 0x04;
ret = i2c_write_read_dt(&fuel_gauge, ®_soc, 1, buf, 2);
if (ret != 0) return ret;
*percent = buf[0]; // integer part, buf[1] is fractional 1/256%
return 0;
}
One practical tip: do not poll the gauge every second. Read it every 60 seconds when awake and every 10 minutes when sleeping, and put the I2C bus and pull-ups behind a load switch you can turn off. The Zephyr Project Documentation power management API makes this easy with pm_device_runtime — you can suspend the gauge and the I2C controller between readings and save 30-40 uA of average sleep current.
Sequencing, Supervision and Low-Power Modes: Tying the Power Tree Together
A well-designed tree still fails if rails come up in the wrong order or if the MCU wakes up before its flash and sensors are ready. Sequencing and supervision are where hardware and firmware meet.
Reset and Supervisor ICs Are Not Optional
Every low-power design needs a voltage supervisor. The MCU's internal POR/BOR is typically slow and has a wide threshold tolerance (±100 mV). An external supervisor like the TPS3839 or MCP1316 with a 1-2% accurate threshold and a fixed 100-200 ms reset delay ensures the MCU only starts when the rail is stable, and holds it in reset during a brownout long enough for the rail to recover. I also use supervisors with a manual reset input for factory test buttons and load-switch sequencing.
For systems with multiple rails — for example 3.3V for I/O and 1.8V for the SoC core — I sequence them with a load switch or a power-good output from the first regulator feeding the enable of the second. The core must never see I/O voltage before its own supply is high, otherwise you get latch-up or back-powering through ESD diodes. A simple approach: buck 3.3V power-good -> enable for 1.8V LDO -> 1.8V power-good -> enable for sensor rail. Add 10 ms RC delays if you need staggered timing. Verify sequencing with a four-channel scope on every build, not just once — capacitor tolerance alone can shift timing by 5-10 ms.
Software-Controlled Power Gating and Tickless Idle
Hardware gives you the rails, but firmware decides how long they stay on. I partition the design into power domains that can be physically switched off: always-on (RTC, supervisor, wake button), gated sensor domain (I2C sensors + pull-ups + LDO), and high-current radio domain (buck + PA). Each domain sits behind a load switch like the TPS22910 or a high-side MOSFET with controlled slew rate to limit inrush. A load switch with a 1 ms rise time prevents a 2A inrush spike when you charge 40 uF of decoupled capacitance.
On the firmware side, use the RTOS tickless idle feature rather than a busy delay loop. In FreeRTOS, configUSE_TICKLESS_IDLE allows the kernel to stop the systick and enter deep sleep between tasks, waking only on interrupts. In Zephyr, PM_DEVICE and system power management do the same with more granularity for peripheral states. The FreeRTOS Documentation covers the expected implementation of vPortSuppressTicksAndSleep() — you need to configure your low-power timer correctly or you will wake every millisecond and gain nothing. I have measured the difference: with tickless idle properly configured, sleep current dropped from 1.2 mA to 9 uA on an nRF52840 board; without it, the regulator never entered its low-Iq mode.
PCB Layout and Thermal Decisions That Make or Break Power Integrity
A regulator that is stable on the evaluation board can oscillate on your board if the layout breaks its assumptions. Power layout is not about aesthetics — it is about loop area, parasitics, and thermal paths.
Placement Priorities for Switching Regulators
Place the switching regulator first, then the radio, then the MCU. Keep the input capacitor loop — input cap, high-side FET, low-side FET or diode, inductor — as tight as physically possible, ideally within 5x5 mm. Route the switching node (SW) as a short, wide trace or small polygon, but do not make it a large antenna. I keep the feedback divider within 3 mm of the FB pin with a Kelvin connection directly at the output capacitor, not at the load 20 mm away, and I route it away from the switching node and inductor. A 10 mil feedback trace running parallel to the SW node for 10 mm will pick up 50 mV of switching noise and turn it into output ripple.
Ground is critical. Use a solid ground plane on the layer directly under the regulator with at least two vias per ground pad. Do not split the ground plane under the switcher — the return current needs a low-inductance path directly under the input loop. I also avoid placing vias in the thermal pad of QFN regulators that will wick solder away during reflow; use 4-6 filled and capped vias of 0.3 mm drill instead of 9 open vias. For high-speed interfaces near power stages, the signal return and stackup considerations in Signal Integrity for High-Speed PCB: Impedance Control, Crosstalk and EMI directly complement power layout — keep power switching currents out of the signal ground references.
Thermal Relief and Copper Weight Trade-offs
Copper weight matters. On a 1 oz (35 um) board, a linear regulator dumping 0.5W needs about 250 mm² of copper to keep the rise under 40°C. On 0.5 oz with thermal relief spokes, that same dissipation rises 60-70°C because the spokes act as thermal resistors. For power components, I use direct connect to copper pours, not thermal reliefs, and I specify 1 oz copper on outer layers and 1 oz on inner layers for power-heavy boards. The cost increase is small compared to a field return.
For enclosed devices, conduction is the only cooling mechanism. I add a 10x10 mm exposed copper pour on the bottom layer under the regulator and couple it to the enclosure with a 1 mm silicone thermal pad if possible. I also place a temperature sensor (NTC or digital like TMP117) within 5 mm of the hottest regulator — not across the board — so firmware can throttle charging or duty cycle when the junction approaches 90°C. This sensor is also useful for battery temperature compensation.
| Topology | Typical Efficiency | Quiescent Current | Output Noise | Best Use Case in IoT |
|---|---|---|---|---|
| LDO | 55-85% (Vout/Vin) | 0.5-30 uA | 10-50 uVrms | Low-current sensor/analog rails, post-buck filtering |
| Buck Converter | 85-96% peak, 75-90% at light load (PFM) | 0.3-10 uA (with sleep mode) | 5-30 mV ripple | Main 3.3V/1.8V rail from battery, high-current radio supply |
| Buck-Boost (e.g., TPS63802) | 80-92% | 5-20 uA | 10-40 mV ripple | Single rail from Li-ion across full 2.8-4.2V range without dropout |
| Load Switch / Ideal Diode | 99%+ (Rdson loss only) | 0.1-2 uA | ~0 (pass-through) | Power domain gating, OR-ing battery/USB, inrush control |
Finally, test what you layout. I always perform a load step test with an electronic load that switches between sleep and peak current while monitoring all rails with a scope in AC coupling at 20 MHz bandwidth. Check ripple at full load, light load, and during mode transitions — many converters show a 100 mV glitch when entering or leaving PFM. Run the board through a thermal cycle from -20°C to +60°C while logging rail voltages with a slow ADC; you will catch temperature-dependent capacitor derating and protection thresholds that bench tests at 25°C miss.
Frequently Asked Questions
Should I use an LDO or a buck converter for a 3.3V rail powered from a Li-ion battery?
Depends on current and noise tolerance. If your average current is under 50 mA and you need very low noise for an analog sensor, an LDO from 3.6-4.2V to 3.3V is simple and quiet, but efficiency will be 78-92%. For a digital rail that sees 200 mA+ peaks or must operate down to 3.0V battery, a buck is more efficient and will not drop out. In practice I often use a buck for the main 3.3V system rail and a small 30 mA LDO after it for the analog domain — you get efficiency and clean analog power without duplicating converters.
How much headroom does an LDO actually need to maintain PSRR?
More than the dropout voltage in the datasheet headline. Dropout is usually specified at 10-50 mV with PSRR already degraded to 10-20 dB. For 60 dB PSRR at 100 kHz, I budget at least 300 mV of headroom, and 500 mV if the input has ripple from a switcher. Check the PSRR vs. headroom graph, not just the dropout table. If you only have 150 mV available, use a low-dropout LDO with an NMOS pass device like the TPS7A05 or add capacitance and accept higher noise.
Can I estimate battery life from average current alone?
Only roughly, and it usually overestimates life. You need to include sleep current, wake duty cycle, transmit energy per packet, converter efficiency at light load, and self-discharge. For example, 10 uA sleep with 30 mA for 100 ms every 10 minutes averages to 15 uA, but if your buck is only 70% efficient at 10 uA, actual battery draw is 21 uA. Add temperature and aging derating of 15-20% and capacity loss from cold. I build a spreadsheet that integrates current over a full operating cycle and then validate with a Coulomb counter like the PPK2 or Nordic Power Profiler for a week of real operation.
Why does my board reset when the radio transmits even though the battery voltage looks fine?
The open-circuit battery voltage is not the voltage under load. The cell's internal resistance plus trace resistance and connector resistance creates an IR drop during the 300-500 mA burst. With 200 mOhm total resistance, a 400 mA pulse drops 80 mV at the cell plus additional drops in ground return. If your buck's input capacitor is too small or too far away, the input rail sags further and the converter hits UVLO. Fix it with a low-ESR 47-100 uF bulk capacitor within 5 mm of the radio's supply pins, wide power traces, and a battery rated for at least 1C pulse current. Then verify with a scope triggered on the transmit enable line.