First, I'd like to say hi to everyone being my first post on this forum. Actually, I signed in to share a code snippet I wrote this morning with everyone since I found almost nothing around about this topic, besides the very well know blog post of Evaluating Arduino and Due ADCs.
It's about pushing to the limit the performance of analogRead() on the Arduino Due. I needed to record a waveform with a carrier frequency of 1 MHz so I asked myself: "Why not using the Due instead of an FPGA or a portable oscilloscope?" Well, after a profoundly religious morning messing up with the ATSAM3X8E manual from Atmel, testing several configurations of the ADC core, I came out with a rather satisfying solution.
analogRead() takes only 0.67 us to execute on my Arduino Due, without loosing too much precision. I didn't do any methodic testing about the resolution of the ADC at around 1.5Mhz, but I would expect it to be at least 8 bits, which is absolutely honest.
I used a sequence of NOP operations to adjust the ADC speed closer to 1 MHz.
Anyways, here's the code: it records 8192 data points via ADC at around 1 MHz every 10 seconds and sends the results via serial communication to the PC.
bool Valid = false;
bool Rec = false;
int Cur = 0;
const int DataSize = 8192;
int Data[DataSize];
int Val = 0;
#define READ(Pin) \
Val = analogRead(Pin); \
__asm__ __volatile__ ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
void setup() {
// First thing: we want to know EXACTLY how much time it takes an analogRead to run
// Tuned with a signal generation technique ;-)
// This ADC configuration achieves a 1.4927 Mhz sample rate
REG_ADC_MR = 0x10320300;
// initialize the serial communication:
Serial.begin(57600);
}
/*
This reading loop has been tested with a reference signal at 1 MHz and thus optimized to have:
Delay = 1.018(1) us
Sample rate = 0.9818(1) MHz
*/
void loop() {
READ(A0);
if (Rec && (Cur < DataSize)) {
Data[Cur++] = Val;
} else {
if (Rec && (Cur >= DataSize)) {
for (int i=0; i<DataSize; ++i) {
Serial.println(Data[i]);
}
Rec = false;
Valid = true;
Cur = 0;
delay(10000);
}
if (!Rec && (Val > 100)) {
Rec = true;
Cur = 0;
Data[Cur++] = Val;
}
}
}
If you're curious about the resolution of such a readout, attached there's the spectrum of a 0.5 MHz recorded square wave.
