Teensy 4.1 crashes during simultaneous playback and recording

junx

Member
Minimal Repro below. Note that a "test.wav" file is required on the SD card. The issue seems to stem from reading and writing to the SD card at the same time. In my case the card is a SanDisk Extreme A2.

Any ideas on how to fix this and prevent teensy from crashing?



C++:
#include <Audio.h>
#include <SD.h>
#include <SPI.h>
// Audio Recording
const int BUFFER_SIZE = 8192;  // Increased buffer size
byte buffer1[BUFFER_SIZE];
byte buffer2[BUFFER_SIZE];
byte* activeBuffer = buffer1;
byte* writeBuffer = buffer2;
int bufferIndex = 0;
bool shouldSwap = false;
AudioInputI2S audioInput;
AudioRecordQueue queue;
AudioConnection patchCord1(audioInput, 0, queue, 0);
// Audio Playback
AudioPlaySdWav playWav;
AudioOutputI2S audioOutput;
AudioConnection patchCord2(playWav, 0, audioOutput, 0);
AudioConnection patchCord3(playWav, 1, audioOutput, 1);
AudioConnection patchCord4(audioInput, 0, audioOutput, 0);
AudioControlSGTL5000 audioShield;

void setup() {
  Serial.begin(9600);
  while (!Serial) ; // Wait for Serial to be ready
  Serial.println("booted up");
  AudioMemory(120);
  Serial.println("Audio memory set");
  audioShield.enable();
  audioShield.inputSelect(AUDIO_INPUT_MIC);
  audioShield.volume(0.3);
  if (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("SD Card initialization failed!");
    return;
  }
  Serial.println("SD Card initialized");
  playWav.play("test.wav");
  Serial.println("Playback started");
  delay(2000); // a couple seconds to confirm audio playback is working
  queue.begin();  // Start the recording queue
  Serial.println("Recording queue begun");
}
void loop() {
  // Recording logic
  if (queue.available() > 0) {
    // Fetch a block of audio data
    memcpy(activeBuffer + bufferIndex, queue.readBuffer(), 256);
    bufferIndex += 256;
    if (bufferIndex >= BUFFER_SIZE) {
      bufferIndex = 0;  // Reset the buffer index
      shouldSwap = true;
    }
    queue.freeBuffer();  // Release the buffer back to the queue
    // Swap buffers and write to SD card in a non-blocking manner
    if (shouldSwap) {
      byte* temp = activeBuffer;
      activeBuffer = writeBuffer;
      writeBuffer = temp;
      shouldSwap = false;
      // Write the buffer to the SD card in a new function
      writeBufferToSD(writeBuffer);
    }
  }
}
void writeBufferToSD(byte* buffer) {
  // Non-blocking write to SD card
  File dataFile = SD.open("recording.raw", FILE_WRITE);
  if (dataFile) {
    dataFile.write(buffer, BUFFER_SIZE);
    dataFile.close();
  }
}
 
Last edited:
Use my new library objects as discussed on this thread. AudioPlaySdWav only works for extremely simple programs, and interacts poorly with SD accesses from your code because it accesses the card from the audio interrupt, and the SdFat library doesn’t bother to trap this so it just crashes. To be fair, even if it didn’t crash, there’s no way it could work…
 
Last edited:
Use my new library objects as discussed on this thread. AudioPlaySdWav only works for extremely simple programs, and interacts poorly with SD accesses from your code because it accesses the card from the audio interrupt, and the SdFat library doesn’t bother to trap this so it just crashes. To be fair, even if it didn’t crash, there’s no way it could work…
What is your new library called and where can I find it?
 
Apologies, xenForo managed to lose the link to the relevant thread - I’ve edited it in to post #2 now.

It’s not a whole new library, just a fork of the existing Audio library with some extra objects added, and the Design Tool updated to allow you to place them. The rest is unchanged, so you can install it in your /libraries sub-folder like any other third party library, and it “masks” the standard Teensyduino one - just move it elsewhere to stop using it. Google is your friend for further details on Arduino library installation…

There are a few examples, but if you need support do ask on the main thread, if the answer’s not already there, as it’ll help future users if all the info is in one place :)
 
Thanks a lot!

Got it to work! Code below for reference. Will post further questions for support in the main thread as requested.

C++:
// MUST USE CUSTOM AUDIO LIB FORK
// https://github.com/h4yn0nnym0u5e/Audio/commits/feature/buffered-SD
#include <Audio.h>

// Define audio components
AudioInputI2S microphone;      // Audio input object for the microphone
AudioPlayWAVstereo playWav;    // Audio object for playing WAV files
AudioOutputI2S audioOutput;    // Audio output object
AudioMixer4 mixer;             // Audio mixer
AudioRecordWAVmono recordWav;  // Audio recorder for WAV files

// Audio connections
AudioConnection patchCord1(microphone, 0, mixer, 0);      // Microphone to mixer channel 0
AudioConnection patchCord2(playWav, 0, mixer, 1);         // WAV player to mixer channel 1
AudioConnection patchCord3(mixer, 0, audioOutput, 0);     // Mixer to output (left channel)
AudioConnection patchCord4(mixer, 0, audioOutput, 1);     // Mixer to output (right channel)
AudioConnection patchCord5(microphone, 0, recordWav, 0);  // Mixer to output (right channel)

// Audio control
AudioControlSGTL5000 audioShield;  // Control object for the audio shield

const char* recFile = "rec131.wav";


void setup() {
  // Initialize audio memory and audio shield
  AudioMemory(60);
  audioShield.enable();
  audioShield.inputSelect(AUDIO_INPUT_MIC);
  audioShield.volume(0.5);

  // Initialize the built-in SD card
  if (!SD.begin(BUILTIN_SDCARD)) {
    // Handle error, such as by signaling with an LED or serial output
  }

  // Set mixer levels (adjust as needed)
  mixer.gain(0, 0.5);  // Set gain for microphone input
  mixer.gain(1, 0.5);  // Set gain for WAV player

  const size_t sz = 65536;
  const AudioBuffer::bufType bufMem = AudioBuffer::inHeap;
  playWav.createBuffer(sz, bufMem);
  recordWav.createBuffer(sz, bufMem);

  // playWav.play("rec131.wav", SD);  // Play a WAV file from the SD card
  playWav.play("test.wav", SD);  // Play a WAV file from the SD card
  Serial.println("Playback started");
  // delay(2000); // A couple seconds to confirm audio playback is working


  // Begin recording to a WAV file

  if (!recordWav.record(recFile)) {
    Serial.println("Failed to start recording!");
  } else {
    Serial.println("recording");
    delay(10000);
    recordWav.stop();
  }
}

void loop() {
}
 
Back
Top