SD taking more time to write samples

Status
Not open for further replies.

iammb

Member
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.

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;
    }
  }
}
//*****************************************************************************************************************/
 
I want to know if its the problem with sd library or something else.
No, this is a well known 'feature' of any SD card.
they all have a build-in controller that is handling bad blocks, wear leveling, etc.
do expect from time to time 'significant' delays. Good logging programs have a sufficient large buffer to cover 100-150 ms worth of data.
Also there are good and less good manufacturers.

Additionally, the FS may needs sometimes more time to find and allocate new clusters to a file, but this can be minimized by freshly formatted disks and pre-allocation of blocks. In this context the exFAT behaves better than FAT32, but unfortunately the stock SD library does not support exFAT.
 
I've experimented this issue too. I was planing to adapt the recoding example sketch including a bigger buffer. Are there any other best practices with the audio library in order to obtain reliable recordings?
 
I've experimented this issue too. I was planing to adapt the recoding example sketch including a bigger buffer. Are there any other best practices with the audio library in order to obtain reliable recordings?

use the audio record queue object.
 
I searched on the forum and i came to know that SD fat library doesn't work with Audio library. So is there any other way to minimize these delay?
 
I read this post : https://forum.pjrc.com/threads/34327-Audio-library-and-SdFat-Library . If sdfat is faster than sd library, how to use it with audio library?

In your code (OP) you are not using SD specific Audio objects. So, you can mix you logger with SdFat.

comment the include of SD.h and follow the the examples of Bill Greiman on how to access SdFat.
Should be easy to adapt.

Or search the forum for microSoundRecorder , or bat detector or "Using-SdFat-to-acces-Teensy-3-6-SD-internal-card-(-amp-with-audio-board)?" for alternative approaches
 
use the audio record queue object.

I am using it indeed. But sometimes I am missing information. What I am not sure of is where/why is that data being missed. I don't know if storing the queue data in a bigger buffer would help.

I read this post : https://forum.pjrc.com/threads/34327-Audio-library-and-SdFat-Library . If sdfat is faster than sd library, how to use it with audio library?

You can check here how to use it with the audio library. What looks more challenging is using it with the audio board, but I don't know if that is your case.
 
Hi,
As advised by WMXZ, i referred microSoundRecorder and bat detector and included sdfs library in my project. Sdfs performance if way better than SD.h. Earlier i was having issue of timestamp gap of 11,12 or even 15 sec between files(when i am trying to record 10 sec audio continuously with SD.h), which is minimized using sdfs library. While recording files continuously(10 sec), i still see some of the files with timestamp gap of 9sec and 11sec. I am not able to figure out how its writing 10sec wav file in 9sec, because when i play that file on media player it plays correctly. These time gaps start occurring after 15-20k files are recorded on sdcard. Code mentioned below does continuous recording
Code:
#include "device.h"
#include <Wire.h>
#include <TimeLib.h>
#include "RTClib.h" // RealTimeClock Library for DS1307 and DS3231
#include "SdFs.h"
#include "record_queue.h"
#include "input_i2s.h"
#include "mixer.h"
#include "filter_biquad.h"
#include "MAX17043.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

//************defines*****************//
#define BAUD             115200
#define NEW_BAUDRATE     921600 

#define BYTES_IN_HEADER   256
#define BYTES_WAVHEADER   36

//***********pin_configuration**********//
#define BUTTON            4
#define LED_REC           36 // RECLED used to indicate initialization
#define LED_UPL           37 // SDLED used for upload indication
#define LED_NETSTAT       38 // NETSTATLED
#define ERR_LED           39 // ERR LED used to indicate Error  
#define REC_TIME          10//  Length of recorded wav file

//***********MIC constants**********//
#define SAMPLE_RATE       16000
#define MIC_GAIN          15

#define FILE_NAME         "A"                 //Add single char for filename
#define DEVICE_ID         "DEV1"
/************************************************************************************
                                  SDCARD  SETTINGS (NEW LIBRARY)                      
************************************************************************************/
// SD_FAT_TYPE = 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 3

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif  // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 1
SdFat sd;
File frec;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile frec,ftx;
#else  // SD_FAT_TYPE
//#error Invalid SD_FAT_TYPE
#endif  // SD_FAT_TYPE
//************************************************************************************//

RTC_DS1307 RTC;

