Internal Voltage Reference measurement

Hello!
When I select **analogReference(INTERNAL2V5);**: how can I measure this voltage to check its error?

For example, when select **analogReference(INTERNAL);** on Arduino UNO, you can measure this voltage in pin AREF. In my case, this voltage is 1.069V, not ideal 1.1V, and knowing this value I can get more accurate analog measurements.

I would like to check the same in Nano Every. Is it posible?
Thank you very much.

If you use the internal reference to measure & calculate a known external voltage, you can calculate the percentage error/difference from the known-actual external voltage.

1 Like

Yes, I know this option, but I prefer to directly measure the internal voltage reference if posible, like Arduino UNO.
Thank you for your post.

On the Arduino Uno R3, the AREF voltage appears on the pin labeled AREF when the command analogRead(); is executed.

To read the internal voltage reference, use the command analogReference() to select the desired reference voltage, before calling analogRead().

To determine whether this is possible with the Nano Every, consult the processor data sheet and the official schematic diagram.

According to the schematic diagram of ADC, I understand that the Internal Vref is not posible to connect to any pin, like the UNO. This Internal Reference is an input of a multiplexer, and the Vref goes directly to ADC.

You never need to measure the internal Vref. It can easily be calculated based on measurements.

Hi,

maybe too late, but I'll show it anyway and connect your voltmeter on AREF Pin.

const uint8_t VREF_0V55 {0};
const uint8_t VREF_1V1  {VREF_ADC0REFSEL_0_bm};
const uint8_t VREF_2V5  {VREF_ADC0REFSEL_1_bm};
const uint8_t VREF_4V3  {VREF_ADC0REFSEL_1_bm | VREF_ADC0REFSEL_0_bm};
const uint8_t VREF_1V5  {VREF_ADC0REFSEL_2_bm};

void setup()
{  
  VREF.CTRLB = VREF_ADC0REFEN_bm;
  ADC0.CTRLC = ADC_REFSEL_VREFA_gc;
  
  VREF.CTRLA = VREF_0V55;
  delay(2000);  
  VREF.CTRLA = VREF_1V1;
  delay(2000);  
  VREF.CTRLA = VREF_1V5;
  delay(2000); 
  VREF.CTRLA = VREF_2V5;
  delay(2000);  
  VREF.CTRLA = VREF_4V3;
}

void loop()
{
  
}

