Hi,
I am making a audio recorder with teensy3.5 and 3.6 using SPH0645 mems i2s mic from adafruit. I want the device to record 10sec audio continuously till the battery last(I am using 3.7v 2000mah lipo battery to power the boards). I am able to record good quality wav files but i found that some samples are taking more time to write to sdcard, usually it will take 1000us to 2500us to write each 512 bytes of data but some samples are taking around 50000us or even more than that(one exception i got was 0.3sec). When i check time stamp of all the files recorded, time difference in some of the files are around 11,12 and 14 sec. As per calculation, in 24 hours 8640 files(10sec) should be created in sdcard. But actual files on sdcard will be 150-200 less. I want to know if its the problem with sd library or something else. I am tested device with 16khz,32khz and 44.1khz at 24mhz core clock selected. I am posting my code which includes sdcard profiling.
I am making a audio recorder with teensy3.5 and 3.6 using SPH0645 mems i2s mic from adafruit. I want the device to record 10sec audio continuously till the battery last(I am using 3.7v 2000mah lipo battery to power the boards). I am able to record good quality wav files but i found that some samples are taking more time to write to sdcard, usually it will take 1000us to 2500us to write each 512 bytes of data but some samples are taking around 50000us or even more than that(one exception i got was 0.3sec). When i check time stamp of all the files recorded, time difference in some of the files are around 11,12 and 14 sec. As per calculation, in 24 hours 8640 files(10sec) should be created in sdcard. But actual files on sdcard will be 150-200 less. I want to know if its the problem with sd library or something else. I am tested device with 16khz,32khz and 44.1khz at 24mhz core clock selected. I am posting my code which includes sdcard profiling.
Code:
#include <SPI.h>
#include <SD.h>
#include <SD_t3.h>
#include <SerialFlash.h>
#include <Audio.h>
#include <Wire.h>
#define DEBUG 1 //uncomment this to enable serial print AT command output
#ifdef DEBUG //TODO: Print filename
#define DEBUG_PRINT(x) \
Serial.print(x); \
Serial.print(" : Line: "); \
Serial.print(__LINE__); \
Serial.println ("");
#else
#define DEBUG_PRINT(x) do {} while (0)
#endif
typedef struct {
uint32_t file_start_time;
uint32_t data_available_time[1750];
uint32_t buffer_fill_time[1750]; //350
uint32_t buffer_Sd[1750]; //256
uint32_t file_end_time;
} Timing_analysis;
Timing_analysis arr_time;
uint16_t buffer_counter = 0;
uint16_t buffer_counter2 = 0;
bool recordInProgress = false;
char* file_name = "K";
//write wav
unsigned long ChunkSize = 0L;
unsigned long Subchunk1Size = 16;
unsigned int AudioFormat = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 44100;
unsigned int bitsPerSample = 16;
unsigned long byteRate = sampleRate * numChannels * (bitsPerSample / 8); // samplerate x channels x (bitspersample / 8)
unsigned int blockAlign = numChannels * bitsPerSample / 8;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;
char filename[16];
uint32_t filenumber=0;
byte buffer_data[512];
uint16_t queue_var = 0;
AudioInputI2S i2s1;
AudioAmplifier amp1;
AudioFilterBiquad biquad1;
AudioRecordQueue queue1;
AudioConnection patchCord1(i2s1, 0, amp1, 0);
AudioConnection patchCord2(amp1, biquad1);
AudioConnection patchCord3(biquad1, queue1);
File frec;
elapsedMicros usecs = 0;
uint32_t device_start_time = 0;
// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN BUILTIN_SDCARD
#define SDCARD_MOSI_PIN 11
#define SDCARD_SCK_PIN 13
#define LED 18
void setI2SFreq(int freq);
void setup()
{
while (!Serial) {}
Serial.print("START!");
pinMode(LED, OUTPUT);
Serial.begin(115200);
AudioMemory(60);
amp1.gain(15);
biquad1.setHighpass(0, 200, 0.707);
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
setI2SFreq(sampleRate);
if (!(SD.begin(SDCARD_CS_PIN)))
{
// stop here, but print a message repetitively
while (1)
{
Serial.println("Unable to access the SD card");
delay(500);
}
}
}
void loop()
{
if (!recordInProgress)
{
startRecording();
}
else if (recByteSaved < (sampleRate * 2 * 10))
{
continueRecording();
}
else if (recordInProgress)
{
stopRecording();
}
}
void startRecording()
{
digitalWrite(LED, HIGH);
recordInProgress = true;
DEBUG_PRINT(("startRecording"));
snprintf(filename, sizeof(filename), "%s%lu.wav", file_name, filenumber);
Serial.println(filename);
if (SD.exists(filename))
{
filenumber++;
snprintf(filename, sizeof(filename), "%s%lu.wav", file_name, filenumber);
}
frec = SD.open(filename, FILE_WRITE);
device_start_time = millis();
arr_time.file_start_time = micros();
writeWavHeader();
if (frec)
{
queue1.begin();
recByteSaved = 0L;
}
}
void continueRecording(void)
{
if (queue1.available() >= 2)
{
arr_time.data_available_time[buffer_counter2] = micros(); // - arr_time.data_available_time[buffer_counter2]
arr_time.buffer_fill_time[buffer_counter] = micros();
memcpy(buffer_data, queue1.readBuffer(), 256);
queue1.freeBuffer();
memcpy(buffer_data + 256, queue1.readBuffer(), 256);
queue1.freeBuffer();
arr_time.buffer_fill_time[buffer_counter] = micros() - arr_time.buffer_fill_time[buffer_counter];
buffer_counter++;
arr_time.buffer_Sd[buffer_counter2] = micros();
frec.write(buffer_data, 512); // write all 512 bytes to the SD card
arr_time.buffer_Sd[buffer_counter2] = micros() - arr_time.buffer_Sd[buffer_counter2];
buffer_counter2++;
recByteSaved += 512;
}
}
void stopRecording(void)
{
DEBUG_PRINT(("stopRecording"));
queue1.end();
writeOutHeader();
arr_time.file_end_time = micros();
Serial.println("buffer_counter");
Serial.println(buffer_counter);
Serial.println("BUFF FiLL time");
Serial.print("\t");
Serial.print("SD write time");
Serial.print("\t");
Serial.print("data available time");
Serial.print("\n");
for (uint16_t j = 0; j < buffer_counter; j++)
{
Serial.print("\t");
Serial.print(arr_time.buffer_fill_time[j]);
Serial.print("\t");
Serial.print("");
Serial.print(arr_time.buffer_Sd[j]);
Serial.print("\t");
Serial.print("");
Serial.print(arr_time.data_available_time[j] - arr_time.data_available_time[j-1]);
Serial.print("\n");
}
Serial.println("\t");
Serial.println(" SD_write_time:");
Serial.println(arr_time.file_end_time - arr_time.file_start_time);
buffer_counter = 0;
buffer_counter2 = 0;
recordInProgress = false;
}
void writeOutHeader() // update WAV header with final filesize/datasize
{
// NumSamples = (recByteSaved*8)/bitsPerSample/numChannels;
// Subchunk2Size = NumSamples*numChannels*bitsPerSample/8; // number of samples x number of channels x number of bytes per sample
Subchunk2Size = recByteSaved - 36;
ChunkSize = Subchunk2Size + 36;
frec.seek(0);
frec.write("RIFF");
byte1 = ChunkSize & 0xff;
byte2 = (ChunkSize >> 8) & 0xff;
byte3 = (ChunkSize >> 16) & 0xff;
byte4 = (ChunkSize >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.write("WAVE");
frec.write("fmt ");
byte1 = Subchunk1Size & 0xff;
byte2 = (Subchunk1Size >> 8) & 0xff;
byte3 = (Subchunk1Size >> 16) & 0xff;
byte4 = (Subchunk1Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = AudioFormat & 0xff;
byte2 = (AudioFormat >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = numChannels & 0xff;
byte2 = (numChannels >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = sampleRate & 0xff;
byte2 = (sampleRate >> 8) & 0xff;
byte3 = (sampleRate >> 16) & 0xff;
byte4 = (sampleRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = byteRate & 0xff;
byte2 = (byteRate >> 8) & 0xff;
byte3 = (byteRate >> 16) & 0xff;
byte4 = (byteRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = blockAlign & 0xff;
byte2 = (blockAlign >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = bitsPerSample & 0xff;
byte2 = (bitsPerSample >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
frec.write("data");
byte1 = Subchunk2Size & 0xff;
byte2 = (Subchunk2Size >> 8) & 0xff;
byte3 = (Subchunk2Size >> 16) & 0xff;
byte4 = (Subchunk2Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.close();
Serial.println("header written");
Serial.print("Subchunk2: ");
Serial.println(Subchunk2Size);
}
void writeWavHeader(void) // write out original WAV header to file
{
frec.seek(0);
frec.write("RIFF");
byte1 = ChunkSize & 0xff;
byte2 = (ChunkSize >> 8) & 0xff;
byte3 = (ChunkSize >> 16) & 0xff;
byte4 = (ChunkSize >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
frec.write("WAVE");
frec.write("fmt ");
byte1 = Subchunk1Size & 0xff;
byte2 = (Subchunk1Size >> 8) & 0xff;
byte3 = (Subchunk1Size >> 16) & 0xff;
byte4 = (Subchunk1Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = AudioFormat & 0xff;
byte2 = (AudioFormat >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = numChannels & 0xff;
byte2 = (numChannels >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = sampleRate & 0xff;
byte2 = (sampleRate >> 8) & 0xff;
byte3 = (sampleRate >> 16) & 0xff;
byte4 = (sampleRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = byteRate & 0xff;
byte2 = (byteRate >> 8) & 0xff;
byte3 = (byteRate >> 16) & 0xff;
byte4 = (byteRate >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
byte1 = blockAlign & 0xff;
byte2 = (blockAlign >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
byte1 = bitsPerSample & 0xff;
byte2 = (bitsPerSample >> 8) & 0xff;
frec.write(byte1); frec.write(byte2);
frec.write("data");
byte1 = Subchunk2Size & 0xff;
byte2 = (Subchunk2Size >> 8) & 0xff;
byte3 = (Subchunk2Size >> 16) & 0xff;
byte4 = (Subchunk2Size >> 24) & 0xff;
frec.write(byte1); frec.write(byte2); frec.write(byte3); frec.write(byte4);
}
//*****************************************************************************************************************/
//Function to set sample rate
void setI2SFreq(int freq)
{
typedef struct
{
uint8_t mult;
uint16_t div;
} tmclk;
const int numfreqs = 14;
const int samplefreqs[numfreqs] = { 8000, 11025, 16000, 22050, 32000, 44100, (int)44117.64706 , 48000, 88200, (int)44117.64706 * 2, 96000, 176400, (int)44117.64706 * 4, 192000};
#if (F_PLL==16000000)
const tmclk clkArr[numfreqs] = {{16, 125}, {148, 839}, {32, 125}, {145, 411}, {64, 125}, {151, 214}, {12, 17}, {96, 125}, {151, 107}, {24, 17}, {192, 125}, {127, 45}, {48, 17}, {255, 83} };
#elif (F_PLL==72000000)
const tmclk clkArr[numfreqs] = {{32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {128, 1125}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375}, {249, 397}, {32, 51}, {185, 271} };
#elif (F_PLL==96000000)
const tmclk clkArr[numfreqs] = {{8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {32, 375}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125}, {151, 321}, {8, 17}, {64, 125} };
#elif (F_PLL==120000000)
const tmclk clkArr[numfreqs] = {{32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {128, 1875}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625}, {178, 473}, {32, 85}, {145, 354} };
#elif (F_PLL==144000000)
const tmclk clkArr[numfreqs] = {{16, 1125}, {49, 2500}, {32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {4, 51}, {32, 375}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375} };
#elif (F_PLL==168000000)
const tmclk clkArr[numfreqs] = {{32, 2625}, {21, 1250}, {64, 2625}, {21, 625}, {128, 2625}, {42, 625}, {8, 119}, {64, 875}, {84, 625}, {16, 119}, {128, 875}, {168, 625}, {32, 119}, {189, 646} };
#elif (F_PLL==180000000)
const tmclk clkArr[numfreqs] = {{46, 4043}, {49, 3125}, {73, 3208}, {98, 3125}, {183, 4021}, {196, 3125}, {16, 255}, {128, 1875}, {107, 853}, {32, 255}, {219, 1604}, {214, 853}, {64, 255}, {219, 802} };
#elif (F_PLL==192000000)
const tmclk clkArr[numfreqs] = {{4, 375}, {37, 2517}, {8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {1, 17}, {8, 125}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125} };
#elif (F_PLL==216000000)
const tmclk clkArr[numfreqs] = {{32, 3375}, {49, 3750}, {64, 3375}, {49, 1875}, {128, 3375}, {98, 1875}, {8, 153}, {64, 1125}, {196, 1875}, {16, 153}, {128, 1125}, {226, 1081}, {32, 153}, {147, 646} };
#elif (F_PLL==240000000)
const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
#endif
for (int f = 0; f < numfreqs; f++) {
if ( freq == samplefreqs[f] ) {
while (I2S0_MCR & I2S_MCR_DUF) ;
I2S0_MDR = I2S_MDR_FRACT((clkArr[f].mult - 1)) | I2S_MDR_DIVIDE((clkArr[f].div - 1));
return;
}
}
}
//*****************************************************************************************************************/