Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: SD taking more time to write samples

  1. #1
    Junior Member
    Join Date
    Jul 2019
    Posts
    16

    SD taking more time to write samples

    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;
        }
      }
    }
    //*****************************************************************************************************************/

  2. #2
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,344
    Quote Originally Posted by iammb View Post
    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.

  3. #3
    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?

  4. #4
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,344
    Quote Originally Posted by JotaEfe13 View Post
    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.

  5. #5
    Junior Member
    Join Date
    Jul 2019
    Posts
    16
    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?

  6. #6
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,344
    Quote Originally Posted by iammb View Post
    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?
    more precise reference!

  7. #7
    Junior Member
    Join Date
    Jul 2019
    Posts
    16
    I read this post : https://forum.pjrc.com/threads/34327...-SdFat-Library . If sdfat is faster than sd library, how to use it with audio library?

  8. #8
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,344
    Quote Originally Posted by iammb View Post
    I read this post : https://forum.pjrc.com/threads/34327...-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

  9. #9
    Quote Originally Posted by WMXZ View Post
    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.

    Quote Originally Posted by iammb View Post
    I read this post : https://forum.pjrc.com/threads/34327...-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.

  10. #10
    Junior Member
    Join Date
    Jul 2019
    Posts
    16
    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();
      }
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •