Become a subscriber (Free)

Join 29,000 other subscribers to receive subscriber sale discounts and other free resources.
:
:
Don't worry -- youre-mail address is totally secure. I promise to use it only to send you MicroZine.

Arduino Voltage Reference

There is an Arduino Voltage Reference (1.1V) built into some Arduino microcontrollers. The Uno and the Nano both have one, and quite a few of the other Arduinos have them.


You usually set up the Arduino ADC using the microcontroller power supply as a voltage reference (since it is easy! and it is the default mode of Arduino software). The trouble with that is the power supply chip will then define the accuracy of your measurement i.e. you won't have a clue if it is accurate or stable with temperature.

Note: Although the Internal Arduino Voltage Reference is stable with temperature and voltage, its initial value varies between chips (probably due to differences in chip manufacture). it needs calibration.

The internal reference is useful when you don't want to go to the trouble of adding an external chip to figure out voltages and need a more stable reference than Vcc or where the supply voltage changes.

For instance the Arduino Uno/Nano can operate from 1V8 to 5V5 and using two AA cells would allow operation (but only if you set the clock to 4MHz - see the datasheet section 29.3 "Speed Grades"). You can use the internal voltage reference to monitor the state of the battery - with no extra components.

This page attempts to quantify, in a small way, whether or not the Arduino voltage reference is any good or not.

Bandgap Voltage Reference

The type of reference in the ATMega328P is a bandgap type. This uses two elements, one with the negative temperature coefficient and one with a positive temperature coefficient which cancel out temperature effects.

While not giving you ultra precise voltage readings in the Arduino, the circuit is designed to be stable against changes in temperature and supply voltage.

This type of circuit layout is used in state of the art references e.g. MAX6143. However, in the ATMega328 and similar, the process to control the layout of the chip on silicon is not as well defined and does not use laser trimming, hence the poor initial accuracy of the Arduino voltage reference (±9%).

You can find out how to eliminate this offset later in this page.

