Hey @SixSixSevenSeven - sorry for the slow reply; I was flying back to the US.
Short version: what youāre seeing looks like the fuel-gauge estimating SoC from an OCV table that doesnāt match your pack/use-case, rather than true coulomb counting. Thatās why you can sit at ~3.4 V and still read ~94%, and then fall off a cliff near cutoff.
A bit of background:
-
The Qualcomm PMIC/FG stack uses a battery profile (voltage-vs-SoC, temp effects, internal resistance, FCC/Qmax) to compute capacity. If the profile or learning state isnāt right, itāll lean on OCV mapping and can be wildly off under load or right after charge.
-
Your pack is 3P (3-cell, ~4.2 V full). The FG needs the correct profile for that chemistry and impedance; otherwise OCVāSoC curves donāt line up. We performed the battery calibration and mapping and installed it into the internal firmware - if this didn't work, the device crashes, so I'll take this bit is working at least!
-
We validated against a simulator and have seen sane discharge on our benches, but weāve also reproduced cases where the OCV-only estimate looks āstuck fullā until the knee.
Could you share a quick snapshot so we can compare apples-to-apples?
# 1) Full dump of the power_supply view
cat /sys/class/power_supply/battery/uevent
# 2) Key live values
cat /sys/class/power_supply/battery/{status,capacity,capacity_raw,voltage_now,voltage_ocv,current_now,charge_counter,health,temp}
# 3) If present, FG sysfs extras
grep -R . /sys/class/power_supply/battery/ | head -n 200
And which image youāre on (headless vs desktop), plus whether anything is powered from the 5 V boost (RPi header) or USB2. Today the SoC algorithm doesnāt account for those external loads explicitly, which can skew how āwork doneā maps to remaining %.
What you can try right now (to nudge learning and get a usable readout):
- One calibration cycle (minimal hassle):
- Charge to full on DC until status=Full, then leave it on charge ~30ā60 min (relaxation).
- Unplug and let it discharge at a steady light/medium load down to auto-shutdown (~3.3 V), avoiding large current spikes and avoiding extra 5 V peripheral load.
- Let it rest 20ā30 min, then recharge to full.This helps the FG update OCV/IR and FCC.
- Sanity-check SoC by voltage (temporary UI):As a stop-gap, treat voltage as a coarse proxy while we sort the profile. Very roughly for a 3S Li-ion at room temp and modest load:
- 4.20 V ā 100%
- 3.95 V ā ~75%
- 3.80 V ā ~50%
- 3.60 V ā ~25%
- 3.45 V ā ~10%
- 3.30 V ā ~0ā3% (knee/cutoff)(Load and temperature shift these noticeably; this is only to avoid nasty surprises.)
- Logging for one run:
while true; do
date '+%F %T'
awk '{printf "Vnow=%.3fV\n",$1/1e6}' /sys/class/power_supply/battery/voltage_now
awk '{printf "Vocv=%.3fV\n",$1/1e6}' /sys/class/power_supply/battery/voltage_ocv
cat /sys/class/power_supply/battery/{capacity,current_now,temp} 2>/dev/null
sleep 60
done | tee battery_log.txt
- If you can share that log from ~100% down past 3.5 V, itāll show whether the FG ever transitions from OCV-to-coulomb-counting and how IR droop maps to load.
What I suspect in your case:
-
The OCV table being used is too āoptimisticā for your pack/IR, so voltage_ocv~3.49 V ā ~94% even while voltage_now~3.41 V under modest background load.
-
Cycle count reporting being 0 suggests the learning state/FCC updates arenāt sticking yet (or that sysfs node isnāt wired on this build).
We can ship a corrected profile once we confirm the deltas (and, if needed, tweak DT/FG params so it favors coulomb counting more aggressively). In the meantime, the voltage-based sanity check above will keep you from getting caught out near the knee.
Appreciate you flagging it and thanks to @radu7 for offering a comparison run!
Thanks
Nick.