Reading Multiple Analog Inputs

I'm all in now. The parts have started arriving. I have my (genuine) Arduino Uno, LCD shield with buttons, and sensors to get the first project completed. I have seen several old threads regarding reading multiple analog input pins. Is it still the case where you must do a 'dummy' between each actual read.

pseudo-code:
Read 1 (throw away)
Read 1 (keep)
Read 2 (throw away)
Read 2 (keep)
Read 3 (throw away)
Read 3 (keep)
Read 4 (throw away)
Read 4 (keep)
loop...

Is this still the case or have things been fixed or improved?

I can't see any reference in the datasheet for that being a requirement.

If the analog source has low current drive capability (i.e. "high impedance") then the sample & hold cap input to the ADC can need a couple of reads to fully charge up and produce a good reading. Hence the read twice and use the 2nd reading.

Even then, couldn't you just buffer it with an opamp and not have that problem anymore?

It's always nice to test these ideas. I made up a test sketch:

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  }  // end of setup

void loop ()
  {
  for (int whichPort = A0; whichPort <= A2; whichPort++)
     {
     Serial.print ("Analog port = ");
     Serial.print (whichPort);
 //    analogRead (whichPort);  // dummy read
     int result = analogRead (whichPort);
     Serial.print (", result = ");
     Serial.println (result);
     } 
  Serial.println ();
  delay (1000);
  }  // end of loop

That switches between A0 and A2, reading the voltages there. I had on them:

  • A0 = 2.5V
  • A1 = 5V
  • A2 = 3.3V

The readings therefore should be:

  • A0 (14) = 511
  • A1 (15) = 1023
  • A2 (16) = 675

What I got with the above sketch was:

Analog port = 14, result = 509
Analog port = 15, result = 1023
Analog port = 16, result = 674

Analog port = 14, result = 509
Analog port = 15, result = 1023
Analog port = 16, result = 670

Analog port = 14, result = 508
Analog port = 15, result = 1023
Analog port = 16, result = 673

Analog port = 14, result = 507
Analog port = 15, result = 1023
Analog port = 16, result = 673

Analog port = 14, result = 508
Analog port = 15, result = 1023
Analog port = 16, result = 675

Slight variations, but it seemed to handle switching ports OK.

Now by uncommenting the dummy read, we can see if it increases accuracy:

Analog port = 14, result = 507
Analog port = 15, result = 1023
Analog port = 16, result = 675

Analog port = 14, result = 505
Analog port = 15, result = 1023
Analog port = 16, result = 675

Analog port = 14, result = 506
Analog port = 15, result = 1023
Analog port = 16, result = 676

Analog port = 14, result = 506
Analog port = 15, result = 1023
Analog port = 16, result = 675

Analog port = 14, result = 507
Analog port = 15, result = 1023
Analog port = 16, result = 673

There isn't much, if any, difference, so I would say the dummy read is not necessary.

I changed my code to take an average of 500 readings.

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  }  // end of setup

const int ITERATIONS = 500;
unsigned long totals [6];

void loop ()
  {
  for (int whichPort = A0; whichPort <= A2; whichPort++)
    totals [whichPort - A0] = 0;
  
  for (int i = 0; i < ITERATIONS; i++)
    {
    for (int whichPort = A0; whichPort <= A2; whichPort++)
       {
 //      analogRead (whichPort);  // dummy read
       int result = analogRead (whichPort);
       totals [whichPort - A0] += result;
       } 
    }

  for (int whichPort = A0; whichPort <= A2; whichPort++)
     {
     Serial.print ("Analog port = ");
     Serial.print (whichPort);
     Serial.print (", average result = ");
     Serial.println (totals [whichPort - A0] / ITERATIONS);
     } 
    
  Serial.println ();
  delay (1000);
  }  // end of loop

With only a single read:

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

With an extra dummy reading:

Analog port = 14, average result = 507
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

So really, no discernable difference.

Delta_G, yes, an op-amp would likely have a low impedance output an drive the analog input sufficiently.

Nick, what happens when you put say a 20K resistor between the voltage sources and the analog pins to simulate a high impedance source?

With a 22k resistor in series with each input ...

Single reading:

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 673

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 673

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 673

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 673

Two readings (dummy plus real):

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

Analog port = 14, average result = 508
Analog port = 15, average result = 1022
Analog port = 16, average result = 672

The input impedance of the analog inputs is well into the MegOhms. The impedance of the source would have to seriously high to cause "slow" reading...

Regards,
Ray L.

The datasheet says:

When the bandgap reference voltage is used as input to the ADC, it will take a certain time for the voltage to stabilize. If not stabilized, the first value read after the first conversion may be wrong.

However we are not using the bandgap reference in this case.

I think there might be a bit of confusion about the need to do an extra reading. After all, if the input changes quickly (eg. from 0V to 5V) then any delay in charging the ADC circuit would apply, even if you hadn't changed the MUX input. I don't see why changing the MUX input, per se, should introduce an error.

The input impedance of the analog inputs is well into the MegOhms. The impedance of the source would have to seriously high to cause "slow" reading...

Plus what Ray said. It will already be high impedance.

This is all very interesting because I have always assumed (without testing) that a dummy read would be necessary.
( A ) it shows the value of testing - which is what I would normally recommend to others
( B ) I wonder if it has anything to do with the time it takes for the analaogRead() code compared with direct reading of the registers

...R

Robin2:
( B ) I wonder if it has anything to do with the time it takes for the analaogRead() code compared with direct reading of the registers

What are you supposing analogRead does?

I am wondering if it is slow in the same way that digitalRead() is slow compared to port manipulation.

...R

Not really, no. Here is the code, with irrelevant parts (for the Atmega328) take out. You can see there isn't much more to it than fooling with the registers.

int analogRead(uint8_t pin)
{
 uint8_t low, high;
 if (pin >= 14) pin -= 14; // allow for channel or pin numbers
 // select the channel (low 4 bits). 
 ADMUX = (analog_reference << 6) | (pin & 0x07);
 // start the conversion
 sbi(ADCSRA, ADSC);
 // ADSC is cleared when the conversion finishes
 while (bit_is_set(ADCSRA, ADSC));
 low  = ADCL;
 high = ADCH;
 // combine the two bytes
 return (high << 8) | low;
}

From the datasheet:

The ADC is optimized for analog signals with an output impedance of approximately 10 kΩ or less. If such a source is used, the sampling time will be negligible. If a source with higher impedance is used, the sampling time will depend on how long time the source needs to charge the S/H capacitor, with can vary widely. The user is recommended to only use low impedance sources with slowly varying signals, since this minimizes the required charge transfer to the S/H capacitor.

I'm sorry, Nick,

do I understand this correctly and does this mean that while a dummy read isn't necessary it might even slow your code down significantly with an high Impedance reading?

I don't think the impedance will slow anything down. As Crossroads said above possibly the internal circuitry would not "charge to" the voltage if it changed quickly. However my tests seem to indicate that even with a 22 k resistor in series the difference was negligible.

Nick, thanks for all your input. It has certainly clarified things.

I think that, while the datasheet is generally (see below) accurate and precise its precision sometimes obscures its message.

Just by the way I noticed this in your quote from the datasheet (and I have checked and your quote is correct)

The user is recommended to only use low impedance sources with slowly varying signals,

This seems rather illogical. Perhaps they meant to say "with rapidly varying signals". Otherwise it seems to imply that one could use a high impedance source with rapidly varying signals.

...R

On the face of it what you say sounds right, but perhaps we are misinterpreting the English here? What they might mean is:

... use low impedance sources and slowly varying signals ...

In the same way you might say "I had toast with jam" meaning "I had toast and jam".

I'm now starting to wonder about this sentence:

If a source with higher impedance is used, the sampling time will depend on how long time the source needs to charge the S/H capacitor, with can vary widely.

Does that mean the time for the ADC conversion varies widely? Elsewhere they seem to say it takes a fixed number of ADC clock cycles.

The conversion will take a fixed number of cycles. Any standard non-microcontroller-embedded ADC datasheet shows the length of time the conversion takes.

I believe what the 328 datasheet is saying is far more fundamental. It takes a long time to charge the S/H capacitor if feed by a high impedance (ie., very low current). The rate at which you can get valid readings will vary widely based on the ability to dis/charge the S/H capacitor. Given, the lowest acceptible sampling rate is twice the input frequency (Nyquist). If the S/H capacitor charging time constant (t=RC) is too much higher than the input period (1/f), it won't matter how fast the input is sampled, the readings will never reach the top or bottom most values. The input becomes some pseudo average value. It may have been simpler if the datasheet just said to keep t=RC (where R is the source impedance) less than 1/4 the input period or 1/8 the sampling period. If the input frequency is 10Hz (0.1s), sampling should be 20Hz (0.05s), and the time constant be should less than 0.025 seconds. This would ensure the S/H capacitor has time to dis/charge and track the input between samples.