Note: If you use an external reference the ADC measurement will be more accurate since you control the chip specification.
However, remember the internal ADC in the Arduino is not too accurate anyway (see ATMega328 datasheet:Absolute accuracy 2LSB (including INL, DNL, quantization, gain and offset errors).

Warning: Never use an external voltage reference and at the same time enable the internal reference - something will break!

Uses for the Arduino Voltage Reference

The Arduino voltage reference can be used in one of five different ways:
  1. For brown-out detection (See datasheet to enable).
  2. As a measurement value in the ADC (fed in to one of the inputs).
  3. As the reference for ADC measurements.
  4. As an input to the comparator.
  5. Temperature measurement (The ADC must use the internal reference).

Brown out detection

Brown-out detection allows the processor to identify when the supply voltage has dipped below a threshold but has not completely gone to zero. This is used to flag to the processor that memory may have been written badly. It just provides an extra layer of reliability to an application.

An input to the ADC

Measuring the reference at an ADC input would allow calibration of a different reference source e.g. the supply (see here) or as a crude comparison to other ADC inputs (unless you calibrate the reference first as shown in this page - in which case it could be quite accurate (~1%)).

ADC reference

Using the Arduino voltage reference as you would expect it to be used!

TIP: Using the 1V1 reference means the 10 bit ADC has an LSB value of  ~1mV (1.074mV/LSB).

Comparator input

Using the voltage reference allows crude comparison i.e you can only compare any input voltage to 1V1. One interesting point is that any of the ADC inputs can be compared by the comparator - and that is without using any more external components. See section 23.2 of the datasheet labelled "Analog Comparator Multiplexed Input".

You could ask the question "Why bother using the comparator when you can easily calculate the result using the ADC?" The answer is speed.

The comparator can compare two voltages within 100s of nanoseconds whereas the ADC is a successive approximation type and takes about 13us to gather the ADC value. This value has to be retrieved by the processor and then you would compare the value to a limit setting, taking far more time.

Temperature Measurement

Since the Arduino voltage reference is independent of temperature it can be compared to the output of a temperature dependent circuit - a circuit inside the chip. This allows you to measure temperature in the ATMega328P.

The temperature sensing element in the ADC can be set to one of the ADC inputs. The datasheet states that the temperature coefficient is 1mV/°C but that the initial accuracy is ±10°C due to process variation in chip manufacture. (See section 24.8 of the datasheet labelled "Temperature Measurement"). To get an accurate reading requires calibration of this system.

Arduino Voltage Reference Performance

The information in the datasheet on the Arduino voltage reference states that it has maximum and minimum values of 1.0V ~ 1.2V, and nominally 1V1. Other than this there is no more information at all.

There is no information about repeatability or stability. It suggests that the voltage could vary by ±9% around 1.1V.

So the real question is:

    Is the Arduino voltage reference any good at all?

The specification seems to imply that it might vary ±9% at any time. In fact this is not true and the voltage reference is far better, and quite useful.

On this page there are some voltage reference measurements - these are not exhaustive but will give you a flavour of the bandgap reference performance.

Arduino voltage reference Questions

Questions asked here are:
  • How does the reference voltage change with temperature?
  • How does the reference voltage change with Vcc?
  • How stable is the reference voltage in general?
Remember these measurements are based on testing a few chips and one or two sets of measurements. They will therefore give an impression and not the absolute answer.

Note: All voltage measurements were made using an ADS1115 on a breakout board. All voltage measurements were made in ADS1115 differential mode. Temperature measurements were made using an MAX6675 and type J thermocouple.

Initial Accuracy

The initial accuracy is bad at ±9% but calibrating the Arduino voltage reference allows you to eliminate this error.

Note: The MAX6143 has an initial accuracy of 0.05% (180 times better c.f. 9%).

Output Stability

Two boards are measured, the first is s standard Arduino uno board and the second is an Arduino Nano board. These both use the same processor ATMega328P.

Measurements made on different time/days of an Arduino Uno powered from the USB (hub) power supply gave the following results:

Arduino Uno USB Stability Measurements

Arduino Uno (PDIP)
USB (HUB) Power Supply
Voltage (Ambient temp)
% error (5V)
Internal
Reference
% error (1V1)
4.806V (21°C) Diff
3.9%
1.104V Diff
0.36%
4.826V (16°C) Diff 3.5%
1.097V Diff
0.27%
4.862V (22°C) Diff 2.8%
1.0976V Diff
0.22%
4.878V (21°C) Diff 2.4%
1.0980V Diff
0.18%
4.842V (20°C) Diff 3.2%
1.0975V Diff
0.23%
4.809V (19.5°C) Diff 3.8%
1.0963V Diff
0.34%
4.788V (23°C) Diff
4.2%
1.0957V Diff
0.39%
4.866V (23°C) Diff 2.8% 1.0956V Diff
0.39%
4.853V (20°C) Diff 17/2/20 2.9%
1.0958V Diff
0.38%
4.876V (17°C) Diff 18/2/20
2.5%
1.0961V Diff
0.35%
4.860V (18°C) Diff 24/2/20 2.8%
1.0957V Diff
0.39%

Max error change for Vcc  =  4.2  - 2.4   = 1.80 %
Max error change for Vref = 0.39 - 0.18 = 0.21%

Measurements made on different time/days of an Arduino Nano powered from a PC USB port gave the following results:

Arduino Nano USB Stability Measurements

Arduino Nano (MSOP)
USB (PC) Power Supply
Voltage (Ambient temp)
% error (5V)
Internal
Reference
% error (1V1)
4.821V (20°C) 3.6%
1.070V
2.72%
4.824V (16°C) 3.5%
1.069V
2.81%
4.831V (17°C) Diff
3.4%
1.068V Diff
2.91%
4.825V (22°C) Diff
3.5%
1.068V Diff
2.91%
4.851V (21°C) Diff 3.0%
1.068V Diff
2.91%
4.852V (15°C) Diff 3.0% 1.069V Diff
2.81%
4.830V (23°C) Diff 3.4%
1.067V Diff 3.00%
4.833V (20°C) Diff 17/2/20 3.3%
1.067V Diff
3.00%
4.862V (17°C) Diff 19/2/20 2.8%
1.0691V Diff
2.81%
4.879V (20°C) Diff 21/2/20
2.4%
1.0715V Diff
2.69%

Max error change for Vcc  =  3.6  - 2.4   = 1.20 %
Max error change for Vref =  3.00 - 2.69 = 0.31%

The USB voltage varies by 2.4% to 3.6% and this does not have a big effect on the error variation in the reference (See voltage measurements below).

Notice how the reference voltage remains constant i.e. has a constant offset error. Even though the voltage reference starts off from a value of 1.070V it keeps close to that value. This is probably due to the manufacturing process and seems to remain constant over time.

For the top set of results, the supply is taken from a USB hub with its own power output while for the bottom it is a direct PC USB output. The latter seems a little more stable (Nano).

In both cases using the on board internal voltage reference will give a more consistent result as it will have tighter voltage regulation.

Note: Remember you are either using the 5V USB supply directly (when working on the bench) or using an external power block. The on board 5V regulator - LD1117AG (same as NCP1117) - has a tighter error spec (0.1V in 5V = 2%) than USB power (see supply sensitivity measurements below).

Conclusion on Stability

Even though the Arduino voltage reference has an initial offset error (probably due to the manufacturing process) the stability of the reference remains very good. with measurements here showing between 0.21% ~ 0.31% change.

Voltage Supply Stability

Using an ATMega382p on a solderless breadboard and connected to a variable supply voltage.

Supply Stability Measurements

Supply Voltage

Internal
Reference
% Initial error
change(1V1).
5.261V (20°C) Diff 1.0995V Diff
0.05%
4.948V (20°C) Diff 1.0988V Diff
0.11%
4.389V (20°C) Diff 1.0980V Diff
0.18%
4.056V (20°C) Diff 1.0975V Diff
0.23%
3.615V (20°C) Diff 1.0971V Diff
0.26%
3.370V (20°C) Diff 1.0968V Diff
0.29%
2.759V (20°C) Diff 1.0965V Diff
0.32%
Note: The reference produced odd values at 2.3V so they are not included. The reason is that the maximum clock speed allowed is proportional to the supply voltage - should lower clock speed to 4MHz for operation at 1V8 (See datasheet section 29.3 Speed Grades - safe operating area).

The error changes by -1.2mV per Supply volt drop when starting from from 5.26V
This is -.11% per supply volt drop.

    calculation: [ (1.0965-1.0995)/(2.759-5.261) ].

TCL
proc perr {max val} {
   puts [expr  { (($max-$val)/$max)*100.0 } ]
}

Conclusion on Supply Voltage

The bandgap voltage reference seems quite good, being insensitive to supply voltage changes. It drops by 1.2mV per supply volt drop starting at 0.05% error at 5.26V supply. If the supply is held constant then this offset error can also be eliminated by calibrating the reference.

Temperature Stability

Using a thermocouple (type J) with the MAX6675 chip and the MSOP Arduino Nano. Heating the chip for a minute and waiting until the temperature stabilised. The MAX6675 thermocouple has an offset temperature error but what we really want is the change in temperature and how that relates to the reference output. The ambient temperature is also measured using a different device to give a reference point for the thermocouple.

Arduino Nano Temperature Measurements

For the Nano ambient temperature measured by the thermocouple is 24.5°C (original thermometer says 23°C) so quite close. Chip temperature is 30°C.

1st measurement:
  • Vref is 1.0674V.
  • Vref is 1.0659kV heated chip to 75°C

Drop is : -1.5mV

Change over temperature

For a 35°C temperature change the reference voltage changes by -1.5mV. roughly -1.5/35 = -0.043mV/°C. However this is based only on one device and one measurement!

    Change is -0.043mv/°C

For a temperature increase from 25°C to 125°C (100°C delta) the reference should drop by 4.28mV. In percentage terms that is (4.28e-3/1.1)*100 = 0.39%.

For a temperature decrease from 25°C to -40°C (-65°C delta) the reference should increase by 2.79mV. In percentage terms that is (2.79e-3/1.1)*65 = 0.16%.

If you consider a simple transistor that has a -2.1mV/°C temperature change then for the same temperature delta you would get a 201mV voltage change (18.2% change) so the bandgap circuit is doing quite well!

2nd measurement:
  • Vref is 1.0665V.Temp 30°C
  • Vref is 1.0652kV heated chip to 75°C
Drop is : -1.3mV - So this is a similar result to the first one.

3rd measurement:
  • Vref is 1.0688V.Temp 30°C
  • Vref is 1.0683kV heated chip to 75°C
Drop is : -0.5mV - A little different, but in the same range.

Conclusion on Temperature

The temperature performance is good with only 0.55% reference change over the full temperature range (estimated from 35°C to 75°C results).

The reference voltage changes by 0.003% per °C (estimated) [ 0.55%/165 (estimated) ].

Note: The MAX6143 has 1000 times better temperature performance at 3ppm/°C.

Over the full temperature range (-40°C to +125°C) the reference will change by about 0.55% (0.39% + 0.16%) = 0.55% (from 1V1) which is not too bad.

The voltage reference should change by +2.79mV ~ -4.28mV (from 1V1) over these temperatures.

Conclusions on the Arduino Voltage Reference

The reference can have a large offset (due to the manufacturing process) ±9% so its initial accuracy can be bad.

Supply voltage sensitivity: ~-1.2mV per Supply volt drop.
        This is ~-.11% per supply volt drop.

Temperature stability: ~0.003% per °C (estimated)    
        ~0.55% over the full temperature range.

Output voltage stability: ~0.31%

To get the best results from the Arduino voltage reference you should calibrate it. This will then eliminate offset voltages due to manufacturing process and supply volt sensitivity (if the voltage source remains constant i.e. supplied through a regulator).

This will then give a stability of 0.55+0.31 = ~0.86%.

Remember this is an estimate based on very few samples, so your results may vary, but it does show that the reference can be made more stable if calibrated. It also shows that the Arduino voltage reference may be more useful than you imagined.

How to Measure Supply Voltage

You can operate the microcontroller (ATMega328p - Uno, Nano) from between 1V8 and 5V5. The microcontroller can not detect this "real" value of the supply voltage this unless you use a known reference voltage to figure it out. This is because the ADC measures everything relative to a reference i.e. the supply voltage is the reference!

Warning: At VCC=4.5V clock can be 20MHz and at VCC=2.7V the clock speed must be <= 10MHz, and for VCC=1.8V the clock speed must be <= 4MHz). See section "29.3 Speed Grades" which shows that the clock frequency must be linearly reduced with decreasing supply voltage.

