I can see no problem with your pseudo-code. You should probably post a
complete testable code in order to get better feedback.
That being said, here are a few suggestions:
- You should completely set the ADC registers to the values that suit
your application, instead of just changing a few bits here and there.
This is because you should not care about how the Arduino core
library initializes those registers, especially if this is a
prototype for a final product that will not use Arduino core. For
example, instead of
REG1 = REG1 | 0x01;
you can write something like this:
REG1 = _BV(FOO) // use foo mode...
| _BV(BAR); // ...in the bar setting
where _BV(x)
is a macro from avr-libc that expands to (1<<(x))
,
and the bit names are those of the datasheet, for better readability.
You may want to run the digital filter in the ADC interrupt service
routine. If you can split your processing into a fast filter
(processing every sample) and a slow filter (running on decimated
samples), then do only the fast one in the ISR and leave the slow one
to the main loop. I say this from experience: when I tried to do
all the processing in loop()
I always lost samples, which did not
happen when I moved the filter to the ISR.
But then, make sure your filter is optimized to be fast. Avoid
floating point operations in the ISR if at all possible.
I have written a program that looks very similar to what you are trying
to do: it samples an analog input at 9.6 kS/s and runs an
homodyne detection
filter in order to extract the signal power in a very narrow band around
1 kHz. The ADC is set to free running mode. In the ADC ISR, I
retrieve the sample, run it through the filter, and store the result
into volatile variables. In loop()
, I read these back from time to
time. Here is how I set the ADC:
static void configure_adc()
{
ADMUX = _BV(REFS0) // ref = AVCC
| _BV(ADLAR) // left adjust result
| analog_in; // input channel
ADCSRB = 0; // free running mode
ADCSRA = _BV(ADEN) // enable
| _BV(ADSC) // start conversion
| _BV(ADATE) // auto trigger enable
| _BV(ADIF) // clear interrupt flag
| _BV(ADIE) // interrupt enable
| 7; // prescaler = 128
}
The complete program is available here:
homodyne.ino.
It was initially intended for an Arduino Uno, but it runs unmodified on
a Leonardo clone.
analogRead
after setting the registers?analogRead
does change the ADCSRB register. So if you are setting ADC High Speed Mode (ADHSM
), that will be overwritten. The clock prescaler is only set in the init function, so you should be able to overwrite this in the setup function