SD.flush() does not return

Uwe

Active member
Hello!
I have written a program that takes audio samples from the Audio shield and writes them onto the build-in SD card on a Teensy 4.1.
Everything runs perfect if the executing instance is "loop()". If I let the recording&writing function to be executed by a thread ("TeensyThreads.h") I run more or less often into a situation where the SD card "flush()" does not return.
I debugged it down to
while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { } // wait for transfer to complete
from file "NXP_SDHC.cpp" which runs endlessly. Obviously waiting for the transfer complete flag which stays unset.
Is this a known issue? Does anybody made a similar experience?
Does it really have to do with threads or is this just a coincidence? (I tested it for more than 100.000 times...)

Uwe
 
Maybe someone wants to reproduce it?
Code:
#include <Audio.h>
#include <SD.h>
#include <TeensyThreads.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s2;           //xy=105,63
AudioAnalyzePeak         peak1;          //xy=278,108
AudioRecordQueue         queue1;         //xy=281,63
AudioPlaySdRaw           playRaw1;       //xy=302,157
AudioOutputI2S           i2s1;           //xy=470,120
AudioConnection          patchCord1(i2s2, 0, queue1, 0);
AudioConnection          patchCord2(i2s2, 0, peak1, 0);
AudioConnection          patchCord3(playRaw1, 0, i2s1, 0);
AudioConnection          patchCord4(playRaw1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=265,212

// The file where data is recorded
File frec;

void setup() {
  Serial.begin(9600);
  while (!Serial) ;
  
  // Audio connections require memory, and the record queue
  // uses this memory to buffer incoming audio.
  AudioMemory(60);

  // Enable the audio shield, select input, and enable output
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);
  sgtl5000_1.volume(0.5);

  if (!(SD.begin(BUILTIN_SDCARD))) {
    // stop here if no SD card, but print a message
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
}

int recCounter = 0;
int recRunning = 0;
void doRec(){
  startRecording();
  while(recCounter < 20){
    continueRecording();
  }
  stopRecording();
  recRunning = 0;
}


void loop() {
  recRunning = 1;
  //doRec(); // use this for main loop only 
  threads.addThread(doRec); // use this for thread operation
  do{
    delay(1);
  }while(recRunning);
}


int loopCounter = 0;
void startRecording() {
  Serial.print("startRecording:");
  Serial.println(loopCounter);
  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");
  }
  frec = SD.open("RECORD.RAW", FILE_WRITE);
  if (frec) {
    queue1.begin();
    loopCounter++;
  }
}

byte buffer[512];
void continueRecording() {
  if (queue1.available() >= 2) {
    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);
//    if (usec > 17000){
//      Serial.print("SD write, us=");
//      Serial.println(usec);
//    }
    recCounter++;
  }
}

void stopRecording() {
  Serial.println("stopRecording");
  queue1.end();
  while (queue1.available() > 0) {
    frec.write((byte*)queue1.readBuffer(), 256);
    queue1.freeBuffer();
  }
  frec.close();
  recCounter = 0;
}

This code is taken from Paul Stoffregens sample code for a simple play/recording. I deleted some functions (e.g. "play") that are not needed.
In the main loop you have two possibilities to start the recoding:
a) doRec();
which does the recording controlled by the main loop
or:
b) threads.addThread(doRec);
which uses Threads for it.
In both cases the same code is being executed. In case a) it is working, case b) freezes after some time. Could be some hundred, maybe some thousand runs.
 
2 questions

Can you reproduce the problem without TeensyThreads? These libraries usually aren't thread safe.

Which version of Teensyduino are you using? This matters because the old SD library was replaced by a thing wrapper for SdFat starting with version 1.54.
 
No, I can't. If I run the code from "loop" the error does not occur.

I'm using version 1.8.13 (I took this from the install path ".../arduino-1.8.13/...". Is this the version you asked for?
 
Where is this version number?

