Pages: [1] 2   Go Down
Author Topic: Bug with analogReference  (Read 2965 times)
0 Members and 1 Guest are viewing this topic.
Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not sure if this is a known issue or not but there appears to be a bug with analogReference when switching between INTERNAL and DEFAULT and vice versa.

Simply issuing the analogReference(xxx) does not in fact switch the ADC reference voltage after completion of the code.  It doesn't switch the voltage until you issue an analogRead().
 
I've been doing a lot of testing with the ADC prescaler, measuring the time it takes when switching back and forth between INTERNAL and DEFAULT. I've found that when going from DEFAULT(5v) to INTERNAL(1.1v) it takes approximately 5600 microseconds before the reference voltage reaches 1.1 volts.  Conversely switching from INTERNAL to DEFAULT only takes about 28 microseconds.

With this information I tried throwing a delay of 7 milliseconds between analog reads when switching from DEFAULT to INTERNAL with the below code excerpt expecting to see a nice step output  with the below loop:

Code:
for (int i=0;int < 1000;i++){
    sample[i] = analogRead(0);
    if (i == 10){
         analogReference(INTERNAL);
         delay(7);
    }
}

unfortunately the graphed out data still shows the adc count sloping up as if without the delay ever being added (with the prescaler set to 4Mhz it's about a 719 samples long ramp up).

If I simply add an analogRead() immediately after the changing ANREF like so:
Code:
for (int i=0;int < 1000;i++){
    sample[i] = analogRead(0);
    if (i == 10){
         analogReference(INTERNAL);
         analogRead(0); //added to switch reference
         delay(7);
    }
}

then I see the expected "step graph" on the output.  I can post graphs if you like.

The same holds true when switching from INTERNAL to DEFAULT.  

So I guess my question is is this a bug or normal operation for the ADC????
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 11
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I believe this is normal behavior for the ADC.  There are some delays and possibly incorrect readings when you switch between different references.  But you're right, the Arduino code doesn't actually change the reference until you do an analogRead().  
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17262
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Known 'feature' of the AVR chip. From the datasheet in section 23:

"The first ADC conversion result after switching reference voltage source may
be inaccurate, and the user is advised to discard this result."

There is lots of related technical information on the ADC section of the data sheet, so you might want to browse that section.

http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf

Lefty

Logged

Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Known 'feature' of the AVR chip. From the datasheet in section 23:

Actually it looks like a function of the IDE.  I found this inside inside the wiring_analog.c

Quote
uint8_t analog_reference = DEFAULT;

void analogReference(uint8_t mode)
{
      // can't actually set the register here because the default setting
      // will connect AVCC and the AREF pin, which would cause a short if
      // there's something connected to AREF.
      analog_reference = mode;
}

IF I'm reading this correctly setting analogReference does nothing by itself.  It looks like it was purposely written this way as a safety to prevent a short if someone had an external source connected to the AREF pin.  My guess is they had to do this or else you would have to set the analogReference in each sketch in the setup section.  This way they were able to set the power on default to DEFAULT so you wouldn't have to use analogreference by default.  

Ofcourse this assumes I'm reading this correctly (I'm still new to microcontrollers).
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17262
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Again the Atmel AVR datasheet is ALWAYS the bible for such issues. The Arduino IDE and board can only do what the chip is designed to do and abide by any restrictions and cautions.

From the AVR datasheet:

Quote
If the user has a fixed voltage source connected to the AREF pin, the user may not use the other
reference voltage options in the application, as they will be shorted to the external voltage. If no
external voltage is applied to the AREF pin, the user may switch between AVCC and 1.1V as reference
selection.

http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf

