I've been thinking about a larger project but what is currently slowing me down is the ADC implementation. I'll be looking to digitize human voice, walkie-talkie style (high frequencies aren't of interest).
Using the Ardunio Uno, with the ATMega328, the ADC is rated 15 kSaps at maximum resolution -> www.atmel.com/Images/doc8161.pdf#page=250
Using the analogRead function built into Arduino has some redundancies I would need to bypass (setting up ADMUX, using 10 bits when I only want 8 right now, blocking call) (see arduino-1.0.1\hardware\arduino\cores\arduinowiring_analog.c)
So I propose an interrupt based method using ISR(ADC_vect) to fill up two finite buffers, then the interrupt triggers another conversion. Should one buffer be full, the ADC reading will be placed in the other buffer.
This double buffering method would allow a chunk of readings to be transmitted while simultaneously acquiring. The transmitting of chunks would actually be in a timer ISR such that the only code in the loop() would be for updating LCD screen, user input/ouput etc.
Any comments on the double buffering method? Here is what I've come up with so far using 10 bit ADC results, a single buffer length of 500 and transfers over serial port for debug.
#include <avr/interrupt.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define ADClength 500
unsigned int ADCreadings[ADClength]; //my implementation of a buffer
unsigned int ADCpos = 0; //current write position of the buffer
void setup() {
Serial.begin(115200);
sbi(ADCSRA, ADIE); // Enable ADC Interrupt
sbi(ADCSRA, ADPS2); //Set the ADC prescaler to
sbi(ADCSRA, ADPS1); // 110 which is
cbi(ADCSRA, ADPS0); // divide by 64
sbi(ADCSRA, ADEN); //Enable ADC conversions
ADMUX = (DEFAULT << 6) | (0 & 0x07); //taken from Arduino_wirings.c sets up AVCC reference and pin 0
sbi(ADCSRA, ADSC); //Start a ADC conversion to get the whole thing started
}
void loop(){
if (ADCpos >= ADClength) { //Is the buffer at max capacity?
for (int i = 0; i < ADClength; i++) {//if yes, then print over serial port all values
Serial.println(ADCreadings[i]);
}
ADCpos = 0; //reset the position
sbi(ADCSRA, ADSC);//restart ADC conversions
}
}
ISR(ADC_vect)
{
byte high, low;
low = ADCL; //Must read ADCL before
high = ADCH; // ADCH
if (ADCpos < ADClength) {//Do we have room in the buffer?
ADCreadings[ADCpos++] = (high << 8) | low; //Yes, add in the 10 bit sample.
sbi(ADCSRA, ADSC); //start another conversion
}
}