I am designing low-cost SoC (State of Charge) evaluation software for a LiFePo4 battery cell at zero current (actually only a low current due to auto discharge). For this peculiar application, low cost here means we are not likely use a current meter/Coulomb meter.

I am running my software on a BeagleBone AI on pin AIN4 which sustains 1.8 V maximum to which I wired my voltage divider. The pin has a 12-bit signed ADC.

The BeagleBone AI is plugged into a 1S24P battery construction that nominally provides a 12 V voltage 51 A·h capacity.

My divider uses a 10 kohms 100 kohms which gives me a scale factor of 11 (AKA (10+100)/10).

For a 13.1 V read voltage, AIN4 reads 1384 AKA 1.217 V

v = 1384/(1<<11 - 1)*1.8 V

Which turns to 13.387 V once the scale is applied:

Vbat = v*11

I notice that the accuracy is not that great for my purpose, as I use the voltage to match the Soc/voltage cell curve as the curve has two plateaus.

What should I do to improve my accuracy?

  • 3
    \$\begingroup\$ Calibrate it? Tighter tolerance of your resistors with less temperature drift? More bits in your ADC? \$\endgroup\$
    – winny
    Aug 10, 2021 at 8:58
  • 2
    \$\begingroup\$ Have you looked at the specified accuracy of the ADC itself? Until you are certain that the ADC has the accuracy you need there is no point in talking about the divider. Please provide a link to the ADC specifications. \$\endgroup\$ Aug 10, 2021 at 11:57
  • 6
    \$\begingroup\$ Do you just have the voltage divider connected directly to the ADC input pin on your Beagle? If so, have you considered the current drawn from the divider by the Beagle on that pin when it does an ADC conversion, and what effect that has on the divider? If you're taking many fast readings you may need to buffer the voltage with an opamp, or if you're only taking occasional readings then a reasonably-sized capacitor (probably greater than 100nF) would probably work well enough. \$\endgroup\$
    – brhans
    Aug 10, 2021 at 11:59
  • \$\begingroup\$ Is using the voltage divider a requirement? There are ICs on the market that will accurately measure voltage. ICs that provide battery monitoring functionalities also exist. If it is a possibility, I would consider a daughterboard for the Beaglebone with such functionality. It will provide a buffer between your battery and the board, as well as give you more information that your management software can work with (individual cell health for example). \$\endgroup\$
    – Mu3
    Aug 10, 2021 at 12:09
  • 2
    \$\begingroup\$ 100% agree with @brhans.... You're probably neglecting the input impedance of the ADC. Hopefully your datasheet tells you what it is. Buffering with a unity-gain opamp may help. A capacitor on the input pin is "mandatory" \$\endgroup\$
    – Kyle B
    Aug 10, 2021 at 13:21

3 Answers 3


There are several things that can be done to improve the accuracy of your measurements:

  1. Try using more of the full scale range of the ADC. If the maximum is 1.8V, and your max battery voltage is 16.4V, try a scale factor of 9.5 instead of 11.

  2. Use resistors with tighter tolerances (try 0.1% or better) and better specifications for temperature drift.

  3. Calibrate the ADC output. Most ADCs have non-ideal offset and nonlinearity that you can calibrate out in hardware or software. One way to do this in software is to take measurements across the full range of ADC inputs and match the curve of measurements to an interpolation function. Then use the interpolation function to scale the ADC output.

  • 3
    \$\begingroup\$ Remember that tolerance isn't as important here as matching; resistor networks are available with much better matching than tolerance, usually for less money than getting two tight-tolerance resistors. \$\endgroup\$
    – Hearth
    Aug 10, 2021 at 14:16
  • 2
    \$\begingroup\$ 0.1% tolerance is pointless for this application. Li batteries are WAY less reproducible in regard to V vs SoC \$\endgroup\$
    – fraxinus
    Aug 10, 2021 at 17:17

12 bits = \$2^{12}\$ = 4096 counts/scale.

If signed and 0b = 0V, then 1.8V = 4096/2 = 2048 (and -1.8V = -2048, ignoring the final bit.)
1.8V/2048 = ~88µV/bit. That is the smallest "step size" detectable in this configuration (using all available dynamic range.)

Since the divider is "dividing" by 11, 88µV/bit * 11 = 9.7mV battery voltage "step" size, best-case.

To achieve more resolution, either use non-signed 0-1.8V full-scale if available (twice the resolution, 44µV/bit), more bits (better (slower) ADC), and/or averaging (oversampling.) Will likely have to oversample anyways, as noise is going to be more of an issue at these low voltages.

Can somewhat reduce sampling noise by reducing the values of the divider resistors (an order of magnitude at least) and switching them into the circuit only when needed. Higher divider current = lower noise.

Also investigate the floating-point math library used in your MCU. Some utilize 24-bit exponent-mantissa format, which can lead to significant rounding errors over just a few operations. Create a test routine to quantify this error.

Finally, measuring battery voltage may not be the best indicator of State of Charge, especially for lithium types. Investigate "Coulomb-counting" and similar SoC devices. These track/calculate the amount of charge in the battery by keeping track of the power in, power out, and even the number of cycles (degeneration.)

  • \$\begingroup\$ Thanks! This use case is only for low cost solution, hence the voltag meter. \$\endgroup\$ Aug 10, 2021 at 13:40

The BeagleBone just uses the 1.8V digital Vdd as a reference, so any error in that will cause a proportional error in the ADC reading. The datasheet limits at room temperature are +/-2% for that.

On top of that there is your resistor tolerance and any errors due to the ADC input impedance. And ADC errors themselves.

You could provide a more accurate external reference (there's no way provided on the board for that, but there's a 0\$\Omega\$ resistor that could be removed). Or provide a reference voltage and measure that and scale the reading by the filtered reference. For example, a 1.225V 0.1% reference.

You could just calibrate the reading by storing a span calibration factor but that would drift as the LDO in the PMIC warms and cools. I don't see a temperature drift specification.

If you use thin-film 0.1% 25ppm/°C resistors and an external reference and calibrate the reading (single-point calibration) you should be able to get one or two orders of magnitude improvement for a parts cost delta of $1.50-ish.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.