It can be nice to know how much battery power you have. It becomes critically important with LiPo batteries since you can permanently damage them by running the voltage down too low. Typically battery voltage detection requires adding a circuit with extra parts and their associated power requirements. Wouldn’t it be great to be able to do this using nothing but software? Read on for a no parts, no pins, no power solution…
Normal Low Battery Detector Circuit
Here is a typical by-the-book low battery detector for LiPo-powered devices…
The voltage divider R5/R9 scales down the battery voltage, where it is compared to an integrated reference voltage inside U3, which outputs a LOWBAT signal that would typically connect to an input pin on your micro-controller.
This circuit works fine and will indicate when the battery voltage drops below the threshold voltage (about 3.6 volts with the above values), but it has a few drawbacks…
- The voltage divider formed by R5 and R9 is always drawing current – 12uA at the low cutout voltage.
- The comparitor U3 is always drawing current – typically ~2.5uA at the cutout voltage.
- The pull-up resistor R6 is drawing ~7.6uA whenever there is a low battery.
- Requires a dedicated input pin on your micro-controller.
- Requires 5 physical parts that cost money and use up board space.
- Can only detect a single hardwired threshold voltage.
- The threshold voltage depends on the tolerances of R5 and R9, and there is no way to calibrate it.
Do we really need 5 parts, an input pin, and >20uA of constant power draw just to detect a low battery?
Do we really need 5 parts, an input pin, and 20uA of constant power draw just to detect a dead battery?
Power is precious, especially if you are using an adorably small LiPo battery. And this circuit continues to pull power even after it has detected a low battery condition- there is no way to turn it off. We can do better…
The Zero Part, Zero Pin, Zero Quiescent Power Solution
Thanks to the AVR’s flexible analog-to-digital converter, you can accurately detect battery voltage completely in software, without sacrificing a single pin or adding a single part to your design! And it does not draw any power when not in use! Yeay!
From the datasheet…
The ADC converts an analog input voltage to a 10-bit digital value through successive approximation. The minimum value represents GND and the maximum value represents the reference voltage.The voltage reference for the ADC may be selected by writing to the REFS1:0 bits in ADMUX. The VCC supply, the AREF pin or an internal 1.1V voltage reference may be selected as the ADC voltage reference.
Typically you would be measuring an unknown voltage (like an input pin) against a known scale (a reference voltage). Our trick is that we are going to do the opposite – we are going to measure a known voltage (the internal 1.1 volt reference) using an unknown scale (the Vcc voltage). Normally it would be silly to measure a known voltage (we already know what it is!), but in this case it will let us reverse-calculate the reference voltage. I wonder if this is what the engineers who designed this chip had in mind when they made it possible to use the internal reference as a input?
Normally it would be silly to measure a known voltage (we already know what it is!), but in this case it will let us reverse-calculate the reference voltage.
Here is a diagram of the analog-to-digital block with the two sources we will be using highlighted…
How do we actually compute the Vcc voltage? Back in the data sheet we find…
ADC here is the result value output by the analog to digital converter.
In our case, Vin is the internal 1.1 volt reference voltage and Vref is the Vcc power supply voltage. If we substitute those in, we get…
…and (if you were awake the 3rd week of 7th grade) algebra gives us…
Vcc = (1.1v * 1024) / ADC
It is so simple a child could do it! We can now compute the current Vcc voltage based solely on the output of the analog to digital converter! But what are we actually doing here?
Imagine that I gave you a stick that had 1024 evenly spaced markings along the length of it. I also gave you another shorter stick and told you that it was exactly 1.1 feet long. Could you figure out how long the longer stick was?
Of course you could! All those LSAT prep classes weren’t a waste after all!
You would take the short stick and measure it with the longer stick and count how many marks long it was. Let’s say it was 250 marks long. So…
250 marks = 1.1 inches
1 mark = 1.1 inches/ 250
1 mark = 0.0044 feet
If 1 mark is 0.0044 feet, and we know the long stick is 1024 marks long, then we know that the long stick is 1024 marks * 0.0044 feet per mark = 4.5056 feet. Our long stick is ~4.5 feet long!
Now change [feet] to [volts] and [marks] to [steps of the analog to digital converter] and… we measured the 1.1 internal reference voltage using a scale that is based on our unknown Vcc voltage and we got an ADC value of 250. This means that our Vcc is at ~4.5 volts!
How precise is this technique? The higher the Vcc, the lower our resolution so let’s take the worst case which is at the device’s maximum allowed Vcc of 5.5 volts. At this limit, a step of the ADC is equal to ~5mV. That is a couple of orders of magnitude more resolution than we need for competent state-of-charge battery measurements, which typically only call for 10ths of volts of resolution.
How accurate is this technique? The two main sources of inaccuracy are (1) the fact that the internal reference can range from 1.0 volts to 1.2 volts depending on manufacturing processes, and (2) the inherent inaccuracies of the ADC. Practically speaking I’ve found these Vcc measurements to be accurate to within 0.1 volts right out of the box. If you were going to use these measurements for, say, detecting the cut-off charging voltage for a LiPo battery, then you could calibrate the exact ADC measurement that matched the target voltage for each individual device and probably get within 10’s of millivolts.
Enough chat chat! Show me the code!
Q: Since the bandgap voltage reference is 1.1 volts, doesn’t this limit the minimum supply voltage I can measure to 1.1 volts?
A: Theoretically yes, but since a typical AVR cuts out at either 2.7 volts (or 1.8 volts for V series parts), this is not a practical limitation since the chip would already be non-functional.
Q: Won’t the battery automatically disconnect before the voltage gets low enough to damage it?
A: Some LiPo batteries come with a protection board attached and this board will typically disconnect when the voltage drops dangerously low, but not all batteries have this board – and you still probably don’t want to let your batteries get low enough to trigger the board since the number of cycles a battery can survive is dependent on the depth of discharge.
Q: Doesn’t the datasheet say that “Internal voltage reference options may not be used if an external voltage is being applied to the AREF pin”, which would imply that you would loose the use of the AREF pin (pin 13) for other functions?
A: The datasheet also says that when “Vcc [is] used as analog reference, [the ADC is] disconnected from PA0 (AREF)”, which make sense. Hmmm… I’ve actually tested this and applying an external voltage to pin 13 does not seem to affect the ability to use the internal reference at all. I have an open case with Atmel to get a clarification on this and will report back.
UPDATE 11/11/2014- I got a clarification from Atmel that on the ATTINYx4A the AREF pin is, in fact, disconnected when the Vcc is used for the Vref. My guess is that the conflicting sentence was mis-copy/pasted from another part like the ATMEGA48A which does apparently have this limitation…Q: Its not really fair to say that this solution uses _no_ power since the ADC does use power.
A: True, the ADC does draw a tiny bit of power (100’s of uA) while it is actually doing a conversion, each conversion only takes a tiny bit of time and the rest of the time you can disable the ADC. Most importantly, the ADC is not drawing any additional current when the chip is sleeping and in shut down because of a low battery.
Q: I’m trying to do low battery detection on an ATTINY25/45/85, but I can’t figure out how to set Vin to the internal reference?
A: Apparently the ATTINYx5 does not have a Vin connection for the internal reference, so we have to get a bit more tricky. The basic idea is to do two samples – first sample the internal temp sensor using the internal 1.1v as Vref, and then sample the temp sensor again, but using the Vcc as the Vref. Since the voltage of the temp sensor is very low, you will not get great resolution but it should still be good enough for battery level gauging, and you can again do some calibration if you need more accuracy.