Last month I was working on a battery management board for a portable instrument. Two cells in series (2S, 8.4 V max), current draw between 50 mA standby and 3 A peak during motor activation. I needed a current sense amplifier on the high side to feed an MCU's ADC — or ideally something with I2C so I could skip the ADC channel entirely.
This is the kind of decision that sounds simple until you start looking at gain error vs. common-mode voltage vs. bus voltage range vs. what's actually in stock at JLCPCB. Here's how I worked through it.
The requirements
Before opening any datasheets, I wrote down what I actually needed:
| Parameter | Requirement |
|---|---|
| Topology | High-side sensing |
| Bus voltage | 0 to 8.4 V (2S Li-ion) |
| Current range | 50 mA to 3 A continuous, 5 A fault |
| Shunt resistor | 10 mΩ (30 mV at 3 A — tolerable drop) |
| Output | I2C preferred, analog acceptable |
| Supply | 3.3 V logic rail available |
| Package | Something hand-solderable for prototyping |
The shunt voltage at full load is only 30 mV, so gain error and offset voltage matter a lot. A part with 1 mV offset would eat 3% of my signal at full scale.
Three candidates
I started with three parts I've used before or seen recommended in app notes:
- INA219 — TI's workhorse I2C current/power monitor. 12-bit ADC, up to 26 V bus. Everywhere.
- INA226 — The INA219's successor. 16-bit ADC, alert pin, better accuracy. A bit more expensive.
- ZXCT1009 — Diodes Inc. analog high-side monitor. SOT-23, dead simple, dirt cheap.
Comparing the specs
Here's where it gets interesting. The datasheets for these three parts total about 140 pages combined. Instead of flipping between PDFs, I pulled the key specs side by side.
The comparison reveals some important differences:
| Spec | INA219 | INA226 | ZXCT1009 |
|---|---|---|---|
| Output type | I2C (12-bit) | I2C (16-bit) | Analog voltage |
| Bus voltage range | 0 – 26 V | 0 – 36 V | 2.5 – 20 V |
| Max common-mode | 26 V | 36 V | 20 V |
| Offset voltage | ±200 μV max (A-grade) | ±10 μV max | ±5 mV max |
| Gain error | ±1.0% (A-grade) | ±0.1% | ±2% |
| Supply range | 3.0 – 5.5 V | 2.7 – 5.5 V | 2.5 – 20 V |
| Quiescent current | 1 mA | 330 μA | 4 μA |
| Package | SOT-23-8 | MSOP-10 | SOT-23-3 |
| Approx. unit price | $0.80 | $1.60 | $0.30 |
A few things jump out immediately:
The ZXCT1009 is tempting but wrong here. At 30 mV full-scale shunt voltage, its ±5 mV offset eats 16% of the signal. That's not a rounding error — that's the difference between reading 3.0 A and 2.5 A. For high-current applications with low shunt resistance, you need a part with microvolts of offset, not millivolts.
The INA226 is dramatically better than the INA219 on offset. 10 μV vs 200 μV (A-grade). At 30 mV full scale, that's the difference between 0.03% and 0.67% offset error. For a battery gauge, that matters over days of integration.
The INA219 has a higher quiescent current. 1 mA vs 330 μA. On a battery-powered device, this is worth thinking about — but honestly, if your load is 50 mA to 3 A, the difference between 330 μA and 1 mA in the sense amp isn't what's going to kill your battery life.
Checking the operating conditions
The next step is making sure the part actually works in my circuit. This is where people get burned — a part can have great specs on paper but not support your specific voltage/current combination.
For the INA226, the critical check is: can it handle an 8.4 V bus (2S fully charged) while running from a 3.3 V supply?
From the datasheet's recommended operating conditions:
- Bus voltage: 0 to 36 V — well within range
- Common-mode voltage: 0 to 36 V — fine
- Supply voltage: 2.7 to 5.5 V — 3.3 V works
- The bus voltage is independent of the supply rail, so running V_S = 3.3 V with V_BUS = 8.4 V is explicitly supported
This is one of those things that's easy to miss. Some current sense amps require V_S ≥ V_BUS, which would force you to run the sense amp from the battery voltage instead of the logic rail — adding complexity and noise.
The register configuration
Since I'm going with the INA226, I need to figure out the register setup. The calibration register determines the LSB size for current and power readings.
With a 10 mΩ shunt, the math works out to:
This gives us:
- Current resolution: ~153 μA per bit (plenty for 50 mA – 5 A range)
- Power resolution: 25 × Current_LSB = 3.8 mW per bit
- Max readable current: 153 μA × 32768 = 5.01 A
The default configuration register value (0x4127) sets averaging to 1 sample, conversion time to 1.1 ms for both bus and shunt — reasonable for a first bring-up. I'll probably increase averaging to 16 or 64 samples in firmware later to smooth out the PWM ripple from the motor driver.
I2C address planning
The INA226 uses two address pins (A0, A1) with four states each (GND, V_S, SDA, SCL), giving 16 possible addresses from 0x40 to 0x4F. With both pins tied to GND, the address is 0x40.
Since I might add a second INA226 on the 5 V rail later, I'll tie A0 to GND and leave a 0-ohm resistor footprint on A1 for future flexibility. That gives me 0x40 now and 0x44 if I populate the second one.
Layout considerations
A few things from the INA226 datasheet's layout section that are worth calling out:
-
Kelvin connections to the shunt. The IN+ and IN– pins must connect directly to the shunt resistor pads, not to the power trace. This is the single most common mistake with current sense designs — routing through the power plane adds milliohms of parasitic resistance that the amplifier measures as real current.
-
Decoupling. 100 nF ceramic on V_S, placed close to the pin. Standard stuff, but the datasheet specifically warns that inadequate decoupling causes oscillation on the internal voltage reference.
-
Shunt resistor placement. The shunt needs to handle I²R heating. At 3 A through 10 mΩ, that's 90 mW — trivial for a 2512 resistor, but worth checking the thermal derating curve if you're using a smaller package.
Final schematic
The complete sense circuit has five components:
Total BOM addition: the INA226, a 10 mΩ shunt, one 100 nF cap, and two pull-ups (probably already on the I2C bus). The ALERT pin is a nice bonus — I configured it as an over-current latch at 4 A so the firmware doesn't have to poll continuously.
What I'd do differently next time
Looking back, the main thing I underestimated was how much the shunt resistance matters for the dynamic range. At 10 mΩ, my 50 mA standby current produces only 0.5 mV across the shunt — that's just 3 LSBs on the INA226 with my calibration. It works, but it's at the noise floor.
If I were redesigning today, I'd consider a 50 mΩ shunt instead. Yes, the voltage drop at 3 A increases to 150 mV (still under 2% of the bus voltage), but the standby measurement jumps to 2.5 mV — a much more comfortable 16 LSBs. Sometimes the boring component choices matter more than the flashy ones.
Key takeaways
-
Offset voltage is the spec that matters most for low-shunt-resistance designs. It's easy to get distracted by ADC resolution, but if your offset is 10% of full-scale, those extra bits are just measuring noise.
-
Check that V_S and V_BUS can be independent. Not all sense amps support this, and it's not always obvious from the headline specs.
-
Do the calibration math before choosing the shunt. The LSB size, maximum readable current, and minimum detectable current are all coupled — you can't optimize them independently.
-
Kelvin-connect the sense pins. This is in every app note and every layout guide, and people still get it wrong. If you're troubleshooting a current sense circuit that reads 15% high, check your routing first.