Yes, digital audio is truly amazing. In another thread I cited audio ADC performance as an example. The person I replied to wrote me off. He said he was interested in "high quality ADCs". If a 124dB, 384kHz Audio ADC isn't impressive what is.
Here is a jitter test sketch. It only captures a counter since the test is how precise scheduling is. It does not use an ISR since many devices/sensors can not be accessed in an ISR using popular Arduino libraries. The I2C Wire library can't be used in an ISR and I2C devices are very common in the Arduino world.
It records the results to an SD. I use my SD library but you can use the "Official Arduino SD library" it's an ancient version of my library with a wrapper to, as you say, "make it user friendly".
The only other library I use is ChibiOS. I did a simple fifo with two semaphores and an array. The data rate is slow, a point every 10,240 usec, since it is common for Arduino users to record things like accelerometers at about 100 Hz.
I ran the test for a number of minutes and there was no jitter between points. micros() in AVR ticks every 4 usec so that limits the accuracy of the test.
Here is calculation of what 4 usec of jitter means in this case. Here is the formula:
SNR due clock jitter:
SNR(dB) = -20log(6.28f*t)
f is the measurement frequency
t is the time jitter in seconds
For t = 4 usec and f about 98 Hz you get about 52 dB. The SNR for an ideal 10-bit ADC is about 62 dB so even this much jitter degrades the signal.
I don't know a lot about audio but I have read about ADC clocks with jitter well below 100 femtoseconds. Wow, not nano, not pico, but femto. I guess you can lease a Galaxy FemtoSecond 77 fsec clock for $233 a month on a six year term.
Here is the sketch for ChibiOS and it is followed by a bit of the file. I look forward to your sketch for this test so I can run it and produce a file.
#include <ChibiOS_AVR.h>
#include <SdFat.h>
// interval between points in units of 1024 usec
const uint16_t intervalTicks = 10;
//------------------------------------------------------------------------------
// SD file definitions
SdFat sd;
SdFile file;
//------------------------------------------------------------------------------
// Fifo definitions
// size of fifo
const size_t FIFO_SIZE = 20;
// count of data records in fifo
SEMAPHORE_DECL(fifoData, 0);
// count of free buffers in fifo
SEMAPHORE_DECL(fifoSpace, FIFO_SIZE);
// data type for fifo item
struct FifoItem_t {
uint32_t usec;
int value;
int error;
};
// array of data items
FifoItem_t fifoArray[FIFO_SIZE];
// head and tail index for fifo
size_t fifoHead = 0;
size_t fifoTail = 0;
//------------------------------------------------------------------------------
// 64 byte stack beyond task switch and interrupt needs
static WORKING_AREA(waThread1, 64);
static msg_t Thread1(void *arg) {
int error = 0;
int count = 0;
while (1) {
chThdSleep(intervalTicks);
// get a buffer
if (chSemWaitTimeout(&fifoSpace, TIME_IMMEDIATE) != RDY_OK) {
// fifo full indicate missed point
error++;
continue;
}
FifoItem_t* p = &fifoArray[fifoHead++];
if (fifoHead >= FIFO_SIZE) fifoHead = 0;
p->usec = micros();
p->value = count++;
p->error = error;
error = 0;
// signal new data
chSemSignal(&fifoData);
}
return 0;
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
Serial.println(F("type any character to begin"));
while(!Serial.available());
// open file
if (!sd.begin() || !file.open("DATA.CSV", O_CREAT | O_WRITE | O_TRUNC)) {
Serial.println(F("SD problem"));
}
// throw away input
while (Serial.read() >= 0);
Serial.println(F("type any character to end"));
// start kernel
chBegin(chSetup);
while(1);
}
//------------------------------------------------------------------------------
void chSetup() {
// start producer thead
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 2, Thread1, NULL);
}
//------------------------------------------------------------------------------
// time in micros of last point
uint32_t last = 0;
void loop() {
// wait for next data point
chSemWait(&fifoData);
FifoItem_t* p = &fifoArray[fifoTail++];
if (fifoTail >= FIFO_SIZE) fifoTail = 0;
file.print(p->usec - last);
last = p->usec;
file.write(',');
file.print(p->value);
file.write(',');
file.println(p->error);
// release space
chSemSignal(&fifoSpace);
if (Serial.available()) {
file.close();
Serial.println(F("Done"));
while(1);
}
}
Here is the file. The first column is the time between points in micros(), the second is the counter, and the third is the number of missed points due to no fifo space.
10240,10,0
10240,11,0
10240,12,0
10240,13,0
10240,14,0
10240,15,0
10240,16,0
10240,17,0
10240,18,0
10240,19,0
10240,20,0
10240,21,0
10240,22,0
10240,23,0
10240,24,0
10240,25,0
10240,26,0
10240,27,0
10240,28,0
10240,29,0
10240,30,0
10240,31,0
10240,32,0
10240,33,0
10240,34,0
10240,35,0
10240,36,0
10240,37,0
10240,38,0
10240,39,0
10240,40,0
10240,41,0
10240,42,0
10240,43,0