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

Thread: Audio samples lost due to SD card writes

  1. #1
    Junior Member
    Join Date
    Jan 2019
    Posts
    2

    Audio samples lost due to SD card writes

    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...quency-problem

    Click image for larger version. 

Name:	SD cards.jpg 
Views:	5 
Size:	328.2 KB 
ID:	15785

    Click image for larger version. 

Name:	Screen Shot 2019-01-30 at 11.42.14 AM.jpg 
Views:	9 
Size:	73.1 KB 
ID:	15786


    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);
        
      }
      
    }

  2. #2
    Junior Member
    Join Date
    Jan 2019
    Posts
    2
    I may have found a partial solution: Replace the SD.h library with SdFs. The following code has been working well with many fewer glitches, but I have not tested extensively. I renamed the object from SD to SDFS just to avoid confusion, but it seems possible to just use SD to avoid changing code.

    Audio.h cannot be included with SdFs.h , so each of the components of the audio library must be added separately.


    Click image for larger version. 

Name:	Screen Shot 2019-01-30 at 1.54.33 PM.jpg 
Views:	5 
Size:	65.8 KB 
ID:	15787

    Code:
    #include "SdFs.h"
    SdFat SDFS;
    //#include <Audio.h>
    #include "record_queue.h"
    #include "input_i2s.h"
    #include "control_sgtl5000.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 (!(SDFS.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 (SDFS.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.
        SDFS.remove("RECORD.RAW");
        Serial.println("old audio file removed");
      }
      
      frec = SDFS.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);
        
      }
      
    }

Posting Permissions

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