Skip to main content

You are here

Measuring VCC via "bandgap" - SOLVED

29 posts / 0 new
Last post
Measuring VCC via "bandgap" - SOLVED

SOLVED: There were two issues - mistake in code and a need to fine tune the reference voltage value 1.1V -> 1.15V

Original post:

Wanted to get RF12mods to test properly and selected "bandgap" VCC for the remote sensor. What could be easier ?
Explained in many details :



  • CapnBry explanation about AREF
  • JeeLabs search on "bandgap"
  • Samples from "Re: Measurement of Bandgap voltage" on

    The reality is that it is simply does not work for me.
    The return ADC numbers are absurd ..

    For AREF=1100mV output is:
    ADC=351 in 20mV units starting at 1V =109 in 10mV units=321 Vcc(200) in mV: 3725

    For AREF=3300mV output is:
    ADC=350 in 20mV units starting at 1V =430 in 10mV units=965 Vcc(200) in mV: 5350


  • HW: JN6 + USB BUB II
  • PWR is 5.01 V ??? Why, it should be 3.3 V, correct?
  • AREF is 3.3 V on ATmega pin 20 ??? Is it not supposed to be 1.1 V ?
  • Almost no differences to vccRead() from bandgap.ino, only Serial output added:

    const long InternalReferenceVoltage = 1100L; unsigned int adcCnt = ADC; Serial.print("ADC="); Serial.println(adcCnt); Serial.print("in 20mV units starting at 1V ="); Serial.println( (((InternalReferenceVoltage/20U) * 1023U)/(adcCnt + 1)) - 50 ); Serial.print("in 10mV units="); Serial.println( ( ((InternalReferenceVoltage * 1023U)/adcCnt) + 5L) / 10L ); Serial.flush();

    and calling it :

    byte x99 = vccRead(VCC_READ_DELAY); Sleepy::loseSomeTime(16); Serial.print("Vcc("); Serial.print( VCC_READ_DELAY ); Serial.print(") in mV: "); Serial.println( (unsigned long) (x99 * 20) + 1000L ); Serial.flush(); Sleepy::loseSomeTime(50);

    Does my USB BUB II provides wrong voltage or ATmega is completely broken?

  • martynj

    @PavelE - if you are reading 5V anywhere on the ATMega and the only power source is from the USB, check the USB solder links.


    If you remember our private discussion a month ago, one of questions was if I need to solder/short-with-jumper on USB BUB II board. I left with impression that nothing to be done.
    So couple of questions, to be sure:

    1) Is PWR=5V for JN6 is (a) acceptable, (b) needed for flashing ATmega or (c) not recommended, for instance because most of Plugs are 3.3V or (d) pretty dangerous ?

    2) Is the internal reference voltage for ATmega328 is 1.1V +-10% always ? Could I measure it with voltmeter somehow (i.e. AREF)?

    3) In post on "Re: Measurement of Bandgap voltage" they recommended different flags which are causing different ADC readings. Are they better than in JCW code or worse for JN6 ?

    // For 168/328 boards const long InternalReferenceVoltage = 1050L; // Adjust this value to your boards specific internal BG voltage x1000 // REFS1 REFS0 --> 0 1, AVcc internal ref. // MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG) ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);

    4) JCW replaced waiting for ADC signal (was in first edition of the code) - "while( ( (ADCSRA & (1<<ADSC)) != 0 ) );" - by a loop with sleep. Do we know why?

    PS: to (1) I've ordered the chip (ATmega328) to replace the current one, potentially broken during my experiments, so do not want to fry it up.


    Regarding the measurement of VGAP with a voltmeter: I think one of the resources on this Vcc-reading method (either on the forum or the blog) mentions this; you can select the internal bandgap as reference, let it measure for a couple of seconds (stabilisation) and then the V_GAP should be on the AREF pin, ready to measure with a DVM.


    The PWR pin is at the supply voltage to the regulator whereas the + pin should be regulated down to 3v3.


    @PavelE - as padvinder describes, Vref is available for DVM measurement - it is slightly easier to probe this on the "hot" side of C3 (this is a decoupling capacitor to reduce the noise present on the signal from the bandgap generator).
    The absolute value of Vbg varies from chip to chip, but once calibrated, tracks temperature well with the formula given in the spec sheet.



    Sorry, but according to JN6 diagram, the PWR on Ports is directly connected to pin 3 of FTDI, meaning that its is NOT regulated by IC2.

    BTW, my VCC is fine - around 3.3V


    @martynj and @padvinder95
    Thanks you for advice, would try it tonight.

    What about the most important 1) ???

    According to JN6 page : "3.3V power regulator which accepts 3.5 … 13V as external power source".

    Do I understand it right?:

  • correct answer is (a)-acceptable
  • I'll still better to put a jumper on USB BUB II to limit PWR to 3.3V
  • JohnO

    Indeed, it isn't regulated. I think it is the input to the regulator - the output of the regulator providing the 3v3 you see on the + connector and into the processor.

    FTDI pin 3, the PWR pins and the input to the regulator are all connected to each other.


    As I understand it:

    • PWR is not really necessary for the JeeNode, as it is connected to nothing---except to the input of the 3V3 regulator. That can indeed handle 3.5 to 13 V, so there 5V is fine.
    • When uploading new code to the ATmega, power (PWR) is provided by the FTDI cable (pin 3), hence the connection from pin 3 to PWR.

    PWR is really the external power supplied to the jeenode. If you're using the AA battery board, it's not even connected by default. So, the two things you need to worry about are:

    • Don't put more than 13V on it (you'll blow the regulator); and
    • Don't supply e.g. 9V externally to the PWR pin while connecting an FTDI cable, as the 5V from the FTDI will then be connected to 9V from an external supply and you'll probably burn the FTDI chip.

    If you're using a USB BUB II to upload code and that only supplies power to PWR, it's not a good idea to limit its voltage to 3V3: that's not enough for the regulator to also supply 3V3. You'll either have to set the BUB to 3V3 and connect its power to the JN's + (3V3) line, or make it at least 3.5V (so 5V) and connect it to PWR.


    Thanks a lot, good post.
    Sorry, was a bit scared about PWR

    So the only puzzle I need to solve is about ADC ... at least begin to understand some things. If we are talking about seconds to stabilize the reference voltage, it is pretty clear why JCW placed sleep code there :)


    > If you're using the AA battery board, it's not even connected by default

    UPDATED: I've got you - you were talking about PWR to Ports on AA board. But PWR on FTDI connector is the output one == 3.3V.

    According to JN6 connection diagram there is no pin from FTDI header - one of options connecting AA board - going to VCC, so it has to go via the power regulator chip (IC2).

    Also when AA board is connected, power should be supplied to PWR for Plugs.

    Actually one measurement I did yesterday was PWR about 3V with AA board connected via FTDI header ...


    The original issue was my misunderstanding and typo, the vccRead() return the correct value on my JN6 when the 1.15V constant is used instead of 1.1V
    const long InternalReferenceVoltage = 1150L;

    Result of the sketch suggests that argument should be >6:
    Vcc(0) in mV: 1120 Vcc(2) in mV: 3320 Vcc(4) in mV: 3320 Vcc(6) in mV: 3320 Vcc(8) in mV: 3300 <<< first good one

    But I was not able to get on AREF anything close to 1.1V, it is always 3.3V ...


    Looking at the schematic (pdf file on, the FTDI pin 3 is connected to the input of the voltage regulator, and the PWR pin on all Ports. I'll admit I have no idea what voltage the FTDI supplies, but I thought it to be 3V3 or 5V. I think an important reason for the omitting of D1 (protection diode in power line from FTDI to regulator input) is that with that additional 0.7V drop, a 3V3 FTDI will never drive the JeeNode.

    The AA board gives you 3 options regarding PWR: leave disconnected (default), as many of the plugs use only VCC (3V3) anyway; connect to 3V3 line (for plugs that do use PWR and need it to be at least as high as VCC); or connect it to the battery, so then it'll carry about 1.2V (or more, if you use other/multiple batteries).

    Concerning your measurement: I suppose you have chosen the second setting for the AA board, i.e. connect the solder jumper between 3V3 and PWR. Why it is then 3V and not 3V3, I wouldn't know.


    As to the calibration of V_gap, take at look at this post: You should set the reference to internal, then perform a couple of analogRead()s on one of the analogue pins; then AREF should read 1.1-ish volts.

    The trick with Vccread is the opposite: VCC is used as reference (the 3V you're measuring) and V_gap is read relative to this. See also these posts from the weblog for the explanation of the vccRead trick. (The thread I posted above also talks about this, but not as clearly as JC. ;-))



    Indeed, FTDI has two jumpers, one for PWR and one [if remember right] for logic levels. As I did nothing, the default is for PWR = 5V.

    AA board [in 1x AA battery configuration] I've left untouched too, so PWR (on Ports) is not connected to anything, but PWR on FTDI connector is 3.3V

    PS: One thing I needed the reference Voltage for is to measure the voltage left in a battery(one inserted into AA board). For now I just connected a resistor (1M) from BATT to A1 on JN6, but should do a voltage divider, of course. If would see JCW tonight, going to discuss if the NC pin on FTDI could be used for BATT measurement.

    BTW - the BATT measurement vs reference is working fine (showing exactly the same as 0.5% DVM) ! Need to clean code, package and check-in into GitHub.


    Thanks for the links. Added to the header :)


    @PavelE, 1MΩ is not suitable. Any I/O pin has a hidden leakage ~2uA at room temperature, sign unknown (meaning the leak can be inwards or outwards). It needs a Thevenin equivalent source resistance of <10KΩ to swamp this leakage to give a chance of reading accurately.

    That is a fundamental problem with monitoring Vsource and maintaining very low total system power consumption. It needs an external controlled FET to 'turn on' the path for sampling if you wish to reach the minimum uA for system sleep.


    I had a similar feelings, but the result was surprisingly precise.

    I've also measured the passing thru the resistor current. It was less than my DVM could measure on 20uA range, when the power was ON (much more with power OFF).

    Indeed, I have to look into a proper voltage divider or extra logic to do it properly, but for now I'm really happy that it is working.

    Finally I only need a precision of 5-10% to turn the WSN OFF (i.e. go to the endless sleep) as soon as AA battery goes below somewhere 0.8-0.9V ;)


    @PavelE, perhaps a different strategy? As the end-of-life battery curve is detected, send out a series of "I'm dying" packets with the remaining energy so there is a positive signal to change the battery.
    No need to set 'endless sleep' - that's automatic ;-)


    I am also using a spare analogue pin to measure the battery voltage on a AA power board. I assume the pin by default starts in "input" mode (which I also assume has a reasonably high impedance), so no resistor or voltage divider should be required. I just put a jumper directly from the battery + rail on one of the port connectors on the AA power board to one of the analogue inputs on the JeeNode and it seems to work perfectly. I detect no perceivable impact on battery life. Is there a flaw in my assumptions?


    @drastica, every I/O pin has a small leakage current as described in #18. For room temperatures it is small and with a direct connection, is less than the quiescent current eaten by the AA power board. When a potential divider is needed (the raw power source is outside the range of the ADC), then this is an issue since the divider current needs to be 50 or more times the leakage current to get any accuracy.

    For your case, perhaps adding a series 10KΩ, parallel 0.1uF is advisable as a filter since the boost convertor feeds back some spikes to the battery. When the internal resistance of the battery increases with age, the spikes become more noticeable.

    Plotting the battery voltage over time as a measure of remaining life is not obvious. The potential varies with temperature and has considerable hysteresis. You can use that effect to your advantage - wake up, check Vb, transmit a packet, check Vb. When the delta Vb starts to grow, the battery is recovering more slowly and for primary cells, shows that end of life is approaching.

    IMHO, the best technique is to plot the temperature corrected Vb and recognise the shape of the end-of-life cliff - there is still enough charge left to send out a few "I'm dying" packets.


    Possible, but then the code on both sides [for WSN setup] gets more complex - to process different packet types. I prefer the common [on this forum] idea to just include couple of bits of voltage indicator into a single data package format.

    I'm branching a separate discussion for the best way of measuring remaining battery power? I want to go into details about different battery types (Eneloop vs Alkaline) and also about different battery setup.


    @PavelE, many ways to skin the same cat. How about a flag in the regular payload?

    'Phew, that last transmission left me feeling really drained'... ;-)


    I'm filling up the header for a new forum discussion "What is the best way to monitor remaining battery power?". Will put references to the most interesting from this thread.


    @martynj - thanks for the comment re low pass filter... the concept of the battery's internal resistance growing had not occurred to me. I presume it explains the noise I see as random small variations the voltage readings... another experiment to tinker with!


    @MartynJ Is it better to go to sleep deliberately when using rechargeable batteries rather than letting them fully discharge.


    @JohnO - yes indeed. Most chemistries dislike (deep discharge)[], and many 'smart' chargers refuse to charge 'flat' cells.

    Premium Drupal Themes by Adaptivethemes