I did a test and the good news is reading the ADC in Noise Reduction Mode in the middle of an SD block transfer seems to work OK.
I did not write rawAnalogReadWithSleep() but it seems to use Noise Reduction Mode.
I added the code between the slashes to the write loop (two bytes are sent for each pass to slightly speed the transfer):
for (uint16_t i = 0; i < 512; i += 2) {
while (!(SPSR & (1 << SPIF)));
//////////////////////////////////////////////////////////////
int rawAnalogReadWithSleep();
if (i == 300) {
rawAnalogReadWithSleep();
Serial.print('.');
}
/////////////////////////////////////////////////////////////
SPDR = buf[i];
while (!(SPSR & (1 << SPIF)));
SPDR = buf[i + 1];
}
I ran this sketch:
#include <SdFat.h>
#include <avr/sleep.h>
SdFat sd;
SdFile file;
ISR(ADC_vect) { }
int rawAnalogReadWithSleep() {
// Generate an interrupt when the conversion is finished
ADCSRA |= _BV(ADIE);
// Enable Noise Reduction Sleep Mode
set_sleep_mode(SLEEP_MODE_ADC);
sleep_enable();
// Any interrupt will wake the processor including the millis interrupt so we have to...
// Loop until the conversion is finished
do
{
// The following line of code is only important on the second pass. For the first pass it has no effect.
// Ensure interrupts are enabled before sleeping
sei();
// Sleep (MUST be called immediately after sei)
sleep_cpu();
// Checking the conversion status has to be done with interrupts disabled to avoid a race condition
// Disable interrupts so the while below is performed without interruption
cli();
}
// Conversion finished? If not, loop.
while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
// No more sleeping
sleep_disable();
// Enable interrupts
sei();
// The Arduino core does not expect an interrupt when a conversion completes so turn interrupts off
ADCSRA &= ~ _BV( ADIE );
// Return the conversion result
return( ADC );
}
void setup() {
Serial.begin(9600);
// setup ADC
analogRead(0);
if (!sd.begin())sd.initErrorHalt();
if(!file.open("ADC_TEST.TXT", O_RDWR | O_CREAT | O_AT_END)) {
sd.errorHalt("opening test.txt for write failed");
}
for (uint16_t i = 0; i < 50000; i++) {
file.println(i);
if (file.writeError) sd.errorHalt("print");
}
file.close();
Serial.println("Done");
}
void loop() {}
Lots of dots get printed and the file has the correct content. The file has 660 blocks.
The bad news is that I can't find proof on the web that Noise Reduction Mode helps.
I tried various tests comparing analogRead() with rawAnalogReadWithSleep() above. If there is an improvement it is really small. Other factors overwhelm the the difference between the two functions. Clean power to the Arduino makes a huge difference.
One curious result is that the two functions return slightly different results. You need to average a 1000 measurements to see the difference.
My test setup was very crude so it is not definitive but as until I see proof I won't believe Noise Reduction Mode is worth the pain.
I hope you prove Noise Reduction Mode gives more accuracy.
Edit:
I did some more work and oversampling and Noise Reduction Mode are extremely frustrating. If I work hard to reduce noise, oversampling will not work since you need noise for oversampling. I don't trust oversampling with the 10-bit AVR ADC, it's too easy to fool yourself.
If you need more accuracy, an external ADC seem like a far better approach.