The ATmega4809 on the Nano Every does not output anything at AREF (see post #5).
The ATmega328 on the UNO does under certain circumstances, and that allows you to blow up that circuit.

Hi,

You haven't tested the code from #7?
Test it and see for yourself.
What it cannot do is measure its internal bandgap.

Your sketch didn’t compile. So I wrote my own testprogram. I didn’t measure anything at the AREF pin. Now I wonder: did you run your sketch?


// Does Nano Every output anything at AREF?????
// multimeter at pin AREF using different reference voltages
// voltage divider 10k/1k from 3V3 output to A0 input to prove changing reference

float fmap(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void measureVolt(String strVref, float refVolt) {
  delayMicroseconds(50);    // allow VREF to settle
  ADC0.COMMAND = 1;         // start measurement
  while (ADC0.COMMAND) {};  // wait for end of measurement
  Serial.print("Ref = ");
  Serial.print(strVref);
  Serial.print(", A0 = ");
  Serial.print(fmap(ADC0.RES, 0, 1023, 0, refVolt));
  Serial.println(" Volt.");
}
void setup() {
  Serial.begin(9600);
  ADC0.MUXPOS = ADC_MUXPOS_AIN3_gc;                         // AIN3 = pin A0
  ADC0.CTRLC = ADC_REFSEL_INTREF_gc | ADC_PRESC_DIV128_gc;  // internal reference and 125kHz clock
  ADC0.CTRLA = ADC_ENABLE_bm;

  VREF.CTRLA = VREF_ADC0REFSEL_0V55_gc;
  measureVolt("0V55", 0.55);
  delay(2000);
  VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc;
  measureVolt("1V1", 1.1);
  delay(2000);
  VREF.CTRLA = VREF_ADC0REFSEL_1V5_gc;
  measureVolt("1V5", 1.5);
  delay(2000);
  VREF.CTRLA = VREF_ADC0REFSEL_2V5_gc;
  measureVolt("2V5", 2.5);
  delay(2000);
  VREF.CTRLA = VREF_ADC0REFSEL_4V34_gc;
  measureVolt("4V34", 4.34);
  delay(2000);
}
void loop(){};

Hi

I changed it, compiled it, I had used a newer toolchain with a newer header file.
Now you can use it to measure AREF with DMM.
The only thing I had also written is that the megaAVR0 cannot measure its own Ub.
Here now 2 different things came together.
One more thing. You don't post code as a picture. Never!

You always measure 0.3V with 10k/1k at 3.3V.
The 0.33V is always below the smallest VREF.
That's okay with all VREFs.
Did you expect something else?

You can also make life easier for yourself with analogReference()
That was just my own test code with direct access, because I wanted to test something else at the time.

const uint8_t VREF_0V55 {0};
const uint8_t VREF_1V1  {VREF_ADC0REFSEL0_bm};
const uint8_t VREF_2V5  {VREF_ADC0REFSEL1_bm};
const uint8_t VREF_4V3  {VREF_ADC0REFSEL1_bm | VREF_ADC0REFSEL0_bm};
const uint8_t VREF_1V5  {VREF_ADC0REFSEL2_bm};

void setup()
{  
  VREF.CTRLB = VREF_ADC0REFEN_bm;
  ADC0.CTRLC = ADC_REFSEL_VREFA_gc;
  
  VREF.CTRLA = VREF_0V55;
  delay(2000);  
  VREF.CTRLA = VREF_1V1;
  delay(2000);  
  VREF.CTRLA = VREF_1V5;
  delay(2000); 
  VREF.CTRLA = VREF_2V5;
  delay(2000);  
  VREF.CTRLA = VREF_4V3;
}

void loop()
{  }

The standard calibration method would be to feed-in a known voltage and make a calibration/correction. You don't need to know what's happening inside the chip. :wink:

A basic straight-line calibration is an offset, which is a value added/subtracted from the readings. Usually the offset is measured at (or near) zero. If no zero calibration is needed the offset is zero. (The Arduino probably will read zero and won't need an offset correction).

Then while applying the offset correction, a 2nd measurement is made at, or near, the maximum, or at the most-likely or most important value, and a slope (multiplication factor) correction is made. If the reading is perfect, the slope is 1.0.

Since multiplying by zero equals zero, the slope correction doesn't mess-up the offset correction.

means AREF is an input and you’re going to apply a voltage to it.

This time around I did measure voltages at the AREF pin. According to the schematics in post #5 this shouldn’t be possible. Apparently the circuitry used is not a ‘clean’ analog switch.

There’s a piece of text in the datasheet I never understood, but it’s making slightly more sense now.

But it makes me wonder: is it meant to protect the VREF circuitry or to avoid affecting the external voltage?

Hi,

everything it describes is correct. Your measured values also match what you have done.
The AREF pin is the reference voltage for the ADC. At the same time, the selected VREF voltage specifies the maximum input voltage that can be measured by the ADC on its channels. The selected VREF, which can be measured at the AREF pin using a DMM, is only the reference voltage for the ADC. There are several internal VREFs to choose from and you can also connect your own to the AREF pin. Note Ub! But not all at the same time. Either an internal VREF which is then applied to AREF or an external one. Only 2 capacitors are connected to the AREF pin on the Every Board to stabilize the selected reference voltage.
The ADC measures everything that is applied to its channels only in relation to the selected VREF.
Have the ADC output the raw values in the code shown in the picture.
They must be less in this order.

3.3V / 10 = 0.33V at the ADC channel

VREF 0.55V > 1024 / 0.55V * 0.33V = 614
VREF 1.1V > 1024 / 1.1V * 0.33V = 307
VREF 2.5V > 1024 / 2.5V * 0.33V = 135
VREF 4.3V > 1024 / 4.3V * 0.33V = 78

These values should be shown.

I’ve been thinking about this. The more I think about it, the less likely it seems that this is an oversight of the chipmaker. If it is deliberate it is either to mimic some properties of the 328 or to enable testing in the factory. The latter makes more sense.

This doesn't seem to be quite correct (post 8). I have a DMM connected to the AREF pin and can clearly see voltage steps when executing a slightly tweaked version of Doc_Arduino's code:

analogReference(INTERNAL2V5);
  VREF.CTRLB = VREF_ADC0REFEN_bm;
  ADC0.CTRLC = ADC_REFSEL_VREFA_gc;
  
  VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc;
  delay(2000);  
  VREF.CTRLA = VREF_ADC0REFSEL_2V5_gc;
  delay(2000); 
  VREF.CTRLA = VREF_ADC0REFSEL_4V34_gc;
  delay(2000);  
  VREF.CTRLA = VREF_ADC0REFSEL_1V5_gc;

The Nano Every schematic does show the module AREF pin connected to the ATMEGA4809's pin 27. Thanks Doc_Arduino.