benkrasnow
Member
This simple audio recorder code takes I2S input from the Teensy audio shield, and saves a mono channel continuously to SD card. I'm feeding the line-in input on the shield with a 40Hz triangle wave from a bench signal generator. The following code is stripped-down, and does nothing but record audio. When looking at the resulting raw file in Audacity, the waveform has discontinuities that are *not* periodically distributed. The upshot is that recording for 100 seconds, may only produce a file that is 98 seconds long. This gets to be a big error over time, and means the device cannot be used for synchronized data collection. If there is a solution to this, great, let me know, but I'm mostly posting to let others know that recording to SD can be a challenge. Based on my own testing, it seems that the SD card write functions cause some amount of CPU blocking that even the DMA in the audio library cannot interrupt.
Teensy 3.6 @ 180MHz, using built-in SD card slot.
I've tried two different SD cards with similar results, but the distribution and intensity of disruptions may have been different -- hard to tell.
Older, similar thread: https://forum.pjrc.com/threads/52476-Audio-board-recording-while-playing-sampling-frequency-problem
Teensy 3.6 @ 180MHz, using built-in SD card slot.
I've tried two different SD cards with similar results, but the distribution and intensity of disruptions may have been different -- hard to tell.
Older, similar thread: https://forum.pjrc.com/threads/52476-Audio-board-recording-while-playing-sampling-frequency-problem
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#define SDCARD_CS_PIN BUILTIN_SDCARD
#define SDCARD_MOSI_PIN 11 // not actually used
#define SDCARD_SCK_PIN 13 // not actually used
File frec;
// GUItool: begin automatically generated code
AudioInputI2S i2s1; //xy=343,366
AudioRecordQueue queue1; //xy=281,63
AudioConnection patchCord1(i2s1, 0, queue1, 0);
AudioControlSGTL5000 sgtl5000_1; //xy=590,729
// GUItool: end automatically generated code
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;
void setup() {
Serial.begin(9600);
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(240);
// Enable the audio shield, select input, and enable output
sgtl5000_1.enable();
sgtl5000_1.inputSelect(myInput);
sgtl5000_1.volume(0.5);
sgtl5000_1.lineInLevel(8,8);
//sgtl5000_1.adcHighPassFilterDisable();
if (!(SD.begin(SDCARD_CS_PIN))) {
// stop here if no SD card, but print a message
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
Serial.println("startRecording");
if (SD.exists("RECORD.RAW")) {
// The SD library writes new data to the end of the
// file, so to start a new recording, the old file
// must be deleted before new data is written.
SD.remove("RECORD.RAW");
Serial.println("old audio file removed");
}
frec = SD.open("RECORD.RAW", FILE_WRITE);
if (frec) {
queue1.begin();
Serial.println("frec open");
}
}
elapsedMillis flushtimer = 0;
void loop() {
continueRecording();
if(flushtimer > 1000)
{
frec.flush();
flushtimer = 0;
}
}
void continueRecording() {
if (queue1.available() >=2 ) {
byte buffer[512];
// Fetch 2 blocks from the audio library and copy
// into a 512 byte buffer. The Arduino SD library
// is most efficient when full 512 byte sector size
// writes are used.
memcpy(buffer, queue1.readBuffer(), 256);
queue1.freeBuffer();
memcpy(buffer+256, queue1.readBuffer(), 256);
queue1.freeBuffer();
// write all 512 bytes to the SD card
// elapsedMicros usec = 0;
frec.write(buffer, 512);
// Uncomment these lines to see how long SD writes
// are taking. A pair of audio blocks arrives every
// 5802 microseconds, so hopefully most of the writes
// take well under 5802 us. Some will take more, as
// the SD library also must write to the FAT tables
// and the SD card controller manages media erase and
// wear leveling. The queue1 object can buffer
// approximately 301700 us of audio, to allow time
// for occasional high SD card latency, as long as
// the average write time is under 5802 us.
//Serial.print("SD write, us=");
//Serial.println(usec);
}
}