Sampling Rate

Hi!

Before I ask my question, I thought I’d first check my logic:
The arduino uno has a clock speed of 16 MHz, and going by atmel’s claim that the 328 can execute 1 MIPS/MHz, that means the uno executes code at 16 MIPS. Now, I would assume that if I were sampling an analog signal, the sampling rate would be 16 MHz.

Is it possible to pre-scale the clock so I could sample the signal at, say, 8 kHz?

ex- The for loop would sample the signal at 8 kHz until 100 samples have been added into the array:

for(int i = 0 ; i <100; i++){
array = analogRead(A0);
}
I’m not even sure if I’m following the right logic.
Thanks!

“Now, I would assume that if I were sampling an analog signal, the sampling rate would be 16 MHz.”
If you read the atmega328 datasheet, you will see this is not possible.
The onboard ADC uses sample & hold capacitor that charges up, and is then converted to a digital value.
As the arduino code is written, the sampling rate maxes out at about 10 KHz.

You can write a while loop running at 0.125mS (125uS) for 8KHz sampling rate, maybe like this:

int analogArray[100]; // elements are indexed 0 to 99
unsigned long currentTime = micros();
for (x = 0; x<100; x=x+1){
while ( (micros() >= (x*125000UL) {
analogArray[x] = analogRead(A0);
analogArray[x] = analogRead(A0);  // read twice, ignore the first, allows for sample/hold settling
// guess would actually sit in here reading until the 125uS passed
} // end while
} // end for:next

Even if analogRead() executed in one clock cycle (it does not, by a long ways), at 8MHz, you'd have one clock cycle per read to deal with the returned value. What would you do with that one clock cycle?

It can sample about, at least, 40khz. Google arduino fastadc.

[quote author=CrossRoads link=topic=79714.msg602336#msg602336 date=1321844912]
[code]
unsigned long currentTime = micros();
for (x = 0; x<100; x=x+1){
while ( (micros() >= (x*125000UL) {

[/quote]

That looks like an infinite loop to me. It also looks like it will sample at 8 Hz rather than 8 kHz.
I imagine what you really meant was to make the while() statement look like:

while (micros() - currentTime < (x + 1)*125UL) {
  ...
}

And, because micros() is a function, and you’re doing 32-bit math, the loop itself probably has significant overhead. But at 16 MHz, you do 2,000 instructions per 8 kHz sample, so as you say, you’ll probably be running the loop many times per sample (which isn’t bad in itself).
[/code]

I think the idea in general is conveyed, even if I did get the comparison backwards (typo, yeah, that's the ticket) and am off by a factor of 1000 (0.000125 = 0.125mS = 125uS, so somewhere along the line I picked up some extra 0's ...)

Thanks all! I would guess that the 125 µs would be subject to some tweaking as well to make up for the time lost when executing the while loop - but even 125 µs should be good enough.

In theory (and probably in practice too) you can achieve ~77 Ksps sampling rate on an AVR, with 8 bit precision. But to get there you need to forget about the Arduino ADC sw layer and program directly the ADC registers (not difficult), and also condition your signal appropriately.

But to get there you need to forget about the Arduino ADC sw layer and program directly the ADC registers (not difficult), and also condition your signal appropriately.

Can you show how?

There is a project, with variable sampling rate. Upper limit 5.7 usec/sample or 175 kHz. http://arduino.cc/forum/index.php/topic,63186.msg458799.html#msg458799 http://oscilloscopeexpress.blogspot.com/

robtillaart:

But to get there you need to forget about the Arduino ADC sw layer and program directly the ADC registers (not difficult), and also condition your signal appropriately.

Can you show how?

There's a fine example in arduino-00xx/hardware/arduino/cores/arduino/wiring_analog.c and the datasheet for the 328 is certainly helpful.