Increasing analog read sample rate

Hi, I would like to get close to maximum analog read sample rate possible. I wrote a test code and got the sample rates around 3600 samples/s. Then I added a prescaler of 16 and got a sample rate of around 5500 samples/s. I am using a delay of 15 microseconds between each reading. The code is provided below. It just calculates time taken for reading and printing 10000 values:

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void setup()
{
  // set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;

  Serial.begin(250000);
  pinMode(A4, INPUT);
  int a = analogRead(A4);
  int i = 0;
  
  int start = millis();// starting the timer
  while (i < 10000) {  // reading and printing 10000 values
    a = analogRead(A4);
    Serial.println(a);
    delayMicroseconds(15);
    i++;
  }
  int finish = millis();
  int time_t = finish - start; // time taken for reading 10000 values
  Serial.println(time_t);
  Serial.println("DONE");
}
void loop()
{

}

I also tried a variation of above code and read it using serial communication using MATLAB and got around same sample rates.
The Arduino code for the variation is:

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int a;
void setup()
{
  // set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
  Serial.begin(250000);
  pinMode(A4, INPUT);
 
}
void loop()
{
a = analogRead(A4);
    Serial.println(a);
    delayMicroseconds(15);
}

Please let me know if there is a way to increase the sample rate more than this.
Thanks!

jaskiratubhi:
Hi, I would like to get close to maximum analog read sample rate possible.

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

So, at 200kHz, the best will be around 65uS/convert ~ 15,000/sec

Remove the delayMicroseconds()

The Serial.println(a) at 250000 baud will take approx. 40uS/char, 4 characters = 160uS
I think it will slow to this rate once the serial output buffer is full (i.e. about 6,000/sec)

Yours,
TonyWilk

The clock frequency should be 50-200 kHz for full 8-bit resolution. On a 16 MHz system and /128 prescaler you'd have a frequency of 125 kHz, so 9615 samples per second.

You can increase this rate - the ADC is rated up to 1 MHz so a /16 prescaler - but you lose resolution: the effective resolution is just 8 bits at that rate. But you can get almost 77,000 sps.

instead of the blocking analogRead() you can do it async way

See my experimental code here - http://forum.arduino.cc/index.php?topic=109259.0

(still need to make a wrapper class for that ... )

IIRC there’s an interrupt available for the ADC, that’s triggered when ready. May be useful in the “free running” mode: have it trigger an interrupt every time the reading is done, have the ISR read the registers (only the high byte or also the low byte if you’re sampling at <200 kHz), and deal with the data in your code.

wvmarle:
You can increase this rate - the ADC is rated up to 1 MHz so a /16 prescaler - but you lose resolution: the effective resolution is just 8 bits at that rate. But you can get almost 77,000 sps.

Yes, but that would be a sample every 15uS or so, to output that over async serial as text you would need a baudrate of over 2Mbps

jaskiratubhi has Serial.println(a) in the timing loop

Yours,
TonyWilk

That's another problem indeed. Getting the data out. I2C or SPI would work a lot better.

you could also use a teensy 3.5 which is much faster ...