It is a sort-of reverse method of ADC measurement. Instead of using the voltage reference as a "reference" you use the supply voltage as the reference and the "Arduino internal voltage reference" as the quantity to be measured.

It is done in this way since you can't select the Vcc voltage as an input to the ADC. See the "ADC Mux block diagram" below.

In this case the Supply voltage "reference" is worth:

    VBIN = VCC/1024  V/LSB   [ pow(2,10) = 1024]

In the above equation VCC is unknown (to the microcontroller!).

By measuring the 1V1 reference, and obtaining the ADC value for it you can solve the equation

    VBIN = VREF / ADCVALUE

Therefore:

    VCC/1024 = VREF / ADCVALUE

So

    VCC = 1024 * (VREF / ADCVALUE)

and...

    VCC = 1024 * (1V1 / ADCVALUE)

Here 1024 is correct (1024 is the divisor of VCC for the reference voltage).

TIP: TIP: For a better result calibrate the Arduino voltage reference.

To figure out a value of the supply voltage using the Arduino voltage reference:

  • Set the ADC reference source to Vcc.
    (This is an option in the ADC mux - see diagram below)
  • Take an ADC reading of the Bandgap voltage (Arduino voltage reference).
You can use the equations above to calculate the supply voltage or follow the example below.

Example Sketch1 Measuring Supply Voltage