AudioInputI2S            i2s1;
AudioAmplifier           amp1;
AudioFilterBiquad        biquad1;
AudioRecordQueue         queue1;
AudioConnection          patchCord1(i2s1, 0, amp1, 0);
AudioConnection          patchCord2(amp1, biquad1);
AudioConnection          patchCord3(biquad1, queue1);

//********** recording_flags **********************************//
bool recordInProgress = false;
bool recording_flag = false;
bool recording_started = false;
//********** recording_constants **********************************//

#define SUB_CHUNK_1_SIZE  16
#define AUDIO_FORMAT      1     //WAV FILE
#define NUM_CHANNELS      1     //MONO:1  STEREO:2
#define BITS_PER_SAMPLE   16    
#define BITS_PER_BYTE     8
#define BYTE_RATE         SAMPLE_RATE*NUM_CHANNELS*(BITS_PER_SAMPLE/BITS_PER_BYTE) // SAMPLE_RATE x channels x (BITS_PER_SAMPLE / 8)
#define BLOCK_ALIGN       NUM_CHANNELS*(BITS_PER_SAMPLE/BITS_PER_BYTE)

//********** recording_variables **********************************//
unsigned long ChunkSize = 0L;
unsigned long Subchunk2Size = 0L;
unsigned long recByteSaved = 0L;
unsigned long NumSamples = 0L;
byte byte1, byte2, byte3, byte4;
char const* Firm_rev = "Ver1.0";
unsigned long sizeof_icmt_chunk = 0;
unsigned long length_icmt_comment = 200;
char icmt_comment[200]={0};
byte Fdate = 0, Fmonth = 0, Fhour = 0, Fmin = 0, Fsec = 0;
uint16_t Fyear = 0;
char filename[30] = {0};
uint32_t filenumber = 0;

//********** recording_functions **********************************//
void startRecording(void);
void stopRecording(void);
void recording(void);
void writeWavHeader(void);
void continueRecording(void);
void dateTime(uint16_t* date, uint16_t* time);
void writeOutHeader(void);
extern void Set_Icmt_comment(void);