From the Arduino reference section ( http://arduino.cc/en/Reference/AnalogReference ) there is a work around for those wishing a work around for the above:

Quote
Warning
If you're using an external reference voltage (applied to the AREF pin), you must set the analog reference to EXTERNAL before calling analogRead(). Otherwise, you will short together the active reference voltage (internally generated) and the AREF pin, possibly damaging the microcontroller on your Arduino board.


Alternatively, you can connect the external reference voltage to the AREF pin through a 5K resistor, allowing you to switch between external and internal reference voltages. Note that the resistor will alter the voltage that gets used as the reference because there is an internal 32K resistor on the AREF pin. The two act as a voltage divider, so, for example, 2.5V applied through the resistor will yield 2.5 * 32 / (32 + 5) = ~2.2V at the AREF pin.



Lefty
« Last Edit: July 29, 2010, 05:43:39 pm by retrolefty » Logged

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
My guess is they had to do this or else you would have to set the analogReference in each sketch in the setup section.  This way they were able to set the power on default to DEFAULT so you wouldn't have to use analogreference by default.  
I think this is the exact reason why the deferred change of reference was chosen.

You could argue however that when analogReference is actually called, the function should change the reference before returning. If you think this is a better approach, you could post a change request accordingly.
Logged

Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
You could argue however that when analogReference is actually called, the function should change the reference before returning. If you think this is a better approach, you could post a change request accordingly.

That is the point I was trying to make, however I don't think there is a safe workaround for this and I believe the original programmers realized this.  So I guess it's not really a bug but a little know issue?

I also wanted to point out to anyone reading this thread that "throwing away" one or two Areads after switching the reference only works in the scenario when switching from INTERNAL to DEFAULT.  This practice doesn't work when switching the other way since the stabilization time can be anywhere from 50 - 200 times longer depending on the prescalar used. Using the default PS setting you would actually have to "throw away" approx 51 reads before getting valid data.  I actually put together a little chart showing the number of throw away analogread's for different arrangements below if anyone is interested.

    SWITCHING FROM DEFAULT TO INTERNAL
prescalar   ADC clk   Settling Time   Discard Reads
128(D)       125kHz       5720us              51
64              250kHz       5704us             95
32              500kHz       5672us             177
16              1MHz          5628us             312
8                2MHz          5616us             509
4                4MHz          5560us             721
2                8MHz    DOES NOT WORK

    SWITCHING FROM INTERNAL TO DEFAULT
prescalar   ADC clk   Settling Time   Discard Reads
128(D)       125kHz       120us              0-1
64              250kHz       128us             1-2
32              500kHz       68us               1-2
16              1MHz          40us               1-2
8                2MHz          28us               1-2
4                4MHz          28us               2-3
2                8MHz    DOES NOT WORK

As a side note, if you connect a 100nF cap across ARef like the datasheet recommends for noise immunity then all of the settling times and throw away reads effectively DOUBLE!  I haven't tried it using the LC network yet since I don't have a coil handy but if I get one I'll post some data if anyone's interested.  This has definitely been a learning experience  :o, thank you everyone for your input.
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
As a side note, if you connect a 100nF cap across ARef
I do and trust others as well - so these figures are relevant. Thanks for sharing!

Quote
... however I don't think there is a safe workaround for this
I don't see any issues with this. Keep the function/logic as is, but add code to change the reference in addition to saving it to a global variable. It is then still ok for sketches not using ADC and reference will still default to 5V internal for those who need it.

Have you tried to disable/enable ADC (disable, change reference, enable) to see if this has an impact on reference settling time?

Have you tried to keep the reference constant, but use multiple channels (e.g. alternating between high and low voltage inputs)?


Edit:
Another option may be to ground an anlog input pin and do a sample off this pin just after changing reference. This woud discharge the ADC sampling capacitor, but I'm not sure how it would influence reference settling time.

As for ADC clock speeds above 250kHz, you're probably on uncharted territory as this is outside Atmel recomendations. A test like yours may however reveal to what extent higher sampling frequencies may be useful.
« Last Edit: July 30, 2010, 09:07:46 am by borref » Logged

Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Have you tried to disable/enable ADC (disable, change reference, enable) to see if this has an impact on reference settling time?

Actually I believe this approach would double the conversion time going from I to D.  If I'm reading the datasheet correctly the first conversion after enabling the ADC is something like 25 ADC clock cycles and each subsequent measurement is only 13, it would then take twice as long to to convert the voltage after reenabling it.  I think the voltage settling time is more of an internal electrical (capacitance) characteristic of the IC because the time is relatively consistent across different prescalar values.  If someone has more intimate knowledge of the ADC circuitry they would be better at answering this question.
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So I thought I'd try some thing else, I decided to put varying resistors across the Aref and GND since the internal Vref is connected to Aref.  Using the prescalar at max speed (4MHz) and varying resistance from 10Meg ohm to 820 ohms I was able to get the settling time down from 5560us @ 721 discards to 136us @ 17 discards.  See chart below:

R ohms    Settling Time    Discard Reads
10 Meg       5516us             715
1  Meg        5340us             692
100k           4064us             527
10k             1184us             153
1k              160us               20
820             136us              17
<820    Started changing the Vref voltage

I don't know if this is safe to do or not, but if anyone has any experience with loading the Aref pin down with a resistor please feel free to chime in.  If not I guess I just have to leave it running this way over night and see if it releases the magic smoke or not smiley....
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If someone has more intimate knowledge of the ADC circuitry they would be better at answering this question.
I thought you were keen on finding this out yourself through measurements?

As for your observations, I'm not entirely convinced that you measure the actual settling time of the voltage reference. Rather you may be measuring the charge/discharge rate of the ADC sampling capacitor through your analog input.

If you feed your analog input with a voltage divider, the recomended input impedance is 10k. More than this and you will see a reduced frequency response which obviously will worsen with higher samplig frequencies.

For faster response after switching reference, you either need to lower the input impedance (which may not always be possible or desired) or you can add a discharge step by connecting the ADC input to ground for one sample just before or after switching reference. If this is unacceptable in terms of sampling frequency, there is not much we can do other than interface an additional external ADC.
Logged

Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So this is the last thing I did.  This time I hooked my scope up to the Aref pin (since this pin shows the Vref voltage) and triggered the analogReference change in both directions and captured the signal.  I tied A0 to GND and repeated the same test with it tied to 5v.  One direction showed the same discharge curve and measured about 5500us and the other direction was actually a little faster than what the sketch reported, it was roughly 7.5us.  
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I redid your last test on a standard Arduino and this seems to confirm your measurements.



Above is from switching AREF from internal Vcc to the internal 1V1 bandgap reference and settling time is just above 5ms. This is significantly more than one ADC sample as the AtMega328 datasheet suggests.

From AtMega328 datasheet:
Quote
The first ADC conversion result after switching reference voltage source may
be inaccurate, and the user is advised to discard this result.

Max analog sampling frequency, when using the Arduino core (analogRead), is just above 8kHz - so we would in fact need to discard up towards 50 samples to be safe. As such, the Atmel quote above seems somewhat of an understatement.

A related thread on the "AVR  freaks" site suggests that the internal bandgap reference has issues with sinking current. In the context above this would be relevant as the 100n Arduino Aref capacitor is at 5V prior to switching.

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=80458&start=all&postdays=0&postorder=asc

This significant settling delay would severly limit the usefullness of doing ADC sampling in a round-robin fashion with alternating internal AREF's.
Logged

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Redoing the test, but switching from Aref at Gnd to 1V1 internal, shows the following:



Settling delay here is approximately 75us. So apparently sourcing current is less of an issue with the bandgap reference.

I also measured the time it takes to discharge the 100n Aref capacitor.



AREF drops from 5V to 1V1 in about 5us when shorted to ground.

As a workaround for the slow settling issue, I added the following logic to my ADC sampling application:

(starting at 5V internal reference)
- change to external reference
- short AREF to Gnd (I used digital pin 3 for this)
- wait 5us
- disconnect AREF from Gnd
- change to internal 1V1 reference

With above steps, it was possible to reduce settling time from in excess of 5000us to around 5us. So, there may be hope for round-robin sampling with alternating AREF's after all. However at the added cost of an IO pin and some additional code.
Logged

Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for confirming I'm not crazy!! Ofcourse the only other variable could be the oscope since we are both apparantly using the same Chinese knock off scope...LOL.  

Just curious but how do you guys post pictures?  I've been trying to find a way to post pictures but am unsure how most people do it.  

Thanks again for the help...it's been very enlightening to say the least.
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Pages: [1] 2   Go Up
Jump to: