Faster Read times for analogRead

This is a sample sketch from the Arduino Cookbook -- somewhat modified...

It shows a simple method to improve (shorten) the read time for Analog Sensors on the Arduino

/*
  Sketch to demonstrate how to decrease time of analog read.
  it shortens the delay by manipulating registers and reducing the prescale
  timer value from 128 to 16;

  Note Serial Speed! Change to suit yourself!

  Sample Sketch From Arduino Cookbook by Margolis (O'Reilly Press)
  Modified by Willr March24, 2011 

  Tested on Mega2560 Arduino board with an MA7361 Z output hooked to 
  Sensor 5

*/

// CHANGE Sensor Pin to suit yourself...
const int sensorPin = 5;

// Change  number of entries to a value divisible by 100 only
const int numberOfEntries = 100;

unsigned long microseconds;
unsigned long duration1;
unsigned long duration2;


int results[numberOfEntries];

void setup(){
  Serial.begin(9600); ///CHANGED
  Serial.flush();
  

 // standard analog read performance -- prescale == 128
 microseconds = micros();
 for (int i=0; i < numberOfEntries; i++)
 {
   results[i] = analogRead(sensorPin);
 } 
 
 duration1 = micros() - microseconds;

 Serial.print(numberOfEntries);
 Serial.print("   readings took ");
 Serial.println(duration1);

// This double loop just prints a neat table..
 for( int j=0; j < numberOfEntries; j=j+20){
   for (int i=0; i < 20; i++) {
     Serial.print(results[j+i]);
     Serial.print(",  ");
   } //end loop i
   Serial.println();
 } //end loop j
 
 Serial.println();
 
 // prescale clock to 16
 bitClear(ADCSRA,ADPS0);
 bitClear(ADCSRA,ADPS1);
 bitSet(ADCSRA,ADPS2);

 // Performance with Changeed Prescale...
 microseconds = micros();
 for (int i=0; i < numberOfEntries; i++)
 {
   results[i] = analogRead(sensorPin);
 } 
 
 duration2 = micros() - microseconds;
 Serial.print(numberOfEntries);
 Serial.print("   readings took ");
 Serial.println(duration2);

 for( int j=0; j < numberOfEntries; j=j+20){
 for (int i=0; i < 20; i++)
 {
   Serial.print(results[j+i]);
   Serial.print(",  ");
 } //end loop i
   Serial.println();
 } //end loop j
 
 Serial.println();
 
 Serial.print("Ratio of read times is : ");
 Serial.println((float)duration1/duration2);
 Serial.println("********************");
 

}

void loop(){
  // empty main loop is deliberate...
  
}

Hope that helps people looking for that "faster read". ]:smiley:

Cheers!

strange, it doesn't print anything to the serial port for me.

Anyway, remind me what the tradeoff is? is there a loss of resolution or accuracy?

Also worth noting that analog reads can be done in the background at the hardware level.

dcb:
strange, it doesn't print anything to the serial port for me.

Anyway, remind me what the tradeoff is? is there a loss of resolution or accuracy?

Also worth noting that analog reads can be done in the background at the hardware level.

Well -- it works for me... XD but....

Check the serial port rate. I tested this on a Mega2560 -- the 115200 rate may be too fast -- so set it to 9600 and try again. Feel free to modify it and post back if it needs to be changed for other processors.

Also the registers may be different on another processor. I don't think so -- but no guarantees...

Background reading may or may not be practical. In my case I am reading multiple sensors and want as few interrupts as possible.

As for trade-offs -- my simple testing does not see one. I think it just cuts the overhead... That's the claim in the book anyway and it seems to be true.

You're creating an array of ints with 1000 elements. With ints being two-bytes, that's a 2000 byte array. On a Mega256 with 8k ram, that's fine. On just about any other Arduino with 2k or less ram, just isn't going to work. Cut it down to 100 elements and it'll work fine on even a 168.

jraskell:
You're creating an array of ints with 1000 elements. With ints being two-bytes, that's a 2000 byte array. On a Mega256 with 8k ram, that's fine. On just about any other Arduino with 2k or less ram, just isn't going to work. Cut it down to 100 elements and it'll work fine on even a 168.

Done on the original post.

dcb:
Anyway, remind me what the tradeoff is? is there a loss of resolution or accuracy?

Yes. Per the datasheets:

By default, the successive approximation circuitry requires an input clock frequency between 50
kHz and 200 kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the
input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate.

Thx jraskell, it is working on my 168.

A little output never hurt :). I'm sure there are plenty of applications for lower resolution and faster analog.

100   readings took 11304
440,  440,  441,  441,  441,  442,  443,  443,  444,  444,  445,  445,  446,  446,  447,  448,  449,  449,  450,  451,  
452,  453,  454,  454,  455,  456,  457,  458,  459,  460,  461,  462,  462,  463,  464,  464,  465,  466,  466,  467,  
468,  469,  469,  470,  471,  472,  473,  473,  474,  474,  475,  475,  476,  477,  477,  478,  478,  478,  479,  479,  
479,  479,  479,  479,  479,  479,  479,  478,  478,  478,  478,  477,  477,  477,  477,  476,  475,  475,  474,  473,  
472,  471,  471,  470,  469,  468,  467,  466,  465,  464,  463,  462,  461,  460,  459,  458,  457,  456,  455,  454,  

100   readings took 1716
463,  463,  463,  463,  463,  463,  463,  463,  463,  463,  463,  463,  462,  462,  462,  462,  462,  462,  463,  463,  
463,  463,  462,  462,  462,  462,  462,  462,  462,  462,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  
460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  460,  
460,  459,  459,  459,  459,  459,  458,  457,  457,  457,  457,  457,  456,  457,  457,  457,  457,  457,  456,  455,  
455,  455,  455,  455,  455,  455,  455,  455,  455,  455,  454,  454,  453,  452,  452,  452,  452,  451,  451,  451,  

Ratio of read times is : 6.59
********************

I appear to be getting full 10 bit resolution on the Mega 2560 at least. A pre-scale of 16 is not 16us -- I did not check. I suppose I could.