//***************************MAIN CODE************************************
void setup()
{
  Serial.begin(BAUD);                      //initialise UART 
  Wire.begin();
  RTC.begin();
    
  DateTime now = RTC.now();
  DateTime compiled = DateTime(__DATE__, __TIME__);
  if (now.unixtime() < compiled.unixtime()) {
  Serial.println("RTC is older than compile time! Updating");
  // following line sets the RTC to the date & time this sketch was compiled    
  RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  
  pinMode_setup();
  FuelGauge.begin();                       //initialise fuel gauge
  Fhour = now.hour();Fmin=now.minute();Fsec=now.second();Fdate=now.day();Fmonth=now.month();Fyear=now.year();
  setTime(Fhour, Fmin, Fsec, Fdate, Fmonth,Fyear);
  SDcard_check();
  DEBUG_PRINT((icmt_comment));
  microphone_initialization();
  queue1.begin();
}
void loop()
{
  recording();  
}
//*****************************************************************************************************************/
//Set wave file header with Operator, Device ID, Batt voltage and %
void Set_Icmt_comment(void)
{
  snprintf(icmt_comment, sizeof(icmt_comment), "Operator:%s, DeviceID:%s, Batt: %.1fV, Pct:%.1f, Signal: %s-%s, Firm_rev: %s, Timestamp:%d/%02d/%02d-%02d:%02d:%02d, Latitude:%s, Longitude:%s,Clock:%d ", "NA",DEVICE_ID, FuelGauge.voltage(), FuelGauge.percent(),"NA","NA",Firm_rev,year(),month(),day(),hour(),minute(),second(),"NA","NA",F_CPU);
  DEBUG_PRINT((icmt_comment));
}

//*****************************************************************************************************************/

//initialize microphone and sdcard
void microphone_initialization()
{
    AudioMemory(200);
    amp1.gain(MIC_GAIN);
    biquad1.setHighpass(0, 200, 0.707);           //200 is cutoff frequency
    
    setI2SFreq(SAMPLE_RATE);
}

//*****************************************************************************************************************/

void SDcard_check(void)
{
//  if (!(sd.begin(SD_CONFIG)))
  if (!(sd.begin(SdioConfig(FIFO_SDIO))))
  {
    DEBUG_PRINT(("SD Error!"));
    // stop here, but print a message repetitively
    digitalWrite(LED_UPL,HIGH); // SD LED set
    while (1)
    {
      DEBUG_PRINT(("Unable to access the SD card"));
      digitalWrite(ERR_LED,HIGH); // ERRLED set
      delay(500);
      digitalWrite(ERR_LED,LOW); // ERRLED set
      delay(500);
    }
  }
  FsDateTime::callback = dateTime;    //callback function to set time on recorded files
}
//*************************Pin initialisation********************************************
void pinMode_setup()
{
  pinMode(LED_REC, OUTPUT);
  pinMode(ERR_LED,OUTPUT);
  pinMode(LED_UPL,OUTPUT);
  pinMode(PWR_PIN, OUTPUT);
  pinMode(NTWRK_STAT, INPUT);
  pinMode(LED_NETSTAT,OUTPUT);
  pinMode(BUTTON,INPUT_PULLUP);
}

//*********************************Start Recording******************************************************

void startRecording(void)
{
  recordInProgress = true;
  DEBUG_PRINT(("startRecording"));
  DEBUG_PRINT(("new filename"));
  Fhour = hour();Fmin=minute();Fsec=second();Fdate=day();Fmonth=month();Fyear=year();
  snprintf(filename, sizeof(filename), "%s%d%02d%02d_%02d%02d%02d.wav",FILE_NAME,Fyear, Fmonth, Fdate, Fhour, Fmin,Fsec);
  DEBUG_PRINT((filename));
  digitalWrite(LED_REC, HIGH);
  Set_Icmt_comment();
  frec = sd.open(filename, FILE_WRITE);
  writeWavHeader();
  recByteSaved = 0L;
  recording_started = true;  
}

//******************************Continue recording**********************************************

void continueRecording(void)
{
  if(recording_started)
  {
    if (queue1.available() >= 2)          //accumulate 512 bytes of data in queue
    {
      memcpy(buffer, queue1.readBuffer(), 256);
      queue1.freeBuffer();
      memcpy(buffer + 256, queue1.readBuffer(), 256);
      queue1.freeBuffer();
      frec.write(buffer, 512);                // write all 512 bytes to the SD card
      recByteSaved += 512;
    }
  }
}

//***********************************************Stop recording*********************************
void stopRecording(void)
{
  DEBUG_PRINT(("stopRecording"));
  writeOutHeader();
  digitalWrite(LED_REC, LOW);
  recordInProgress = false;
  recording_flag = true;
  filenumber++;
}

//**************************************************************************************************

void writeOutHeader(void)  // update WAV header with final filesize/datasize
{

  sizeof_icmt_chunk = (sizeof(icmt_comment)+ 12);
  ChunkSize = recByteSaved + BYTES_IN_HEADER;
  Subchunk2Size = ChunkSize - BYTES_IN_HEADER;

  frec.seek(0);
  frec.print("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.print("WAVE");
  frec.print("fmt ");
  byte1 = SUB_CHUNK_1_SIZE & 0xff;
  byte2 = (SUB_CHUNK_1_SIZE >> 8) & 0xff;
  byte3 = (SUB_CHUNK_1_SIZE >> 16) & 0xff;
  byte4 = (SUB_CHUNK_1_SIZE >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = AUDIO_FORMAT & 0xff;
  byte2 = (AUDIO_FORMAT >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = NUM_CHANNELS & 0xff;
  byte2 = (NUM_CHANNELS >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = SAMPLE_RATE & 0xff;
  byte2 = (SAMPLE_RATE >> 8) & 0xff;
  byte3 = (SAMPLE_RATE >> 16) & 0xff;
  byte4 = (SAMPLE_RATE >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = BYTE_RATE & 0xff;
  byte2 = (BYTE_RATE >> 8) & 0xff;
  byte3 = (BYTE_RATE >> 16) & 0xff;
  byte4 = (BYTE_RATE >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = BLOCK_ALIGN & 0xff;
  byte2 = (BLOCK_ALIGN >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = BITS_PER_SAMPLE & 0xff;
  byte2 = (BITS_PER_SAMPLE >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  frec.print("LIST");
  byte1 = sizeof_icmt_chunk & 0xff;
  byte2 = (sizeof_icmt_chunk >> 8) & 0xff;
  byte3 = (sizeof_icmt_chunk >> 16) & 0xff;
  byte4 = (sizeof_icmt_chunk >> 24) & 0xff;  
  frec.write(byte1);frec.write(byte2);frec.write(byte3);frec.write(byte4);
  frec.print("INFO");
  frec.print("ICMT");
  byte1 = length_icmt_comment & 0xff;
  byte2 = (length_icmt_comment >> 8) & 0xff;
  byte3 = (length_icmt_comment >> 16) & 0xff;
  byte4 = (length_icmt_comment >> 24) & 0xff;  
  frec.write(byte1);frec.write(byte2);frec.write(byte3);frec.write(byte4);
  frec.write(icmt_comment,sizeof(icmt_comment));
  frec.print("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);
  DEBUG_PRINT(("Close file")); 
  frec.close();
  DEBUG_PRINT(("Subchunk2: ")); 
  DEBUG_PRINT((Subchunk2Size)); 
}

void writeWavHeader(void)         // write out original WAV header to file
{
  frec.seek(0);
  frec.print("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.print("WAVE");
  frec.print("fmt ");
  byte1 = SUB_CHUNK_1_SIZE & 0xff;
  byte2 = (SUB_CHUNK_1_SIZE >> 8) & 0xff;
  byte3 = (SUB_CHUNK_1_SIZE >> 16) & 0xff;
  byte4 = (SUB_CHUNK_1_SIZE >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = AUDIO_FORMAT & 0xff;
  byte2 = (AUDIO_FORMAT >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = NUM_CHANNELS & 0xff;
  byte2 = (NUM_CHANNELS >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = SAMPLE_RATE & 0xff;
  byte2 = (SAMPLE_RATE >> 8) & 0xff;
  byte3 = (SAMPLE_RATE >> 16) & 0xff;
  byte4 = (SAMPLE_RATE >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = BYTE_RATE & 0xff;
  byte2 = (BYTE_RATE >> 8) & 0xff;
  byte3 = (BYTE_RATE >> 16) & 0xff;
  byte4 = (BYTE_RATE >> 24) & 0xff;  
  frec.write(byte1);  frec.write(byte2);  frec.write(byte3);  frec.write(byte4);
  byte1 = BLOCK_ALIGN & 0xff;
  byte2 = (BLOCK_ALIGN >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  byte1 = BITS_PER_SAMPLE & 0xff;
  byte2 = (BITS_PER_SAMPLE >> 8) & 0xff;
  frec.write(byte1);  frec.write(byte2); 
  frec.print("LIST");
  byte1 = sizeof_icmt_chunk & 0xff;
  byte2 = (sizeof_icmt_chunk >> 8) & 0xff;
  byte3 = (sizeof_icmt_chunk >> 16) & 0xff;
  byte4 = (sizeof_icmt_chunk >> 24) & 0xff;
  frec.write(byte1);frec.write(byte2);frec.write(byte3);frec.write(byte4);
  frec.print("INFO");
  frec.print("ICMT");
  byte1 = length_icmt_comment & 0xff;
  byte2 = (length_icmt_comment >> 8) & 0xff;
  byte3 = (length_icmt_comment >> 16) & 0xff;
  byte4 = (length_icmt_comment >> 24) & 0xff;  
  frec.write(byte1);frec.write(byte2);frec.write(byte3);frec.write(byte4);
  frec.write(icmt_comment,sizeof(icmt_comment));
  frec.print("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);
}

/* User provided date time callback function.
   See SdFile::dateTimeCallback() for usage.
*/
void dateTime(uint16_t* date, uint16_t* time)
{
  // DateTime now = rtc.now();
  // User gets date and time from GPS or real-time
  // clock in real callback function

  // return date using FAT_DATE macro to format fields
  // *date = FAT_DATE(year, month, day);
  *date = FAT_DATE(year(), month(), day());

  // return time using FAT_TIME macro to format fields
  //  *time = FAT_TIME(hours, minutes, seconds);
  *time = FAT_TIME(hour(), minute(), second());
}
//*****************************************************************************************************************/
//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;
    }
  }
}

//*****************************************************************************************************************/
void recording(void)
{
  if (!recordInProgress)
  {
    startRecording();
  }
  else if (recByteSaved < (SAMPLE_RATE * 2 * 10))
  {
    continueRecording();
  }
  else if (recordInProgress && (recByteSaved >= (SAMPLE_RATE * 2 * 10)))
  {
    stopRecording();
  }
}
 
Status
Not open for further replies.
Back
Top