What effect Arduino analogRead speed?

Hi,
this is a general knowledge question asking.
I feel that the analogRead(Ax) speed say number of readings in a certain period of time dramatic changes in different Sketch.
I don't have a specific sketch and specific readings frequency yet, just feeling, may wrong?

Thanks for help.
Adam

could be right as the other code in different sketchs has different execution overhead.

a simple example

this is faster

int something= analogreadthingy

than this

serial.print ( analogreadthingy )

the serial print has more code overhead then just storing the value.

1 Like

Read the data sheets for the processor in question. For the Uno and Nano, etc. the processor is stopped for two clock cycles while the analog read is being done. This is to avoid noise accoding to the data. Other processors may not do this.

2 Likes

Thank you Idahowalker.
very good clue, are there any other factors?

the attached hardware to the analog pin can have an effect on analog reads.

1 Like

Thanks.
are there any difference between pins of Ax if use the same attached hardware? say attached to A0 or to A5?

No, they are all the same.

The speed of an analogRead can be controlled by the pre scaler register, code can change this value to make it faster or slower. However if you make it too fast you loose some of the accuracy in the least significant bits.

2 Likes

Thank you Grumpy_Mike.

The ADC clock runs at 125 kHz on an Arduino UNO. It has to be slower than 200 kHz to get all 10 bits of resolution but with the limited selection of prescale values, 125 kHz is the highest available rate below 200 kHz.

An ADC read takes 13 ADC clock cycles, so about 9615 Hz (a little under 10,000 samples per second). This has to be shared across multiple inputs if you use more than one. All of the input pins go to the same ADC so there is no advantage or disadvantage to using any particular pin or pins.

If you don't need all 10 bits of resolution you can change the clock to 250 kHz, 500 kHz, or 1 MHz to get close to 20,000, 40,000 or 80,000 samples per second.

2 Likes

Thank you johnwasser.
I'll test that.

How fast are you trying to read and what's the frequency of the signal you're trying to measure? This might not really be an issue, or it might be a problem that's impossible to solve.

And then what are you trying to do? i.e. If you read an audio signal the raw data will "look random" (even if it's a constant sine wave). If you want to re-construct the original analog or display the analog waveform you have to know the sample rate, and if you really want to do it "right" you need a smoothing filter.

1 Like

Thank you DVDdoug.

actually, I am not looking for how fast or how slow the sampling-rate is, what I really need is just a common speed whatever it is, my concern is why the sampling-rate vary so much, say in one sketch read 50 times, and got only 3 times in another sketch.

post the sketch and you might find out why.

1 Like

As you were told in reply #2 it depends on what else you are doing with your sketch. The speed of an analogRead is constant for any one prescaller setting.

put here avoid a new post.
I found a so-call 'ADC Free Running mode' sketch as below, question is how to get the real value read from ADC (A0), Serial.print(x)? where can put it?
Thanks.

int numSamples = 0;
long t, t0;

void setup ( )
{
  Serial.begin(115200);
  Serial.println("xxx_setup!");

  Serial.print("File   : "), Serial.println(__FILE__);
  const char compile_date[] = __DATE__ " " __TIME__;
  Serial.print("Compile timestamp: ");
  Serial.println(compile_date);

  //pinMode (A0 , INPUT) ;

  ADCSRA = 0;                       // clear ADCSRA register
  ADCSRB = 0;                       // clear ADCSRB register
  ADMUX |= (0 & 0x07);              // set A0 analog input pin
  ADMUX |= (1 << REFS0);            // set reference voltage
  ADMUX |= (1 << ADLAR);            // left align ADC value to 8 bits from ADCH AREGISTER

  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);  // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                 // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);  // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE);           // enable auto trigger
  ADCSRA |= (1 << ADIE);            // enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN);            // enable ADC
  ADCSRA |= (1 << ADSC);            // enable ADC measurement
}

ISR (ADC_vect)
{
  byte x = ADCH;      // read 8 bit value from ADC
  numSamples++;
}

void loop ( )
{
  if (numSamples >= 1000)
  {
    t = micros ( ) - t0 ; // calculate elapsed time

    Serial.print ( "Sampling frequency:" ) ;
    Serial.print ( ( float )1000000 / t) ;
    Serial.println ( "KHz" ) ;

    delay (2000) ;

    // restart
    t0 = micros();
    numSamples = 0;
  }
}

The thing about the free running mode is that it doesn't do an analogue read any faster but if you are clever it allows you to do some other things while it is doing the conversion. Providing that is, that these other things take less time than a conversion. You have to set off a conversion, do the other things like storing the previous sample in an array and incrementing the array pointer. You then end up in a short loop waiting for the end of conversion flag, to indicate that the conversion has finished and the results registers are ready to read.

A good example of this technique is to be found in many FFT libraries where they use it to get a sample in as quickly as possible. Also normally you disable the interrupts from timer zero, which looks after background tasks like updating the millis and micros counts. This ensures that your code is not interrupted by these tasks and the sample rate is as constant as possible. You find this in FFT examples as well.

1 Like

Thank you Grumpy_Mike.

firstly I‘d like to clarify that the 'free running mode doesn't do an analogue read any faster' ? my misunderstanding?

secondly if the 'free running mode' make it possible to allow to do some other things while it is doing the conversion, it is good enough for my purpose, are there any examples please. for example, if I can get a count of number of the reading times in a certain time say 10ms.

Thanks.

Well that will be about 10 with the standard value of prescaler register, with the sample time being 0.1 mS

1 Like

Thanks.

I'll check FFT libraries.

Sorry my English.
I mean I like to get the numbers of the how many times the analogRead have read in 10 millisecond, 50 times or 100 times?

or would say how many datas read in 10 millisecond?

well, the code I used as below, that designed to read A0 in each 10 ms in free running mode and print out the counter, it didn't.

also, is it OK to print the value of analogRead?

unsigned long prev;
unsigned long counter = 0;
int IRreceiverFL = A0;  // left SERVO to 47
const unsigned long Readingperiod = 10;
int j1 = 0;

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  Serial.println("xxx_setup!");

  Serial.print("File   : "), Serial.println(__FILE__);
  const char compile_date[] = __DATE__ " " __TIME__;
  Serial.print("Compile timestamp: ");
  Serial.println(compile_date);

  prev = millis();
  pinMode(IRreceiverFL, INPUT);

  ADCSRA = 0b11100101;      // set ADC to free running mode and set pre-scalar to 32 (0xe5)
  ADMUX = 0b00000000;       // use pin A0 and external voltage reference
}

void loop() {

  FLReading();
}

void FLReading()  
{
  int val = analogRead(IRreceiverFL);

  if (val > 500) { 
    counter++;
  }
  if (millis() - prev >= Readingperiod) {
    j1++;
    if (j1 > 10) ///// 
   {
      j1 = 0;
    }

    Serial.print("counter=");
    Serial.println(counter);
    prev = millis();
    counter = 0;
  }
}

another sketch got serial monitor results just: x=4 why?

int numSamples = 0;
long t, t0;

void setup ( )
{
  Serial.begin(115200);
  Serial.println("xxx_setup!");

  Serial.print("File   : "), Serial.println(__FILE__);
  const char compile_date[] = __DATE__ " " __TIME__;
  Serial.print("Compile timestamp: ");
  Serial.println(compile_date);

  //pinMode (A0 , INPUT) ;

  ADCSRA = 0;                       // clear ADCSRA register
  ADCSRB = 0;                       // clear ADCSRB register
  ADMUX |= (0 & 0x07);              // set A0 analog input pin
  ADMUX |= (1 << REFS0);            // set reference voltage
  ADMUX |= (1 << ADLAR);            // left align ADC value to 8 bits from ADCH AREGISTER

  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);  // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                 // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);  // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE);           // enable auto trigger
  ADCSRA |= (1 << ADIE);            // enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN);            // enable ADC
  ADCSRA |= (1 << ADSC);            // enable ADC measurement
}

ISR (ADC_vect)
{
  byte x = ADCH;      // read 8 bit value from ADC

  Serial.print("x = ");
  Serial.println(x);
  
  numSamples++;
}

void loop ( )
{
  if (numSamples >= 1000)
  {
    t = micros ( ) - t0 ; // calculate elapsed time

    Serial.print ( "Sampling frequency:" ) ;
    Serial.print ( ( float )1000000 / t) ;
    Serial.println ( "KHz" ) ;

    delay (2000) ;

    // restart
    t0 = micros();
    numSamples = 0;
  }
}

BTW. I used MEGA2560.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.