Pages: [1]   Go Down
Author Topic: Experiment - split up ananlog read in 3 steps  (Read 1594 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

AnalogRead() takes about 110 micros() on a UNO. During this time the call is blocking and only interrupts can be served.

As I did not like that I did an experiment to check if analogRead() can be split in 3 functions:

void AR_Start(uint8_t pin);   // starting the conversion
bool AR_Ready();                 // checking if conversion is done
int AR_Value());                   // reading the value

Find below a first experiment in which I broke up the code of analogRead() in these 3 steps (removed some lines) and it seems to work.  (using a floating line).

output: (count++, micros, value) except for 1st 2 lines
Code:
start:
398
248 112 386
231 104 339
240 108 312
233 104 293
232 104 280
247 112 273
241 108 275
234 108 291
233 104 310
234 112 338
240 108 355
233 108 362
The output indicates that it takes 100++ micros() to do the analogRead(), so there is quite some time to do some computing between starting the analogRead() and reading its value.  In that time I can:
- increment an int 200+ times
- do digitalWrite 20+ times
- etc

The nice part is that in theory I can start an new analogRead directly after reading its value so the new value is (almost) ready when I need it - OK the reading might become outdated or other effects may arise, to be investigated.

(The highly experimental code - all disclaimers apply smiley-wink
Code:
//
//    FILE: asyncAnalogRead.pde
//  AUTHOR: Rob Tillaart
//    DATE: 09-jun-2012
//
// PUPROSE: experimental
//

void setup()
{
  Serial.begin(115200);
  Serial.println("start: ");
  Serial.println(analogRead(0));  // traditional
}

void loop()
{
  unsigned long start=0;
  unsigned long duration = 0;
  int count=0;

  AR_Start(0);
  start = micros();
  while(!AR_Ready())
  {
    count++; // dummy behaviour
  }
  duration = micros() - start;

  Serial.print(count);
  Serial.print("\t");
  Serial.print(duration);
  Serial.print("\t");
  Serial.print(AR_Value());
  Serial.println();
  delay(200);
}

#include "wiring_private.h"
#include "pins_arduino.h"

// uint8_t analog_reference = DEFAULT;

void AR_Start(uint8_t pin)
{
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#else
  if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

#if defined(ADCSRB) && defined(MUX5)
  // the MUX5 bit of ADCSRB selects whether we're reading from channels
  // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
  ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
  // set the analog reference (high two bits of ADMUX) and select the
  // channel (low 4 bits).  this also sets ADLAR (left-adjust result)
  // to 0 (the default).
#if defined(ADMUX)
  ADMUX = (DEFAULT << 6) | (pin & 0x07);
#endif

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

boolean AR_Ready()
{
  // ADSC is cleared when the conversion finishes
  return bit_is_set(ADCSRA, ADSC)==0;
}

int AR_Value()
{

  // we have to read ADCL first; doing so locks both ADCL
  // and ADCH until ADCH is read.  reading ADCL second would
  // cause the results of each conversion to be discarded,
  // as ADCL and ADCH would be locked when it completed.
  int low  = ADCL;
  int high = ADCH;
  // combine the two bytes
  return (high << 8) | low;
}
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Dallas, Texas
Offline Offline
God Member
*****
Karma: 3
Posts: 718
Old, decrepit curmugeon
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can speed up the time it takes by adjusting the prescaler value.  I played with it below and this didn't change the number of bits generated for me.

Code:
ADCSRA = ADCSRA & 252; // Speed up adc conversion by adjusting adc clock prescaler

The scaler can be further reduced providing even more of a speedup if less precision is needed.  In the sketch I did this on, I was able to read (and write to SD card) about 12,000,000 bytes per day.  With this prescalar change I got 40,000,000 bytes per day.

And this can be combined with your approach, if less processing is needed during the analog conversion.
Logged

New true random number library available at: http://code.google.com/p/avr-hardware-random-number-generation/

Current version 0.7.2

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


unfortunately I cannot change the prescaler to get more precission  (I need to oversample for that)
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Montreal
Offline Offline
Edison Member
*
Karma: 23
Posts: 2487
Per aspera ad astra.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why not to use default "Conversion completed" interruption?
Quote
The nice part is that in theory I can start an new analogRead directly after reading its value so the new value is (almost) ready when I need it
Usually I start analog measurements when I need a data at this specific point in time, not when I need a value that was taken "a while" ago. Start Conversion Timing for most application is critical, doesn't matter when data is ready, as soon as conversion completed before new measurements has to be done.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Quote
Usually I start analog measurements when I need a data at this specific point in time
Agree, Normally I do too but sometimes I want to do high speed sampling as possible.

My UNO makes about 8200 analog samples per second if I do not do any math with it, just a raw loop of analogRead().

An example, if I need to do typical thermistor math:
Code:
double Thermister(int RawADC)
{
  double Temp = log(((10240000L/RawADC) - 10000));
  Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
  Temp = Temp - 273.15;            // Convert Kelvin to Celcius
  // Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
  return Temp;
}
this number drops to about 3000 (IIRC) so a bit of float math makes me loose 2/3 of my samples.

Simple sum:
8200 samples = 1 sec   ==>  1 sample = 110 usec

3000 Samples + 3000Math = 1 sec  ==>  (with the above)  ==> 1 Math = 220 usec.

If I can bring the analog sample from 110 usec to 10 usec (as on average there is 100usec waiting time, see above)   1sample + 1 Math becomes 230 usec
That makes it possible to do 1sec/230 usec = 4000+ samples per second  which is >30% more samples per second than traditional.

So this technique would bring the number of samples down from 8200 to 4000 (~1/2) iso to 3000 (~1/3).


Other way to look at it, if I make 8200 analog samples every second and I am polling until ready for 100usec per sample I have been busy waiting for 80% of the time.

Quote
Why not to use default "Conversion completed" interruption?
Never worked with it, do you have an example? or a link?

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Dallas, Texas
Offline Offline
God Member
*****
Karma: 3
Posts: 718
Old, decrepit curmugeon
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Why not to use default "Conversion completed" interruption?
Never worked with it, do you have an example? or a link?

Section two on interrupt driven ADC may help, can't find any arduino examples...

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=56429&start=0
Logged

New true random number library available at: http://code.google.com/p/avr-hardware-random-number-generation/

Current version 0.7.2

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Thanks for the link, added to my TODO list smiley
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 178
Posts: 12288
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Why not to use default "Conversion completed" interruption?
can't find any arduino examples

There are some examples for using Noise Reduction (which is sort of related).  I can't find anything about asynchronous reads either.

@robtillaart: Would auto-triggering with a ring buffer be useful?  Analog readings would be collected (and timestamped) continuously in the background.  The application would pull readings from a shared ring buffer.  I think managing multiple channels is the only tricky part.
Logged

Montreal
Offline Offline
Edison Member
*
Karma: 23
Posts: 2487
Per aspera ad astra.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can't recollect if I seen any such examples, that working with interruption Conversion Complete.  It looks like concept to get maximum quantity samples is not correct from the bases,  even such software exist, and definitely would provide the biggest numbers, BUT. Continue my line of thoughts, that Timing Start Conversion is most critical part, ( quality of samples, not the quantity,  BTW, why do I need to sample temperature 9.6 ksps?), it make more sense to define specific sampling frequency let say 8 kHz, than try to squize something that would be hard to predict. AFAIK, timing to serve ISR is not strictly defined, so application that provide max numbers of samples via ISR_ADC_vect would have unspecified sampling rate.
 There is an other example, which has specific sampling rate, and not pulling ADC waiting results.
http://interface.khm.de/index.php/lab/experiments/arduino-realtime-audio-processing/
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

(related threads)

- http://arduino.cc/forum/index.php/topic,128723.msg971116.html
- http://arduino.cc/forum/index.php/topic,125766.msg946608.html#msg946608 -
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1]   Go Up
Jump to: