The Raspberry Pi Power Trap: GPIO Back-Powering, SD Card Death
Every robotics builder who has bolted a Raspberry Pi onto a moving chassis eventually kills one the same three ways. Not through bad code — through bad power. The Pi’s compute is more than adequate for companion-computer duty next to a Pixhawk: AprilTag detection, MAVLink bridging, SLAM front-ends. But the moment you take it off a regulated bench supply and put it on a battery, a BEC, and a vibrating frame, the power delivery becomes the least reliable part of the whole robot.
I’ve bricked boards, corrupted SD cards mid-flight-log, and watched a Pi brownout under CPU load powered by a “20,000 mAh” power bank that should have had current to spare. None of these were code bugs. All three trace back to the same root cause: the Raspberry Pi’s power architecture assumes it is being fed through a clean, protected, current-stable USB-C path — and a robotics power tree almost never looks like that.
This post is the audit. Three failure modes, why each one happens at the hardware level, and the two wrong fixes people (including me) try before landing on the right one.
Quick Reference
| Failure Mode | Root Cause | Symptom | Fixed By |
|---|---|---|---|
| GPIO back-powering | PMIC and SoC fed directly, bypassing polyfuse/surge/reverse-polarity stage | PMIC dies instantly or after repeated transients; board never boots again | Replicating the USB-C protection stack on the HAT’s input stage |
| SD card corruption | Write cache in RAM + FTL block write interrupted mid-operation | Filesystem won’t mount, superblock unreadable, requires re-flash | Read-only root (overlayfs) + a small hold-up capacitor sized only for a final sync |
| Power bank brownout / shutoff | Poor transient response and “phone-charging” current-sensing logic in commercial power banks | Instant freeze under CPU load, or clean shutdown when idle | Purpose-built buck stage with real bulk capacitance and no phone-charging heuristics |
Part 1 — Bypassing the PMIC: The GPIO Back-Powering Trap
How It Happens
The Raspberry Pi is designed to be powered through its USB-C port. Power entering there passes through a real protection stage before it ever reaches silicon: a polymer fuse (polyfuse) that opens under sustained overcurrent, surge and EMI filtering, and reverse-polarity protection, all ahead of the Power Management IC (PMIC) that generates the SoC’s core rails.
Feeding 5V directly into the GPIO header — Pin 2 or Pin 4 — skips every one of those stages. The rail lands on the PMIC with nothing between it and whatever is happening upstream. In a robotics build, “upstream” usually means motors, servos, and ESCs sharing a battery bus, all of which throw inductive voltage spikes and switching noise onto the 5V rail during normal operation. The PMIC has no meaningful transient tolerance of its own — a momentary overvoltage event that the polyfuse and surge filter would have absorbed instead hits the regulator directly, and it fails permanently. The board doesn’t misbehave; it stops existing.
The two wrong approaches people try here:
- “Never power through GPIO, only USB-C.” This is the advice you’ll find everywhere, and it’s not wrong exactly but the rule was never “don’t use the pins,” it was “don’t skip the protection that’s supposed to sit in front of them.”
- “Add a big diode or a bulk cap across the rail and call it protected.” A flyback diode across the motor rail helps the motor’s own driver, not the Pi. A bulk capacitor smooths ripple but has no response time against a fast inductive spike and no current-limiting behavior at all. Neither replaces the polyfuse, and neither stops a short circuit anywhere else on the battery bus from riding straight into the PMIC.
The correct approach is to use the protection stage on the raspi’s input side:
| Stage | Function | Candidate Part |
|---|---|---|
| PTC fuse | Opens under sustained overcurrent, self-resets after fault clears | Bel Fuse 0ZCJ-series 0603 PTC |
| TVS diode | Clamps fast inductive spikes from motor/ESC switching before they reach the regulator | SMBJ6.0A (6V standoff, bidirectional not required here since polarity is fixed) |
| Ideal diode / reverse-polarity controller | Blocks reverse connection without the ~0.4V drop and heat of a Schottky at 3A | TI LM74610 (controls an external N-FET as a near-zero-drop ideal diode) |
Part 2 — Sudden Power Loss and SD Card Corruption
How It Happens
Linux leans on RAM as a write cache. Rather than committing every filesystem change to the SD card immediately, the kernel batches writes and flushes them periodically — this is what makes the SD card last and keeps I/O fast. It also means that at any given moment, a meaningful chunk of “written” data exists only in RAM.
Pull power abruptly — battery dies, connector vibrates loose, brownout trips — and two things fail at once:
- OS level: whatever was sitting in the write cache, unflushed, is gone. It never touches the card.
- Hardware level: the SD card’s own Flash Translation Layer (FTL) is mid-management of physical block writes. If power drops in the exact window the FTL is relocating or writing a block, the on-card structure it uses to map logical blocks to physical ones can end up inconsistent. On the next boot, the ext4 superblock is unreadable and the OS can’t mount the root filesystem at all — not “some files missing,” but “the card doesn’t come back.”
The two wrong approaches:
- “Just use a better SD card.” A higher-endurance card reduces wear over time and slightly improves the odds of a clean FTL state, but it does not change the fact that the write cache in RAM is unconditionally lost on power failure. The failure mode isn’t card quality, it’s timing.
- “Add a supercapacitor so the Pi can shut down gracefully.” This is the fix I actually reached for first, and it’s a trap of its own if you size the capacitor by intuition rather than by the load. A full
shutdown -h nowsequence — unmounting filesystems, stopping services, powering down the SoC cleanly — takes several seconds under real load. Sizing a small, board-mountable supercap for that duration means either an unrealistically large capacitor bank or a false sense of security when the cap you actually fit can’t deliver it.
Hold-up time for a capacitor bank under constant load follows:
\[t_{\text{hold}} = \frac{C \cdot (V_{\text{start}}^2 - V_{\text{cutoff}}^2)}{2 \cdot P_{\text{load}}}\]Plugging in numbers that fit on a HAT-sized board — a 1F, 5.5V supercap, starting at 5.0V, cutting off at the Pi’s brownout threshold of roughly 4.64V, against a representative Pi 5 load of 3W:
\[t_{\text{hold}} = \frac{1 \times (25 - 21.53)}{2 \times 3} \approx 0.58\ \text{seconds}\]Half a second. Nowhere near enough to run a full OS shutdown sequence. This is the invisible version of the trap — the capacitor looks like a real engineering solution, has a datasheet and a voltage rating, and still doesn’t do the job you sized it for.
The correct approach combines two things that address different halves of the problem:
- Read-only root via overlayfs. Raspberry Pi OS supports mounting the root filesystem read-only with a tmpfs overlay absorbing runtime writes. Most of what the OS wants to write during normal operation — logs, temp files, package caches — never touches the SD card at all once this is enabled. This doesn’t eliminate the failure mode, it removes almost all of the opportunity for it: there’s very little left on the card that could be mid-write when power drops.
- A hold-up capacitor sized for a
sync, not a shutdown. With overlayfs in place, the only writes that matter are the ones an application deliberately commits to persistent storage — flight logs, calibration data. Those can be flushed with a singlesync()call, which completes in milliseconds, not seconds. A capacitor sized for that job is a completely different, much smaller design problem than one sized for a full shutdown sequence.
sync() plus a filesystem remount to read-only." Those two numbers differ by an order of magnitude.
A simple power-loss monitor is just a GPIO watching a comparator on the input rail:
# power_watchdog.py — runs as a systemd service, polls a GPIO
# tied to a comparator on the input rail ahead of the buck stage
import RPi.GPIO as GPIO
import os, time
POWER_GOOD_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(POWER_GOOD_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def on_power_loss(channel):
os.system("sync")
os.system("mount -o remount,ro /")
GPIO.add_event_detect(POWER_GOOD_PIN, GPIO.FALLING,
callback=on_power_loss, bouncetime=50)
while True:
time.sleep(1)
Part 3 — The Power Bank Problem: Brownouts and Auto-Shutoff
How It Happens
A commercial USB power bank is engineered to trickle-charge a phone battery, and it shows in two specific ways once you put a Pi’s actual current profile on it.
Transient load drops. The Pi’s average draw is modest, but its peak draw during a CPU burst — spinning up all cores for image processing, AprilTag detection, anything vision-related — spikes hard and fast. A power bank’s internal regulator is tuned for the slow, steady current a phone battery wants, not a sub-millisecond current step. When the Pi demands that step, the regulator can’t react fast enough and the rail sags — sometimes below the Pi’s brownout threshold of roughly 4.64V — which either freezes the board outright or corrupts whatever the SD card was doing at that instant (compounding Part 2).
Low-current auto-shutoff. Many power banks include “smart” logic that interprets sustained low current draw as “the phone is fully charged, stop supplying power.” A Pi idling in a low-power wait state can look exactly like that to the power bank’s sensing circuit, and the bank cuts output entirely — an unexpected hard shutdown with none of the graceful-shutdown safeguards from Part 2 having a chance to run.
The two wrong approaches:
- “Buy a bigger power bank.” More mAh is more energy capacity, not faster transient response or different current-sensing logic. A 20,000 mAh bank with the same internal regulator topology sags exactly the same way under the same current step a 5,000 mAh bank does.
- “Add a dummy load resistor to defeat the auto-shutoff.” This works, in the sense that it keeps the sensed current above the shutoff threshold — at the cost of continuously wasting energy as heat for the entire runtime, which is a bad trade on anything battery-powered, and it does nothing at all about the transient brownout problem.
The correct approach is to not use a phone-charging power bank as a Pi supply in the first place, and instead run a buck stage designed around the Pi’s real current profile: adequate bulk input and output capacitance to absorb fast current steps without the regulator needing to react instantaneously, a control loop with fast enough transient response for the load, and — critically — a supply with no charge-completion heuristics to accidentally trip, because it isn’t pretending to be a phone charger.