Inaccurate BandGap measurement

I’ve followed advice on this forum on how to use “bandgap” voltage reference to measure supply voltage, however, the measurements are not as accurate as the ADC can be on an Arduino Mega.

On the one hand, I’ve measured the 1.1V ref to actually be 1.087V using a DMM to measure the voltage across a capacitor from AREF to GND with the appropriate code.

On the other hand, measuring the BG internally with the ADC using the attached code returns an ADC average reading of 226.5 which is 1.107V with a 5V supply (measured using a DMM from the 5V pin). This is a 20mV error. I’ve being getting about 5mV accuracy when using the ADC to measure an external voltage source.

The Arduino Mega is powered via USB.

#define N 128
#define ND 128.0D

int analogReadBG(){
  uint8_t low, high;
  ADMUX = 0;
  bitClear(ADCSRB,MUX5); // Set ADC input as BG (1.1V)
  bitSet(ADMUX,MUX4);
  bitSet(ADMUX,MUX3);        
  bitSet(ADMUX,MUX2);
  bitSet(ADMUX,MUX1);        
  bitSet(ADMUX,REFS0);  // Set 5V as ADC reference voltage
  
  for (int i=0;i<7;i++){ // Perform several converstions for reading to settle
    bitSet(ADCSRA, ADSC);
    while (bit_is_set(ADCSRA, ADSC));
  }
  low  = ADCL;
  high = ADCH;
  return (high << 8) | low;
}

void setup() {
  Serial.begin(115200);
}
long movingSum;
double movingAverage;
void loop() {  
  movingSum = 0;
  for (int i=0;i<N;i++){
    movingSum += analogReadBG();
  }
  movingAverage = movingSum/ND;
  Serial.println(movingAverage);
  delay(1000);
}

According to the datasheet the reference voltage is 1.1 ±0.1 V. This is quite a large tolerance.

Bandgap reference voltage value depends on technology and production process. There is quite big tolerance but it doesn't mean that voltage will drift up/down in time. Tolerance is for product and reference voltage should fall into. This type of reference value is pretty stable in time and is tolerant to temperature changes. It is needed to be evaluated its exact voltage before first use and to implement obtained value into program.

kogana: I've followed advice on this forum on how to use "bandgap" voltage reference to measure supply voltage, however, the measurements are not as accurate as the ADC can be on an Arduino Mega.

The Arduino Mega is powered via USB.

You have yet to establish that is true. USB power is noisy, highly sensitive to loads, and drifts with temperature. If the USB power is from a computer the voltage will be sensitive to whatever your computer is doing.

Your DMM filters most/all of that showing you what appears to be a stable reading.

On the one hand, I've measured the 1.1V ref to actually be 1.087V using a DMM to measure the voltage across a capacitor from AREF to GND with the appropriate code.

Assuming the Mega was "idle" (empty loop). That is the value you should use.

On the other hand, measuring the BG internally with the ADC using the attached code returns an ADC average reading of 226.5 which is 1.107V with a 5V supply (measured using a DMM from the 5V pin). This is a 20mV error.

Excellent. You have confirmed that a USB port cannot be used as a reference.

This makes calibrating the internal bandgap a breeze... http://www.adafruit.com/products/2200

I will try to connect the arduino to an exteranl power supply. However, reading various external voltages through the analog inputs, showed stable readings, consistent with the 5V Vcc measurement (5mV accuracy). The bandgap readings were quite stable as well, suggesting a stable supply.

To eliminate doubts regarding the DMM accuracy, the AREF pin was tested with another Arduino (Uno). The reading was a stable 222. The 5V pin was measured with the second Arduino as well to a stable 1021.75 (1023/1021.75*222 = 222.27).

I think, any DMM is accurate enough to evaluate the reference voltage in this case. The method to increase precision is also to make several measurements and to calculate an average value.