TeensyDuino Prog about screen.png
Click "Help" then "about" to find version number.
 
I looked into the version number of the Teensy loader and it displays 1.53. That is the right number, isn't it?
I decided to update to 1.55 then.
Now I have another problem: My thread version does not work at all anymore. The second time it wants to execute "queue1.available()" in procedure "continueRecording()" it does not return from there.
 
I supposed that version 1.55 needs more thread stack so I set the stack size to 30k.
Code:
  threads.addThread(doRec, 30000);
but that also does not help.
Further investigating makes me believe that "queue1.available()" freezes (does not return) when the first audio data becomes available.
Could anybody reproduce that?

Again: This freezing of "queue1.available()" does not happen in Teensyduino version 1.53 but (only?) in version 1.55!
 
I was able to get the code to run also under 1.55. I had to remove the SD operations from "startRecording()":
Code:
  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");
  }
  frec = SD.open("RECORD.RAW", FILE_WRITE);
If I move this to "loop()" the freezing of the audio unit does not happen anymore. This looks to be a problem in the combination of Audio+SD+Teensythreads in version 1.55.
If somebody could tell me where to get version 1.54 I could try to find out if this also happens in 1.54.

Now I can start to investigate if my essential problem (SD.flush() freezing) also happens in 1.55.
 
Last edited:
I wonder if that is somewhat related to the issue I have here:

https://forum.pjrc.com/threads/68868-Challenges-Integrating-Teensy4-1-Audio-SD-Card-and-LVGL-use-SDIO

Where I cannot access a file outside of the Teensy Audio library whilst a WAV is running, but can easily play multiple WAVs at the same time, or show multiple images and GIFs when a WAV is not running.

I've stripped out LVGL and have a posted a simple code that shows where a small TXT file access crashes T4.1 for me when playing a WAV file via Audio.
 
I was able to get the code to run also under 1.55. I had to remove the SD operations from "startRecording()":
Code:
  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");
  }
  frec = SD.open("RECORD.RAW", FILE_WRITE);
If I move this to "loop()" the freezing of the audio unit does not happen anymore. This looks to be a problem in the combination of Audio+SD+Teensythreads in version 1.55.
If somebody could tell me where to get version 1.54 I could try to find out if this also happens in 1.54.

Now I can start to investigate if my essential problem (SD.flush() freezing) also happens in 1.55.

If you wish for it to open at the start of the file, you can do it like you did.

Alternatively you could: frec = SD.open("RECORD.RAW", FILE_WRITE_BEGIN);
This will open an existing file and not position to the end...

There is also an example in the SD Library which shows you how you can use other options for open from the underlying SDFat library if needed.

Not sure about flush. Sounds like there is probably some place that is not thread safe...

But also not really sure what you are running as your first post mentions:
while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { } // wait for transfer to complete
from file "NXP_SDHC.cpp" which runs endlessly. Obviously waiting for the transfer complete flag which stays unset.
And I know that file is not part of Teensyduino, and I don't see the line you mention anywhere in the code.
 
And I know that file is not part of Teensyduino, and I don't see the line you mention anywhere in the code.

And I can't find this file in my 1.55 installation! I really don't know where it came from in my 1.53 installation???
But that was the file where the SD file functions ended in.(the file path was "../hardware/teensy/avr/libraries/SD/utility/"

The problem with the file function SD.open(...)is not the parameters (nevertheless thank you for pointing out).
The problem is if I call SD.open (regardless of the parameters) in a thread instead of the main "loop" than my whole program freezes when audio data become available.
The last observation I made was that the system function "delay" does not return. For me it looks like that the OS task switcher has a problem.
 
Sounds like old or random stuff...

That is if you look at the current SD library: https://github.com/PaulStoffregen/Sd
There is no utility directory...

That is from the earlier version of stuff before the newer stuff with 1.55 which uses SDFat. (Current default branch: Juse_Use_SdFat) not master.
 
Back
Top