3
\$\begingroup\$

I have an application with Arduino, where some of the analog pins need AVCC as their reference voltage, while another one needs the internal 1.1V as the reference voltage to obtain a measurement with better precision than comparing against 5V.

I just found out that switching from AVCC to 1.1V internal requires a 5ms delay. The following code works:

    void setup() {    
      ADMUX = 0b01000011; // configure ADC
      ADCSRA = 0b10010111;
      ADCSRB = 0;
      DIDR0 = 8;  // disable A3 digital
      Serial.begin(9600);
    }
    
    void loop() {
      ADMUX = 0b11000011;  // select channel 3 and 1.1V ref
      delay(5);  
    
      ADCSRA |= 64;                // start conversion
      while ((ADCSRA & 16) == 0); // wait for conversion to complete
      ADCSRA = 0b10010101;       // clear the conversion complete signal for another time
      int bat = ADCL;
      bat |= (ADCH << 8); 
      Serial.print("a3=");Serial.print(bat);
    
      // read touch A6
      ADMUX = 0b01000110;           // select channel 6 and AVCC ref
      ADCSRA |= 64;                // start conversion
      while ((ADCSRA & 16) == 0); // wait for conversion to complete
      ADCSRA = 0b10010111;       // clear the conversion complete signal for another time
      int touch = ADCL;
      touch |= (ADCH << 8); 
      Serial.print(", a6=");Serial.println(touch);
    }

However, if I change 5ms to less, then the result of measurement against 1.1V is wrong. It is less. The less the program waits, the lower value. This indicates that when the 1.1V regulator is not selected, it is switched off and it needs 5ms to power up. I did not find anything of this sort in the datasheet, but I could have overlooked it.

Interestingly, in the analogRead() function of Arduino, there is a mysterious commented-out delay(1):

    // without a delay, we seem to read from the wrong channel
    // delay(1);

uncommenting it does not help as 1ms is not enough for this end. Therefore the code that uses analogReference() and analogRead() does not work at all, since analogReference() only changes a global variable and the actual switching is done only in analogRead(). Even subsequent analogRead() does not help (as it only takes about 20 usec), one has to wait those 5ms for the 1.1V guy to warm up.

So I was wondering - is there a way to keep it heated to avoid wasting so much time in the main loop? OK, I know I could use state variables like heating1v1 = true and measure the time, but maybe there was another way...?

And of course, it can be a feature of this particular mega328, which is probably some clone... so your original atmel microchip can be in a better shape. I tried two different boards with the same outcome.

\$\endgroup\$
2
  • \$\begingroup\$ And btw. I realized that not waiting 5ms in the same way after switching back to AVCC also results in wrong reading, but only 10% error, whereas with 1.1V the error is "total". \$\endgroup\$
    – Palo
    Jan 18, 2022 at 3:20
  • \$\begingroup\$ That may be the requirement to do a dummy conversion after changing references, see my answer. Or it could just be the external capacitor charging to AVCC as referred to by Passerby in his answer. \$\endgroup\$ Jan 19, 2022 at 21:37

2 Answers 2

3
\$\begingroup\$

It just seems to be the way it works with most AVR chips. You could make your own reference on the board if you need a fast accurate one. Or you can look to see if the 100nF cap is across AREF as noted here: https://forum.arduino.cc/t/bug-with-analogreference/22994/19 which when removed brought the ADC set to internal 1.1V ref to ready in microseconds not milliseconds. Of course a decoupling cap is recommended for noise reduction (or a full lc setup), they ended up using a 10nF cap instead for half a millisecond ready time, and or using another pin to ground and drain the cap to make it ready faster as well.

That said you probably want to calibrate the internal reference as it's not fairly accurate in it of itself. Just fyi.

\$\endgroup\$
2
\$\begingroup\$

Yes, You can keep the internal 1.1V of the Atmega 328 always on.

The 1.1V bandgap-reference internal to the ATMEGA328 is also used by the brown-out detector (BOD) and the analog comparator.

If either of those consumers are active the reference will remain enabled even if the ADC does not use it.

For example if you enable the BOD the reference will stay on and the ADC will not have to wait when changing the reference being used. There however is a requirement to do a dummy conversion and discard the result before doing the real conversion as indicated in section 24.5.2.

See section 14.7.1 of the Datasheet

enter image description here

From section 24.5.2 enter image description here

\$\endgroup\$
8
  • \$\begingroup\$ Does that actually affect the stable read time for the internal reference? Or is that just the base microsecond delay and not any issues with off chip parts like seen in my answer? \$\endgroup\$
    – Passerby
    Jan 19, 2022 at 17:43
  • 1
    \$\begingroup\$ The implication from the datasheet is that the reference does not turn-off when the ADC is not using it so there will be no delay when selecting the reference by the ADC. There is a requirement to do a dummy conversion after changing references. \$\endgroup\$ Jan 19, 2022 at 18:27
  • \$\begingroup\$ @palo if Kevin's answer helps you more than mine you can switch the accepted answer. Just test and let us know which works better for future reference. \$\endgroup\$
    – Passerby
    Jan 19, 2022 at 20:46
  • \$\begingroup\$ Thanks for all your great feedback. For now we solved it with delay, waiting 10ms in the main loop of the robot is acceptable. I am curious and will test the options of shortening the AREF pin. May the suggestion to discard the first reading after swtich relate to the fact that if the reference voltage could be switched even while the measurement is taking place, but it will only take effect in the next one? In each case, as expained in the post, it was not sufficient to do extra readings, the program had to wait 5ms - much longer time - and then the first reading was ok. \$\endgroup\$
    – Palo
    Jan 19, 2022 at 22:04
  • \$\begingroup\$ @Passerby - I am not sure whether 14.7.1 mentioned here is it. I have the ADC switched on all the time (point 14.7.1.3), but still need to wait 5ms after switch. So it must be the capacitor issue. Till now AREF was not connected to anything. Will try connecting to GND in the lab. I do not have the option to change fuses on this board. Will test the ACBG bit. :) But reading it again - it says on only when BOD is enabled. hmmm. would need to change the fuses then, hmmm. \$\endgroup\$
    – Palo
    Jan 19, 2022 at 22:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.