Put the following code into your sketch within the setup() function.

If you calibrate the reference then change the value of ...
	arduinoADCcal 

...to your measured value. The representation of 1.1V is 11000 which is a fixed decimal point representation where the decimal point is assumed to be one place to the right. So you can think of 11000 representing the number of 0.1mVs in the actual voltage i.e. 11000 x 0.1e-3 = 1.1V

Using an ADS1115 or good voltmeter will give you enough digits. If you use a standard DVM then you will only get 3 digits  (on a 2 volt range) so set the last two digits to zero.

////////////////////////////////////////////////////////////////
void selfMeasureVcc(char *buf) {
uint8_t low,high; // ADC bytes.
// Default reference value. Set this to your measured reference voltage (or leave as is).
// The value uses an integer fixed point representation
// with the assumed decimal point one place to the right.
static unsigned long arduinoADCcal = 11000;

   if (strlen(buf)>1) {
      if (strlen(buf)<6)
         Serial.print(F("Not enough digits"));

      else if (strlen(buf)>6)
         Serial.print(F("Too many digits"));
      else
         arduinoADCcal = atoi(&buf[1]); // delay<nnn>

   } else if (strlen(buf)==1)
      Serial.print(F("Ref calibration value: ")); Serial.println(arduinoADCcal);


   // ADCSRA |= _BV(ADEN); // Enable ADC. Enabled by init() in Arduino code.

   ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // Set VCC ref and band gap as input.
   delay(2); // Vref settling time delay

   // Throw away 1st result as datasheet says
   // After switch, ref may be invalid.
   // Datasheet: "24.5.2 ADC Voltage Reference".
   ADCSRA |= _BV(ADSC); // Start conversion
   while ( bit_is_set(ADCSRA, ADSC) ); // Wait for conversion complete.

   ADCSRA |= _BV(ADSC); // Start conversion
   while ( bit_is_set(ADCSRA, ADSC) ); // Wait for conversion complete.

   // ADCL must be read first, then ADCH, to ensure that the content
   // of the Data Registers belongs to the same conversion
   // Datasheet Section "24.2 Overview"
   low = ADCL;  // Read ADCL first which blocks ADCH updates.
   high = ADCH; // After reading ADCH both registers can be updated by the chip.

   long ADCValue = (high << 8) | low;
   Serial.print(F("ADC value of 1V1 ref: "));  Serial.println(ADCValue);

   #define BINS 1024L // VCC/1024 is the value of each LSB of the ADC.

   Serial.println( (arduinoADCcal)* BINS );
   Serial.println( ((arduinoADCcal * BINS)+5L) );
   Serial.println( ((arduinoADCcal * BINS)+5L) / 10L );

   // Note +5 = middle of LSB bin
   // Calculate Vcc (in mV); 1125300 = 1.1*1024*1000
   // Here ccal value is 1.1*10e4 so no need for *1000 and must divide by 10.

   uint32_t res = (((arduinoADCcal * BINS)+5L) / 10L) / ADCValue;

   // Calculate Vcc (in mV); 1126400 = 1.1*1024*1000
   // should be 1024 / ADCValue = 1125300L / ADCValue; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
   // internal1.1Ref = 1.1 * Vcc1 (per voltmeter) / Vcc2 (per readVcc() function)
   Serial.print(F("Measured (mV) ")); Serial.print(res); Serial.println(F(" mV"));
}

