If one wants to do quick bursts of free-running ADC conversions, should one pause and restart using:
The ADC enable bit: bitClear(ADCSRA,ADEN)
& bitSet(ADCSRA,ADEN)
,
The interrupt enable bit bitClear(ADCSRA,ADIE)
& bitSet(ADCSRA,ADIE)
,
The start conversion bit bitClear(ADCSRA,ADSC)
& bitSet(ADCSRA,ADSC)
,
or do you need some more complicated combination of the bits?
Here's some code where I'm trying to trigger a pulse and burst of samples and then report back to the host computer:
const int numSamples = 20;
const byte startPin = PD0; // start signal (pullup)
const byte pulsePin = PD6; // Normally low
const int pulse_us = 10 ; // output pulse length
int16_t sampleData[numSamples];
volatile int sample;
unsigned long t0, t;
// state machine:
typedef enum { STATE_NONE, // idle
STATE_SAMPLING, // record ADC
STATE_DONE, // report data
} states;
// current state-machine state
volatile states state = STATE_NONE;
void setup()
{
Serial.begin(115200);
pinMode(startPin,INPUT_PULLUP);
pinMode(pulsePin,OUTPUT);
// Clear ADC
ADCSRA = 0;
ADCSRB = 0;
ADMUX = 0;
ADMUX |= (0b0000 << MUX0); // Choose ADC channel 0
ADMUX |= (0b01 << REFS0); // Choose VCC reference voltage
bitSet(ADMUX,ADLAR); // ADC left align ADC result into ADCH register
// 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 |= (0b101 << ADPS0); // /32 : 16M/32/13=38461Hz 26us
//ADCSRA |= (0b100 << ADPS0); // /16 : 16M/16/13=76923Hz 13us 10 bit precision
ADCSRA |= (0b011 << ADPS0); // /8 : 16M/8/13=153.8KHz 6.5us low precision
//ADCSRA |= (0b010 << ADPS0); // /4 : 16M/4/13=307.6KHz 3.2us lower precision
//ADCSRA |= (0b001 << ADPS0); // /2 : 16M/2/13=615.4Hz 1.6us bad precision
ADCSRB |= (0b000 << ADTS0); // Choose free running trigger mode
bitSet(ADCSRA,ADATE); // enable auto trigger mode per ADSCRB:ADTSx
bitSet(ADCSRA,ADIE); // enable interrupts when measurement complete
bitSet(ADCSRA,ADEN); // enable ADC
bitSet(ADCSRA,ADSC); // start ADC measurements
}
ISR(ADC_vect) // Record samples
{
sampleData[sample++] = ADC; // read 10bit value from ADC
if (sample >= numSamples) {
bitClear(ADCSRA,ADEN); // stop recording
state = STATE_DONE;
}
}
void report(){
t = micros()-t0; // calculate elapsed time
Serial.print("Sampling frequency: ");
Serial.print((float)1000000/t);
Serial.println(" KHz");
for (int i = 0; i < numSamples; i++){
Serial.print(i);
Serial.print(' ');
Serial.print(sampleData[i]);
Serial.println();
}
}
void startSampling(){
sample = 0;
t0 = micros();
digitalWrite(pulsePin,HIGH);
bitSet(ADCSRA,ADEN); // start ADC
delayMicroseconds(pulse_us);
digitalWrite(pulsePin,LOW);
}
void loop()
{
switch (state){
case STATE_NONE:
if(digitalRead(startPin)==LOW){
startSampling();
state = STATE_SAMPLING;
}
break;
case STATE_SAMPLING:
break;
case STATE_DONE:
report();
state = STATE_NONE;
break;
default:
;;
}
}
Toggling ADEN
was my first thought, but ADIE
seems as if it would be faster, and ADSC
seems cleanest, if it works to modulate free-running ADC mode. Which would be fastest and cleanest?
I have a Nano on order, but nothing available for testing right now.