Arduino Voltage Reference Block Diagrams

Arduino Uno/Nano ADC Mux block diagram

Arduino ADC mux for bandgap voltage reference operation
Source: ATMega328P datasheet

ATTiny85 Internal Voltage Reference


The ATTiny85 voltage reference, which is selectable as either 1V1 or 2.56V, is slightly differently arranged in the ADC. The AREF pin can only be set up as an input (there is no switching FET that connects the internal reference mux to the AREF pin). So you cannot setup the Arduino voltage reference for measurement at the AREF pin.

Therefore you can't calibrate it directly. You would either assume that it has the stated value or accurately measure the Vcc supply then take an ADC reading (but remember the ADC has its own errors as well!).

One way that would eliminate ADC errors is to feed in a variable voltage to an ADC input - which you measure. Then compare it to the reading from the voltage reference (ADC reading). Once the two readings match the input voltage would then reveal the true Arduino reference voltage (of course only to 1LSB accuracy).

Arduino ATTiny85 ADC Mux block diagram

ATtiny85 internal voltage reference
Source: ATTiny85 datasheet

Calibrating the Arduino Voltage Reference

To calibrate the reference in an Uno or Nano you just turn on the reference and measure the voltage at the reference pin. Remember the only thing on the pin should be a capacitor and no other driving circuitry (if you want to preserve the chip!).

Warning: Do not connect any other voltage reference to the VREF pin when switching the Arduino (Uno/Nano) voltage reference on - there is no protection and you could damage either the external reference or the internal reference circuit.


Turning on the reference is quite simply using the following Arduino code:

    analogReference(INTERNAL); 

However, you will need to activate the ADC to enable the reference, so a simple read will do.

    analogRead(0); // Could be any channel

This is due to the way the "wiring" code is written - the mux registers and REFS0/1 are only written just before an ADC read command (within the analogRead() function).

For the arduino Mega you can choose between the following:
    INTERNAL1V1
    INTERNAL2V56

Place the above code in the setup() part of the Arduino Sketch.

Now connect a multimeter to the VREF pin and write down the result (for use in your code - see measuring the supply voltage, specifically).

TIP: Use a standard multimeter, or for more digits use an ADS1115 in differential mode or a Fluke meter (very expensive).

TIP: Add a capacitor to the Vref pin for extra noise reduction. I use a 100nF capacitor.


To set the reference back to the supply use:

    analogReference(DEFAULT);

...again followed by...

    analogRead(0); // Could be any channel

Code for analogue operation is found here:
"C:/Program Files (x86)/Arduino/hardware/arduino/avr/cores/arduino/wiring_analog.c"

Definitions (#define ) are here:
C:/Program Files (x86)/Arduino/hardware/arduino/avr/cores/arduino/Arduino.h

The Arduino code above ( for internal reference selection ) will set the registers as follows (datasheet section: 24.9.1 ADMUX ADC Multiplexer Selection Register):

ADMUX bits 7 and 6 set high (REFS1 and REFS0).
ADMUX bits 3..0 set to B1110.

Note: The data sheet states:

"The first ADC conversion result after switching reference voltage source may be inaccurate, and the user is advised to discard this result."
 
(See datasheet section "24.5.2 ADC Voltage Reference").

So you should throw away the first ADC result.


New! Comments

Have your say about what you just read! Leave me a comment in the box below.




Privacy Policy | Contact | About Me

Site Map | Terms of Use



Visit our Facebook Page:
To Visit Click Here


Recent Articles

  1. How to use Arduino shiftOut() for controlling chips with a 3 wire serial interface

    The Arduino shiftOut() function can simply control many different serial interfaced chips. Find out how it works and how fast it operates.

    Read more

  2. How to use the ADS1115

    A tutorial on using the ADS1115 precision 16 bit ADC for low power use.

    Read more

  3. The TP4056: Lithium Ion/polymer Battery Charger IC

    Learn how to use the TP4056 properly. There's a right, and a wrong way, to use it to safely charge Lithium Ion batteries.

    Read more

  4. How to use the MCP4922, a versatile 2 channel analogue output device

    The MCP4922 chip is an SPI interfaced 12 bit DAC but how fast can it go? Find out here.

    Read more

  5. How to use the MCP4725, a versatile and tiny (SOT-23-6) analogue output device

    The MCP4725 chip is a 12 bit DAC with memory that outputs voltage that you can use for many dfferent purposes. Find out what they are in this page.

    Read more

  6. How to use the MCP4728, a versatile four channel DAC with built in voltage reference.

    The MCP4728 chip is a four channel 12 bit DAC, with memory that outputs voltage that you can use for calibration, anywhere you want a fixed voltage.

    Read more

Readers Comments

"I wanted to thank
you so so so much
for all the information
you have provided in
your site it's

SUPERB and FANTASTIC."

- Ranish Pottath

"This site really is
the best and my favorite.
I find here many useful
projects and tips."

- Milan

bursach<at>gmail.com<

"Awesome site,
very, very easy and nice
to navigate!"


- Matt
matt_tr<at>
wolf359.cjb.net


Learn Microcontrollers

"Interested in
Microcontrollers?"

Sign up for The
Free 7 day guide:

FREE GUIDE : CLICK HERE


"I am a newbie to PIC
and I wanted to say
 how great your
site has been for me."


- Dave

de_scott<at>bellsouth.net

"Your site is a great
and perfect work.
congratulations."


- Suresh

integratredinfosys<at>
yahoo.com

"I couldn't find the correct
words to define
yourweb site.

Very useful, uncovered,
honest and clear.

Thanks so much for
your time and works.
Regards."


- Anon

Back to Top