Interrupts while recording not working (Teensy 4.1 and audio bard with Accelerometer)

Hello

I am trying to use a Accelerometer while recording audio. But I have a problem with interrupts.
First of all, there are multiple ways to check if new data is available for the Accelerometer (check te register or use DRDY PIN. Goes on hi if Data is ready. I found that using the Pin is faster then always checking the register.

I use the ADCL357 Accelerometer with I2C.
In the Setup I configure the sensor (this works without a problem).
I set up an interrupt routine so that I can read the Data:

Code:
pinMode(Data_pin, INPUT_PULLDOWN);
attachInterrupt(digitalPinToInterrupt(Data_pin), Interrupt_Data, RISING);

I have managed to read in 200us intervals (4kHz)
I also set up the SD Card (on the Teensy)
The second task is record audio. That is also no problem. I set up the audio with:
Code:
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.micGain(40);

But now the Problem. I want to use a switch/button to start and stop the recording. For this I have also set up an Interrupt:
Code:
 pinMode(Switch_pin, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(Switch_pin), Interrupt_Start_Stop, CHANGE);
This works fine for the starting. But the Interrupt gets ignored most of the times or takes ages to take affect while recording.
In the loop is only the continue Recording function (if a recording is running (active == true))
Code:
if (active == true) 
  {
    continueRecording();
  }
The continueRecording function is from the recorder sample.

But if I remove the continueRecording function than I can stop the recording.

How can it be that the Interrupt is ignored? Is the processor to slow to handle this?

The complete Code:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce2.h>

#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

// 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
// GUItool: end automatically generated code

//Define Input
const int myInput = AUDIO_INPUT_MIC;

//Define SD Card Pins
#define SDCARD_MOSI_PIN  11   
#define SDCARD_SCK_PIN   13 
#define SDCARD_CS_PIN    BUILTIN_SDCARD

//Define Input Pins
#define Switch_pin       41
#define Data_pin         32
Bounce Switch = Bounce();
Bounce Data = Bounce();

bool active = 0;
int counter = 0;

File File_audio;
File File_accelerometer;
String Dateiname_audio = "";
String Dateiname_accelerometer = "";

//https://forum.arduino.cc/t/debouncing-an-interrupt-trigger/45110/2
unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = 0;
unsigned long interrupt_delay = 200;

//Accelerometer
int adxl357 = 0x1D;

uint8_t DEVID_AD;
uint8_t REVID;
uint8_t Status;
uint8_t Range;
uint8_t POWER_CTL;

uint8_t XDATA3 = 0;
uint8_t XDATA2 = 0;
uint8_t XDATA1 = 0;

uint8_t YDATA3 = 0;
uint8_t YDATA2 = 0;
uint8_t YDATA1 = 0;

uint8_t ZDATA3 = 0;
uint8_t ZDATA2 = 0;
uint8_t ZDATA1 = 0;

long int XDATA = 0;
long int DATA = 0;
long int ZDATA = 0;

void Interrupt_Start_Stop() 
{
  //allow new Intinterrupt only after a delay (debounce)
  AudioNoInterrupts();
  noInterrupts();
  interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > interrupt_delay) 
  {
    if(active == false) //Wenn keine Aufzeichnung aktiv -> Aufzeichnung Starten
    {
      Dateiname_audio = String(counter) + ".raw";
      Dateiname_accelerometer = String(counter) + ".csv";
      while (SD.exists(Dateiname_audio.c_str()) || SD.exists(Dateiname_accelerometer.c_str())) 
      {
        Dateiname_audio = Dateiname_audio + "new";
        Dateiname_accelerometer = Dateiname_accelerometer + "new";
        Serial.println("Datei mit gleichen Namen schon vorhanden, Namen abwandeln");
        counter ++;
        Dateiname_audio = String(counter) + ".raw";
        Dateiname_accelerometer = String(counter) + ".csv";
        Serial.print("Neuer Dateinamen: ");
        Serial.print(Dateiname_accelerometer);
        Serial.print(" ; ");
        Serial.println(Dateiname_audio);
      }
      File_audio = SD.open(Dateiname_audio.c_str(), FILE_WRITE);
      if (File_audio) 
      {
        queue1.begin();
        active = true;
        Serial.print("Start: ");
        Serial.println(Dateiname_audio);
        counter++;
      }
      else
      {
        Serial.print("Error while starting audio");
      }

      File_accelerometer = SD.open(Dateiname_accelerometer.c_str(), FILE_WRITE);
      if (File_accelerometer) 
      {
        Serial.print("Start: ");
        Serial.println(Dateiname_accelerometer);
      }
      else
      {
         Serial.print("Error while starting accelerometer");
      }
    }
    else//Aufzeichung Stoppen
    {
      active = false;
      Serial.print("Stopping");
      //Audio Stop
      queue1.end();
      while (queue1.available() > 0) 
      {
        File_audio.write((byte*)queue1.readBuffer(), 256);
        queue1.freeBuffer();
      }
      File_audio.close();

      //Accelerometer Stop
      File_accelerometer.close();
      Serial.println("Stoped");
    }
  }
  last_interrupt_time = interrupt_time;
  AudioInterrupts();
  interrupts();
}

void continueRecording() 
{
   if (queue1.available() >= 2) {
    byte buffer[512];
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer+256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    File_audio.write(buffer, 512);
  }
}

void convert(long int* output, uint8_t* Data3, uint8_t* Data2, uint8_t* Data1)
{
  //-524288 bis 524287
  //Umrechnen in Dezimal (Zweierkomplement)
  *output = 0;
    *output = *Data3;
    *output <<= 8;
    *output |= *Data2;
    *output <<= 8;
    *output |= *Data1;
    *output >>= 4;

  if(bitRead(*Data3, 7) == 1) //negative Zahel
  {
    *output = *output - (2*524288);
  }
}

void Interrupt_Data()
{
    Wire2.beginTransmission(adxl357); 
    Wire2.write(0x0E); //0x08 für start bei x // 0x0E für Start bei z
    Wire2.endTransmission();
    Wire2.requestFrom(adxl357, 3);

    ZDATA3 = Wire2.read();
    ZDATA2 = Wire2.read();
    ZDATA1 = Wire2.read();
    convert(&ZDATA, &ZDATA3, &ZDATA2, &ZDATA1);

    File_accelerometer.print(micros()); //oder micros()
    File_accelerometer.print(";");
    File_accelerometer.println(ZDATA);
    ZDATA = 0;
    ZDATA3 = 0;
    ZDATA2 = 0;
    ZDATA1 = 0;
}

void setup() 
{
  //https://forum.pjrc.com/threads/57444-How-to-change-clock-speed-on-Teensy-4-0
  //https://www.youtube.com/watch?v=i_pGZm4jqBc
  set_arm_clock(816000000);
  Serial.begin(115200);
  while ( !Serial && millis() < 4000 ) ;
  Serial.print("F_CPU_ACTUAL: ");
  Serial.println(F_CPU_ACTUAL);

  Serial.println("setup");

  
  // ---- Set up Audio ----
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.micGain(40);

  // ---- Initialize the SD card ----
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(1000);
    }
  }

  // ---- Set up Accelerometer ---- 
  Wire2.begin();
  Wire2.setClock(400000); //400000
  delay(500);

  //Read  and set Range
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2C);
  Wire2.write(1); // 1 für Fast mode +-10g // 129 für High speed mode +110g // 2 für Fast mode +-20g
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  Range = Wire2.read();

  Serial.print("Range: ");
  Serial.println(Range);

  //Read DEVID_AD
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x00);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  DEVID_AD = Wire2.read();

  Serial.print("DEVID_AD: ");
  Serial.println(DEVID_AD);

  //Read REVID
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x03);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  REVID = Wire2.read();

  Serial.print("REVID: ");
  Serial.println(REVID);

  //Read and set POWER_CTL
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2D);
  Wire2.write(0); //enable measurement mode
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  POWER_CTL = Wire2.read();

  Serial.print("POWER_CTL: ");
  Serial.println(POWER_CTL);

  // ---- Set Interrupt for Data ready (Accelerometer) ----
  pinMode(Data_pin, INPUT_PULLDOWN);
  attachInterrupt(digitalPinToInterrupt(Data_pin), Interrupt_Data, RISING);

  // ---- Set Interrupt for Start/Stop Recording ----
  pinMode(Switch_pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(Switch_pin), Interrupt_Start_Stop, CHANGE);
}

void loop() 
{

  if (active == true) 
  {
    continueRecording();
  }
}

I have also tired using the Bounce(2) libary without luck

Edit: when I add Serial.println(digitalRead(Switch_pin)); to the loop.
From the moment the recording is started, a change at the input is only detected with an extreme delay. It is even so that nothing more or is output. It seems as if he would no longer run through the loop.
 
Last edited:
I have found now I way to register the switch. It is a bit ugly but I can’t find anything better.
But the problem is only occurring when I want to read data from the sensor and record at the same time.
Each of them alone works perfectly. The following code manages to do both but far from good. The problem lies with the timing of the sensor signal. Without recording I get very consistent timing of around 250us

1.png
But when I record at the same time the timing is way off. I get timings from (allegedly) 81us to 27000 us. With this bad of a timing a analysis is impossible.
2.png

I also made A test without using interrupts. This works better but is still not perfekt. The timing also has here some spikes.
3.png

Is there a way to fix this problem? Or anythink that I can try?

Thanks a lot

The code:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce2.h>

#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

// 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
// GUItool: end automatically generated code

//Define Input
const int myInput = AUDIO_INPUT_MIC;

//Define SD Card Pins
#define SDCARD_MOSI_PIN  11   
#define SDCARD_SCK_PIN   13 
#define SDCARD_CS_PIN    BUILTIN_SDCARD

//Define Input Pins
#define Switch_pin       41
#define Data_pin         32
Bounce Switch = Bounce();
Bounce Data = Bounce();

bool active = 0;
int counter = 0;

File File_audio;
File File_accelerometer;
String Dateiname_audio = "";
String Dateiname_accelerometer = "";

//https://forum.arduino.cc/t/debouncing-an-interrupt-trigger/45110/2
unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = 0;
unsigned long interrupt_delay = 2000;

unsigned long Sensor_time = 0;
unsigned long Sensor_last_time = 0;
unsigned long Sensor_delay = 4000;

//Accelerometer
int adxl357 = 0x1D;

uint8_t DEVID_AD;
uint8_t REVID;
uint8_t Status;
uint8_t Range;
uint8_t POWER_CTL;

uint8_t XDATA3 = 0;
uint8_t XDATA2 = 0;
uint8_t XDATA1 = 0;

uint8_t YDATA3 = 0;
uint8_t YDATA2 = 0;
uint8_t YDATA1 = 0;

uint8_t ZDATA3 = 0;
uint8_t ZDATA2 = 0;
uint8_t ZDATA1 = 0;

long int XDATA = 0;
long int DATA = 0;
long int ZDATA = 0;

void Interrupt_Start() 
{
  interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > interrupt_delay) 
  {
    active = true;
    //Dateinamen betstimmen
    Dateiname_accelerometer = String(counter) + ".csv";
    Dateiname_audio = String(counter) + ".raw";
    while (SD.exists(Dateiname_accelerometer.c_str()) || SD.exists(Dateiname_audio.c_str()))
    {
      Serial.println("Datei mit gleichen Namen schon vorhanden, Namen abwandeln");
      counter ++;
      Dateiname_accelerometer = String(counter) + ".csv";
      Dateiname_audio = String(counter) + ".raw";
      Serial.print("Neuer Dateinamen: ");
      Serial.print(Dateiname_accelerometer);
      Serial.print(" , ");
      Serial.println(Dateiname_audio);
    }
  
    //Accelerometer File öffnen
    File_accelerometer = SD.open(Dateiname_accelerometer.c_str(), FILE_WRITE);
    if (File_accelerometer) 
    {
      Serial.print("Start: ");
      Serial.println(Dateiname_accelerometer);
    }
    else
    {
      Serial.print("Error while starting accelerometer");
    }

     //Audio File öffnen
    File_audio = SD.open(Dateiname_audio.c_str(), FILE_WRITE);
    if (File_audio) 
    {
      queue1.begin();
      Serial.print("Start: ");
      Serial.println(Dateiname_audio);
      counter++;
    }
    else
    {
      Serial.print("Error while starting audio");
    }
  }
  last_interrupt_time = interrupt_time;
}
void Interrupt_Stop() 
{
  interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > interrupt_delay) 
  {
    active = false;
    Serial.print("Stopping");

    //Accelerometer Stop
    File_accelerometer.close();

    //Audio Stop
    queue1.end();
    while (queue1.available() > 0) 
    {
      File_audio.write((byte*)queue1.readBuffer(), 256);
      queue1.freeBuffer();
    }
    File_audio.close();

    Serial.println("Stoped");
  }
  last_interrupt_time = interrupt_time;
}

void convert(long int* output, uint8_t* Data3, uint8_t* Data2, uint8_t* Data1)
{
  //-524288 bis 524287
  //Umrechnen in Dezimal (Zweierkomplement)
  *output = 0;
    *output = *Data3;
    *output <<= 8;
    *output |= *Data2;
    *output <<= 8;
    *output |= *Data1;
    *output >>= 4;

  if(bitRead(*Data3, 7) == 1) //negative Zahel
  {
    //https://studyflix.de/informatik/zweierkomplement-1781
    
    //Methode 1
    /**output = ~*output;
    *output = *output + 1;
    for(int i = 31; i >= 20; i--)
    {
      bitClear(*output, i);
    }
    *output = *output * -1;*/

    //Methode 2
    *output = *output - (2*524288);
  }
}

void continueRecording() 
{
   if (queue1.available() >= 2) {
    byte buffer[512];
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer+256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    File_audio.write(buffer, 512);
  }
}

void Interrupt_Data()
{
  Switch.update();

  if (Switch.fell())
  {
    Interrupt_Start();
  }
  else if(Switch.rose())
  {
    Interrupt_Stop();
  }

  if(active == true)
  {
    continueRecording();

    Wire2.beginTransmission(adxl357); 
    Wire2.write(0x0E); //0x08 für start bei x // 0x0E für Start bei z
    Wire2.endTransmission();
    Wire2.requestFrom(adxl357, 3);

    ZDATA3 = Wire2.read();
    ZDATA2 = Wire2.read();
    ZDATA1 = Wire2.read();
    convert(&ZDATA, &ZDATA3, &ZDATA2, &ZDATA1);

    File_accelerometer.print(micros()); //oder micros()
    File_accelerometer.print(";");
    File_accelerometer.println(ZDATA);
    ZDATA = 0;
    ZDATA3 = 0;
    ZDATA2 = 0;
    ZDATA1 = 0;
  }
  //interrupts();
}

void setup() 
{
  //https://forum.pjrc.com/threads/57444-How-to-change-clock-speed-on-Teensy-4-0
  //https://www.youtube.com/watch?v=i_pGZm4jqBc
  set_arm_clock(816000000);
  Serial.begin(115200);
  while ( !Serial && millis() < 4000 ) ;
  Serial.print("F_CPU_ACTUAL: ");
  Serial.println(F_CPU_ACTUAL);

  Serial.println("setup");

  // ---- Initialize the SD card ----
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(1000);
    }
  }

  // ---- Set up Audio ----
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.micGain(40);

  // ---- Set up Accelerometer ---- 
  Wire2.begin();
  Wire2.setClock(1000000); //400000 für Fast Mode //1000000 für High Speed Mode
  delay(500);

  //Read  and set Range
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2C);
  Wire2.write(129); // 1 für Fast mode +-10g // 129 für High speed mode +110g // 2 für Fast mode +-20g
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  Range = Wire2.read();

  Serial.print("Range: ");
  Serial.println(Range);

  //Read DEVID_AD
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x00);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  DEVID_AD = Wire2.read();

  Serial.print("DEVID_AD: ");
  Serial.println(DEVID_AD);

  //Read REVID
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x03);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  REVID = Wire2.read();

  Serial.print("REVID: ");
  Serial.println(REVID);

  //Read and set POWER_CTL
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2D);
  Wire2.write(0); //enable measurement mode
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  POWER_CTL = Wire2.read();

  Serial.print("POWER_CTL: ");
  Serial.println(POWER_CTL);

  // ---- Set Interrupt for Data ready (Accelerometer) ----
  pinMode(Data_pin, INPUT_PULLDOWN);
  attachInterrupt(digitalPinToInterrupt(Data_pin), Interrupt_Data, RISING);

  // ---- Set Interrupt for Start/Stop Recording ----
  //https://github.com/thomasfredericks/Bounce2
  Switch.attach(Switch_pin, INPUT_PULLUP);
  Switch.interval(25);
  pinMode(Switch_pin, INPUT_PULLUP);
  //attachInterrupt(digitalPinToInterrupt(Switch_pin), Interrupt_Start_Stop, CHANGE);
}

void loop() 
{
}
without Interrupts:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce2.h>

#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

// 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
// GUItool: end automatically generated code

//Define Input
const int myInput = AUDIO_INPUT_MIC;

//Define SD Card Pins
#define SDCARD_MOSI_PIN  11   
#define SDCARD_SCK_PIN   13 
#define SDCARD_CS_PIN    BUILTIN_SDCARD

//Define Input Pins
#define Switch_pin       41
#define Data_pin         32
Bounce Switch = Bounce();
Bounce Data = Bounce();

bool active = 0;
int counter = 0;

File File_audio;
File File_accelerometer;
String Dateiname_audio = "";
String Dateiname_accelerometer = "";

//https://forum.arduino.cc/t/debouncing-an-interrupt-trigger/45110/2
unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = 0;
unsigned long interrupt_delay = 2000;

unsigned long Sensor_time = 0;
unsigned long Sensor_last_time = 0;
unsigned long Sensor_delay = 4000;

//Accelerometer
int adxl357 = 0x1D;

uint8_t DEVID_AD;
uint8_t REVID;
uint8_t Status;
uint8_t Range;
uint8_t POWER_CTL;

uint8_t XDATA3 = 0;
uint8_t XDATA2 = 0;
uint8_t XDATA1 = 0;

uint8_t YDATA3 = 0;
uint8_t YDATA2 = 0;
uint8_t YDATA1 = 0;

uint8_t ZDATA3 = 0;
uint8_t ZDATA2 = 0;
uint8_t ZDATA1 = 0;

long int XDATA = 0;
long int DATA = 0;
long int ZDATA = 0;

void Interrupt_Start() 
{
  interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > interrupt_delay) 
  {
    active = true;
    //Dateinamen betstimmen
    Dateiname_accelerometer = String(counter) + ".csv";
    Dateiname_audio = String(counter) + ".raw";
    while (SD.exists(Dateiname_accelerometer.c_str()) || SD.exists(Dateiname_audio.c_str()))
    {
      Serial.println("Datei mit gleichen Namen schon vorhanden, Namen abwandeln");
      counter ++;
      Dateiname_accelerometer = String(counter) + ".csv";
      Dateiname_audio = String(counter) + ".raw";
      Serial.print("Neuer Dateinamen: ");
      Serial.print(Dateiname_accelerometer);
      Serial.print(" , ");
      Serial.println(Dateiname_audio);
    }
  
    //Accelerometer File öffnen
    File_accelerometer = SD.open(Dateiname_accelerometer.c_str(), FILE_WRITE);
    if (File_accelerometer) 
    {
      Serial.print("Start: ");
      Serial.println(Dateiname_accelerometer);
    }
    else
    {
      Serial.print("Error while starting accelerometer");
    }

     //Audio File öffnen
    File_audio = SD.open(Dateiname_audio.c_str(), FILE_WRITE);
    if (File_audio) 
    {
      queue1.begin();
      Serial.print("Start: ");
      Serial.println(Dateiname_audio);
      counter++;
    }
    else
    {
      Serial.print("Error while starting audio");
    }
  }
  last_interrupt_time = interrupt_time;
}
void Interrupt_Stop() 
{
  interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > interrupt_delay) 
  {
    active = false;
    Serial.print("Stopping");

    //Accelerometer Stop
    File_accelerometer.close();

    //Audio Stop
    queue1.end();
    while (queue1.available() > 0) 
    {
      File_audio.write((byte*)queue1.readBuffer(), 256);
      queue1.freeBuffer();
    }
    File_audio.close();

    Serial.println("Stoped");
  }
  last_interrupt_time = interrupt_time;
}

void convert(long int* output, uint8_t* Data3, uint8_t* Data2, uint8_t* Data1)
{
  //-524288 bis 524287
  //Umrechnen in Dezimal (Zweierkomplement)
  *output = 0;
    *output = *Data3;
    *output <<= 8;
    *output |= *Data2;
    *output <<= 8;
    *output |= *Data1;
    *output >>= 4;

  if(bitRead(*Data3, 7) == 1) //negative Zahel
  {
    //https://studyflix.de/informatik/zweierkomplement-1781
    
    //Methode 1
    /**output = ~*output;
    *output = *output + 1;
    for(int i = 31; i >= 20; i--)
    {
      bitClear(*output, i);
    }
    *output = *output * -1;*/

    //Methode 2
    *output = *output - (2*524288);
  }
}

void continueRecording() 
{
   if (queue1.available() >= 2) {
    byte buffer[512];
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer+256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    File_audio.write(buffer, 512);
  }
}

void Interrupt_Data()
{
  Wire2.beginTransmission(adxl357); 
  Wire2.write(0x0E); //0x08 für start bei x // 0x0E für Start bei z
  Wire2.endTransmission();
  Wire2.requestFrom(adxl357, 3);

  ZDATA3 = Wire2.read();
  ZDATA2 = Wire2.read();
  ZDATA1 = Wire2.read();
  convert(&ZDATA, &ZDATA3, &ZDATA2, &ZDATA1);

  File_accelerometer.print(micros());
  File_accelerometer.print(";");
  File_accelerometer.println(ZDATA);
  ZDATA = 0;
}

void setup() 
{
  //https://forum.pjrc.com/threads/57444-How-to-change-clock-speed-on-Teensy-4-0
  //https://www.youtube.com/watch?v=i_pGZm4jqBc
  set_arm_clock(816000000);
  Serial.begin(115200);
  while ( !Serial && millis() < 4000 ) ;
  Serial.print("F_CPU_ACTUAL: ");
  Serial.println(F_CPU_ACTUAL);

  Serial.println("setup");

  // ---- Initialize the SD card ----
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(1000);
    }
  }

  // ---- Set up Audio ----
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.micGain(40);

  // ---- Set up Accelerometer ---- 
  Wire2.begin();
  Wire2.setClock(1000000); //400000 für Fast Mode //1000000 für High Speed Mode
  delay(500);

  //Read  and set Range
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2C);
  Wire2.write(129); // 1 für Fast mode +-10g // 129 für High speed mode +110g // 2 für Fast mode +-20g
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  Range = Wire2.read();

  Serial.print("Range: ");
  Serial.println(Range);

  //Read DEVID_AD
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x00);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  DEVID_AD = Wire2.read();

  Serial.print("DEVID_AD: ");
  Serial.println(DEVID_AD);

  //Read REVID
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x03);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  REVID = Wire2.read();

  Serial.print("REVID: ");
  Serial.println(REVID);

  //Read and set POWER_CTL
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2D);
  Wire2.write(0); //enable measurement mode
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  POWER_CTL = Wire2.read();

  Serial.print("POWER_CTL: ");
  Serial.println(POWER_CTL);

  // ---- Set Interrupt for Data ready (Accelerometer) ----
  pinMode(Data_pin, INPUT_PULLDOWN);
  //attachInterrupt(digitalPinToInterrupt(Data_pin), Interrupt_Data, RISING);

  // ---- Set Interrupt for Start/Stop Recording ----
  //https://github.com/thomasfredericks/Bounce2
  Switch.attach(Switch_pin, INPUT_PULLUP);
  Switch.interval(25);
  pinMode(Switch_pin, INPUT_PULLUP);
  //attachInterrupt(digitalPinToInterrupt(Switch_pin), Interrupt_Start_Stop, CHANGE);
}

void loop() 
{
  Switch.update();

  if (Switch.fell())
  {
    Interrupt_Start();
  }
  else if(Switch.rose())
  {
    Interrupt_Stop();
  }

  if(active == true)
  {
    if(digitalRead(Data_pin))
    {
      Interrupt_Data();
    }
    continueRecording();
  }

}
 
Quick glance shows that small SD writes are done in _ISR:
Code:
void Interrupt_Data()
{
// ...
    File_accelerometer.print(micros()); //oder micros()
    File_accelerometer.print(";");
    File_accelerometer.println(ZDATA)

Perhaps the data could be put in a RAM buffer in the _ISR and then written from the buffer in loop()
 
Thanks for the sugestions

I will try to use a buffer.

What I find interesting is that everything is working without delays when I am not recording? Maye with the Recording it is to much for the SD Card to handle? I will try it.
 
I have changed the code so that I use both SD Cards. But with also no luck.
I have not jet figured out how to use a buffer. For what I have read the new SD.h already uses sdfs, and this one is already using a buffer. If someone has some hints that would be helpful.
Here my code:

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce2.h>

#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

// 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
// GUItool: end automatically generated code

//Define Input
const int myInput = AUDIO_INPUT_MIC;

//Define SD Card Pins
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 11
#define SDCARD_SCK_PIN 13

//Define Input Pins
#define Switch_pin       41
#define Data_pin         32
Bounce Switch = Bounce();
Bounce Data = Bounce();

bool active = 0;
int counter = 0;

File File_audio;
File File_accelerometer;
String Dateiname_audio = "";
String Dateiname_accelerometer = "";

SDClass sd1;
SDClass sd2;

//https://forum.arduino.cc/t/debouncing-an-interrupt-trigger/45110/2
unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = 0;
unsigned long interrupt_delay = 2000;

unsigned long Sensor_time = 0;
unsigned long Sensor_last_time = 0;
unsigned long Sensor_delay = 4000;
String Data_to_write = "";

//Accelerometer
int adxl357 = 0x1D;

uint8_t DEVID_AD;
uint8_t REVID;
uint8_t Status;
uint8_t Range;
uint8_t POWER_CTL;

uint8_t XDATA3 = 0;
uint8_t XDATA2 = 0;
uint8_t XDATA1 = 0;

uint8_t YDATA3 = 0;
uint8_t YDATA2 = 0;
uint8_t YDATA1 = 0;

uint8_t ZDATA3 = 0;
uint8_t ZDATA2 = 0;
uint8_t ZDATA1 = 0;

long int XDATA = 0;
long int DATA = 0;
long int ZDATA = 0;

bool ok;

void Interrupt_Start() 
{
  interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > interrupt_delay) 
  {
    active = true;
    //Dateinamen betstimmen
    Dateiname_accelerometer = String(counter) + ".csv";
    Dateiname_audio = String(counter) + ".raw";
    while (sd1.exists(Dateiname_accelerometer.c_str()) || sd2.exists(Dateiname_audio.c_str()))
    {
      Serial.println("Datei mit gleichen Namen schon vorhanden, Namen abwandeln");
      counter ++;
      Dateiname_accelerometer = String(counter) + ".csv";
      Dateiname_audio = String(counter) + ".raw";
      Serial.print("Neuer Dateinamen: ");
      Serial.print(Dateiname_accelerometer);
      Serial.print(" , ");
      Serial.println(Dateiname_audio);
    }
  
    //Accelerometer File öffnen
    File_accelerometer = sd1.open(Dateiname_accelerometer.c_str(), FILE_WRITE);
    if (File_accelerometer) 
    {
      Serial.print("Start: ");
      Serial.println(Dateiname_accelerometer);
    }
    else
    {
      Serial.print("Error while starting accelerometer");
    }

     //Audio File öffnen
    File_audio = sd2.open(Dateiname_audio.c_str(), FILE_WRITE);
    if (File_audio) 
    {
      queue1.begin();
      Serial.print("Start: ");
      Serial.println(Dateiname_audio);
      counter++;
    }
    else
    {
      Serial.print("Error while starting audio");
    }
  }
  last_interrupt_time = interrupt_time;
}
void Interrupt_Stop() 
{
  interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > interrupt_delay) 
  {
    active = false;
    Serial.print("Stopping");

    //Accelerometer Stop
    File_accelerometer.close();

    //Audio Stop
    queue1.end();
    while (queue1.available() > 0) 
    {
      File_audio.write((byte*)queue1.readBuffer(), 256);
      queue1.freeBuffer();
    }
    File_audio.close();

    Serial.println("Stoped");
  }
  last_interrupt_time = interrupt_time;
}

void convert(long int* output, uint8_t* Data3, uint8_t* Data2, uint8_t* Data1)
{
  //-524288 bis 524287
  //Umrechnen in Dezimal (Zweierkomplement)
  *output = 0;
    *output = *Data3;
    *output <<= 8;
    *output |= *Data2;
    *output <<= 8;
    *output |= *Data1;
    *output >>= 4;

  if(bitRead(*Data3, 7) == 1) //negative Zahel
  {
    //https://studyflix.de/informatik/zweierkomplement-1781
    
    //Methode 1
    /**output = ~*output;
    *output = *output + 1;
    for(int i = 31; i >= 20; i--)
    {
      bitClear(*output, i);
    }
    *output = *output * -1;*/

    //Methode 2
    *output = *output - (2*524288);
  }
}

void continueRecording() 
{
   if (queue1.available() >= 2) {
    byte buffer[512];
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer+256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    File_audio.write(buffer, 512);
  }
}

void Interrupt_Data()
{
  Wire2.beginTransmission(adxl357); 
  Wire2.write(0x0E); //0x08 für start bei x // 0x0E für Start bei z
  Wire2.endTransmission();
  Wire2.requestFrom(adxl357, 3);

  ZDATA3 = Wire2.read();
  ZDATA2 = Wire2.read();
  ZDATA1 = Wire2.read();
  convert(&ZDATA, &ZDATA3, &ZDATA2, &ZDATA1);

  Data_to_write = String(micros()) + ";" + String(ZDATA);
  /*File_accelerometer.print(micros());
  File_accelerometer.print(";");
  File_accelerometer.println(ZDATA);*/
  File_accelerometer.println(Data_to_write);
  ZDATA = 0;
}

void setup() 
{
  //https://forum.pjrc.com/threads/57444-How-to-change-clock-speed-on-Teensy-4-0
  //https://www.youtube.com/watch?v=i_pGZm4jqBc
  //set_arm_clock(816000000);
  Serial.begin(115200);
  while ( !Serial && millis() < 4000 ) ;
  Serial.print("F_CPU_ACTUAL: ");
  Serial.println(F_CPU_ACTUAL);

  Serial.println("setup");

  // ---- Initialize the internal SD card ----
  //https://forum.pjrc.com/threads/71716-recording-playing-back-audio-on-multiple-SD-cards?p=317860#post317860
  if (!sd1.sdfs.begin(SdioConfig(FIFO_SDIO))) {
    Serial.println("error sd1.begin");
  }

   if (!sd2.sdfs.begin(SdSpiConfig(SDCARD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16)))) {
    Serial.println("error sd2.begin");
  }

  //Nodes:
  //SdFat_Usage Example

  //https://forum.pjrc.com/threads/71467-ADS1299-SPI-with-Teensy-4-1-and-SD-card
  //sync()

  //https://forum.pjrc.com/threads/69460-Builtin-Sd-Card-Teensy-4-1-SD-begin()-errors
  //SD.mediaPresent()

  // ---- Set up Audio ----
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.micGain(40);

  // ---- Set up Accelerometer ---- 
  Wire2.begin();
  Wire2.setClock(1000000); //400000 für Fast Mode //1000000 für High Speed Mode
  delay(500);

  //Read  and set Range
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2C);
  Wire2.write(129); // 1 für Fast mode +-10g // 129 für High speed mode +110g // 2 für Fast mode +-20g
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  Range = Wire2.read();

  Serial.print("Range: ");
  Serial.println(Range);

  //Read DEVID_AD
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x00);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  DEVID_AD = Wire2.read();

  Serial.print("DEVID_AD: ");
  Serial.println(DEVID_AD);

  //Read REVID
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x03);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  REVID = Wire2.read();

  Serial.print("REVID: ");
  Serial.println(REVID);

  //Read and set POWER_CTL
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2D);
  Wire2.write(0); //enable measurement mode
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  POWER_CTL = Wire2.read();

  Serial.print("POWER_CTL: ");
  Serial.println(POWER_CTL);

  // ---- Set Interrupt for Data ready (Accelerometer) ----
  pinMode(Data_pin, INPUT_PULLDOWN);
  //attachInterrupt(digitalPinToInterrupt(Data_pin), Interrupt_Data, RISING);

  // ---- Set Interrupt for Start/Stop Recording ----
  //https://github.com/thomasfredericks/Bounce2
  Switch.attach(Switch_pin, INPUT_PULLUP);
  Switch.interval(25);
  pinMode(Switch_pin, INPUT_PULLUP);
  //attachInterrupt(digitalPinToInterrupt(Switch_pin), Interrupt_Start_Stop, CHANGE);
}

void loop() 
{
  Switch.update();

  if (Switch.fell())
  {
    Interrupt_Start();
  }
  else if(Switch.rose())
  {
    Interrupt_Stop();
  }

  if(active == true)
  {
    if(digitalRead(Data_pin))
    {
      Interrupt_Data();
    }
    continueRecording();
  }

}
 
SD cards are not consistent in fast write and return times - low end is fast - but when the card gets data it may need to do housekeeping that can take over 100 ms.

An interrupt safe set of 'ping pong' buffers or suitable use of a circular buffer can allow the ISR to buffer the data in large enough quantity to allow loop to empty on save to SD card and return to use by the _ISR before needed.

Not sure there is an exact example made or posted on the forum covering this use case, but that seems to be the proper direction.

There are posts on all the elements: SD buffer in 512B groups of 4K - and data buffering to allow for that.

Others may chime in ... gotta run ...
 
Writing with a buffer is not so easy. I was not really able to find any good solutions, I have to dig deeper. What I have read is that SdFat manages it own buffer, therefore I am not sure what adding another world benefit.

What I should mention is that I would need to record for multiple hours or even days at a time.

But I have done some test. Writing only one file at a time, I can write without a problem every 2-4us. But when I try to write two file simultaneously (on two sd cards) I get those timing spikes. Therefore, it seems to be only a problem when I want two write two files at the same time.
 
Buffering from an _ISR() is not trivial - when there is another non _ISR() like loop() emptying the buffer.
This post by @PaulStoffregen points to one solution and the issues. That uses a circular buffer where the _ISR inserts new data and the loop() code could remove oldest data when sent to SD card.

The SD code will buffer as needed to perform a write in some fashion as the block write on SD is 512 bytes AFAIK.

But as noted, and in other threads, the SD card has a processor that has to manage the writes that can on regular basis take 100+ ms as it does house keeping.

Not sure how the use of two SD cards affects the low level code - assuming one is BUILTIN SDIO and the other standard SPI access, if they share common buffers or independent.
 
Thanks @defragster I have found and used this example.

I have now implemented the buffer. But sadly this does not make a difference.
Still when recording the timing is all over the place. (When I am not recording the minings are way better)
Example where it schould be ervery 1000us:
Bild1.jpg

What I find strange is that even set to only record with 250Hz (4000us) I get this behavior (not so bad but still)

Bild2.jpg

I suspect that it has something to with the implementation of the audio library. That somehow this is interrupting the normal programm.

I have another idea: I will try to use a usb stick instead of a sd card. I hope that with a good usb stick the writing will be better. But I don’t know.

My Code:
Code:
#include "SdFat.h"
#include "RingBuf.h"
#include <Wire.h>
#include <Bounce2.h>
#include <Audio.h>

// Use Teensy SDIO
#define SD_CONFIG  SdioConfig(FIFO_SDIO)

//Define (Parameters) of Buffer and SD File
#define LOG_INTERVAL_USEC 1000  // Interval between measuremts for 1 ksps.
#define LOG_FILE_SIZE 10*25000*600  // 150,000,000 bytes.
#define RING_BUF_CAPACITY 400*512

#define LOG_FILENAME "SdioLogger.csv"

unsigned long last_data_time = 0;
unsigned long data_time = 0;

SdFs sd;
FsFile file_accel;
FsFile file_audio;

// RingBuf for File type FsFile.
RingBuf<FsFile, RING_BUF_CAPACITY> rb;

//Define Input Pins
#define Switch_pin       41
#define Data_pin         32
Bounce Switch = Bounce();
Bounce Data = Bounce();

//Variables for Accelerometer
int adxl357 = 0x1D;

uint8_t DEVID_AD;
uint8_t REVID;
uint8_t Status;
uint8_t Range;
uint8_t POWER_CTL;

uint8_t XDATA3 = 0;
uint8_t XDATA2 = 0;
uint8_t XDATA1 = 0;

uint8_t YDATA3 = 0;
uint8_t YDATA2 = 0;
uint8_t YDATA1 = 0;

uint8_t ZDATA3 = 0;
uint8_t ZDATA2 = 0;
uint8_t ZDATA1 = 0;

long int XDATA = 0;
long int YDATA = 0;
long int ZDATA = 0;

//Define System Variables
size_t n = 0;
int counter = 0;
size_t maxUsed = 0;
bool active = false;
String Data_to_write = "";
String Dateiname_audio = "";
String Dateiname_accelerometer = "";

//Define Variables for Audio

// 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
// GUItool: end automatically generated code

//Define Input
const int myInput = AUDIO_INPUT_MIC;

void logData() 
{
  //Check if file is full
  n = rb.bytesUsed();
  if ((n + file_accel.curPosition()) > (LOG_FILE_SIZE - 20)) 
  {
    Serial.println("File full - quitting.");
    active = false;
    return;
  }
  else
  {
    //Log Number of bytes in Ringbuffer
    if (n > maxUsed) 
    {
      maxUsed = n;
    }

    //If Ringbuffer is > 512 and File is not Bussy write Data to file
    if (n >= 512 && !file_accel.isBusy()) 
    {
      if (512 != rb.writeOut(512)) 
      {
        Serial.println("writeOut failed");
        active = false;
        return;
      }
    }
  }

  //Get new Data if Data is avalible and time is up
  data_time = micros();
  if(digitalRead(Data_pin) && (data_time - last_data_time >= LOG_INTERVAL_USEC) )
  {
    getData();
    rb.println(Data_to_write);
    last_data_time = data_time;

    if (rb.getWriteError()) 
    {
      // Error caused by too few free bytes in RingBuf.
      active = false;
      return;
    }
  }
}

void getData()
{
  Wire2.beginTransmission(adxl357); 
  Wire2.write(0x08); //0x08 für start bei x // 0x0E für Start bei z
  Wire2.endTransmission();
  Wire2.requestFrom(adxl357, 9);

  XDATA3 = Wire2.read();
  XDATA2 = Wire2.read();
  XDATA1 = Wire2.read();
  
  YDATA3 = Wire2.read();
  YDATA2 = Wire2.read();
  YDATA1 = Wire2.read();
  
  ZDATA3 = Wire2.read();
  ZDATA2 = Wire2.read();
  ZDATA1 = Wire2.read();

  convert(&XDATA, &XDATA3, &XDATA2, &XDATA1);
  convert(&YDATA, &YDATA3, &YDATA2, &YDATA1);
  convert(&ZDATA, &ZDATA3, &ZDATA2, &ZDATA1);

  Data_to_write = String(micros()) + ";" + String(XDATA) + ";" + String(YDATA) + ";" + String(ZDATA);
}

void convert(long int* output, uint8_t* Data3, uint8_t* Data2, uint8_t* Data1)
{
  //-524288 bis 524287
  //Umrechnen in Dezimal (Zweierkomplement)
  *output = 0;
    *output = *Data3;
    *output <<= 8;
    *output |= *Data2;
    *output <<= 8;
    *output |= *Data1;
    *output >>= 4;

  if(bitRead(*Data3, 7) == 1) //negative Zahel
  {
    *output = *output - (2*524288);
  }
}

void Interrupt_Start()
{
  Serial.println("Starting");
  //---- INIT SD Card and Create File ----
  // Init SD Card
  if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial);
  }

  //Check for File Name
  Dateiname_accelerometer = String(counter) + ".csv";
  Dateiname_audio = String(counter) + ".raw";
  while (sd.exists(Dateiname_accelerometer.c_str()) || sd.exists(Dateiname_audio.c_str()))
  {
    Serial.println("Datei mit gleichen Namen schon vorhanden, Namen abwandeln");
    counter ++;
    Dateiname_accelerometer = String(counter) + ".csv";
    Dateiname_audio = String(counter) + ".raw";
    Serial.print("Neuer Dateinamen: ");
    Serial.print(Dateiname_accelerometer);
    Serial.print(" , ");
    Serial.println(Dateiname_audio);
  }

  //Create file
  if (!file_accel.open(Dateiname_accelerometer.c_str(), O_RDWR | O_CREAT | O_TRUNC)) 
  {
    Serial.print("Failed to open: ");
    Serial.println(Dateiname_accelerometer);
    return;
  }
  else
  {
    Serial.print("Start: ");
    Serial.println(Dateiname_accelerometer);
  }

  if (!file_audio.open(Dateiname_audio.c_str(), O_RDWR | O_CREAT | O_TRUNC)) 
  {
    Serial.print("Failed to open: ");
    Serial.println(Dateiname_audio);
    return;
  }
  else
  {
    queue1.begin();
    Serial.print("Start: ");
    Serial.println(Dateiname_audio);
  }

  // File must be pre-allocated to avoid huge
  // delays searching for free clusters.
  if (!file_accel.preAllocate(LOG_FILE_SIZE)) {
     Serial.println("preAllocate failed\n");
     file_accel.close();
     return;
  }

  // initialize the RingBuf.
  rb.begin(&file_accel);
  maxUsed = 0;

  active = true;
  counter++;

  Serial.println("Recording");

}

void Interrupt_Stop()
{
  Serial.println("Stop");
  active = false;

  //Accelerometer Stop
  rb.sync();
  file_accel.truncate();
  file_accel.rewind();

  Serial.print("fileSize: ");
  Serial.println((uint32_t)file_accel.fileSize());
  Serial.print("maxBytesUsed: ");
  Serial.println(maxUsed);
  file_accel.close();

  //Audio Stop
  queue1.end();
  while (queue1.available() > 0) 
  {
    file_audio.write((byte*)queue1.readBuffer(), 256);
    queue1.freeBuffer();
  }
  file_audio.close();
}

void continueRecording() 
{
   if (queue1.available() >= 2) {
    byte buffer[512];
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer+256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    file_audio.write(buffer, 512);
  }
}

void setup()
{
  // ---- Set up Serial ----
  Serial.begin(9600);
  while (!Serial) {}

  Serial.println("setup");

  // ---- Set up Accelerometer ---- 
  Wire2.begin();
  Wire2.setClock(1000000); //400000 für Fast Mode //1000000 für High Speed Mode
  delay(500);

  //Read  and set Range
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2C);
  Wire2.write(129); // 1 für Fast mode +-10g // 129 für High speed mode +110g // 2 für Fast mode +-20g
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  Range = Wire2.read();

  Serial.print("Range: ");
  Serial.println(Range);

  //Read DEVID_AD
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x00);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  DEVID_AD = Wire2.read();

  Serial.print("DEVID_AD: ");
  Serial.println(DEVID_AD);

  //Read REVID
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x03);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  REVID = Wire2.read();

  Serial.print("REVID: ");
  Serial.println(REVID);

  //Read and set POWER_CTL
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2D);
  Wire2.write(0); //enable measurement mode
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  POWER_CTL = Wire2.read();

  Serial.print("POWER_CTL: ");
  Serial.println(POWER_CTL);

  // ---- Set up Audio ----
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.micGain(40);

  // ---- Set Interrupt for Data ready (Accelerometer) ----
  pinMode(Data_pin, INPUT_PULLDOWN);
  //attachInterrupt(digitalPinToInterrupt(Data_pin), Interrupt_Data, RISING);

  // ---- Set Interrupt for Start/Stop Recording ----
  //https://github.com/thomasfredericks/Bounce2
  Switch.attach(Switch_pin, INPUT_PULLUP);
  Switch.interval(25);
  //pinMode(Switch_pin, INPUT_PULLUP);
  //attachInterrupt(digitalPinToInterrupt(Switch_pin), Interrupt_Start_Stop, CHANGE);


}

void loop() 
{
  Switch.update();

  if (Switch.fell() && active == false)
  {
    Interrupt_Start();
  }
  else if(Switch.rose() && active == true)
  {
    Interrupt_Stop();
  }

  if(active == true)
  {
    logData();
    //continueRecording();
  }
}

Is there somthing else that I could try?

Thanks
 
Is it stalling because the ring buffer is full?
Is there a file write in another location needing?: !file_accel.isBusy()

Just with a quick glance maybe in logData() repeat on this while() there?
Code:
    //If Ringbuffer is > 512 and File is not Bussy write Data to file
[B]    if (n >= 512 && !file_accel.isBusy()) [/B]
    {
      if (512 != rb.writeOut(512))

If it is filling faster than 'n>=512' only writing a single 512 buffer will fall behind?

Have 'seen' of that code but never looked into it. If there are multiples of 512 available sending them as a single 1024, 2048 or 4096 write would do better keeping the ring buffer empty and the writes would be more efficient.
 
No, the buffer is not full. The Code saves the max bytes in the buffer. With all my test it was always (way) below 600. Therefore this should not be the bottleneck.
There is another file write. But is the second file from the audio recording.
I can try and write bigger chucks.
I suspect that the writing implementation is not the problem. I suspect that is has to do with the fact that I write two files at one. (it does not mater if on to one card or on to cards.), or that the recording implementation has some error. But I will try writing two “normal” files at once. If then there is no Problem, then I suspect that recording implementation somehow interrupts that main code. Maybe it does something in the background. But I have to do some more test.
 
I have now made some test. The problem seems to be when writing wo files.
I changed the size of the bufferwriteout, and I track how often data is written to the sd card. Now you can clearly see that the problem is when the buffer is written. Is seams that when the buffer is written the code stops and waits. This results that the timing is then to slow.
In this Image you can clearly see that the timing spikes when the buffer is written. I also tested using two different bufferwriteout sizes so that they don’t fill up at the same time. But this does not help. In this case one file was written 12 times, the other 25 times. If you count you can see the 25 spikes. I think the spikes is higher if both must write at the same time. Ther fore the only solution that I see is to increase the write speed, or to allow that the writing is done in the background. Otherwise, I have no other idea.

Bild3.jpg

The Code
Code:
#include "SdFat.h"
#include "RingBuf.h"
#include <Wire.h>
#include <Bounce2.h>
#include <Audio.h>

// Use Teensy SDIO
#define SD_CONFIG  SdioConfig(FIFO_SDIO)

//Define (Parameters) of Buffer and SD File
#define LOG_INTERVAL_USEC 1000  // Interval between measuremts for 1 ksps.
#define LOG_FILE_SIZE 10*25000*600  // 150,000,000 bytes.
#define RING_BUF_CAPACITY 400*512
#define BYTES_TO_TWO_WRITE 32768

#define LOG_FILENAME "SdioLogger.csv"

unsigned long last_data_time = 0;
unsigned long data_time = 0;

SdFs sd;
FsFile file_accel;
FsFile file_audio;

int w_counter1 = 0;
int w_counter2 = 0;

// RingBuf for File type FsFile.
RingBuf<FsFile, RING_BUF_CAPACITY> rb1;
RingBuf<FsFile, RING_BUF_CAPACITY> rb2;

//Define Input Pins
#define Switch_pin       41
#define Data_pin         32
Bounce Switch = Bounce();
Bounce Data = Bounce();

//Variables for Accelerometer
int adxl357 = 0x1D;

uint8_t DEVID_AD;
uint8_t REVID;
uint8_t Status;
uint8_t Range;
uint8_t POWER_CTL;

uint8_t XDATA3 = 0;
uint8_t XDATA2 = 0;
uint8_t XDATA1 = 0;

uint8_t YDATA3 = 0;
uint8_t YDATA2 = 0;
uint8_t YDATA1 = 0;

uint8_t ZDATA3 = 0;
uint8_t ZDATA2 = 0;
uint8_t ZDATA1 = 0;

long int XDATA = 0;
long int YDATA = 0;
long int ZDATA = 0;

//Define System Variables
size_t n1 = 0;
size_t n2 = 0;
int counter = 0;
size_t maxUsed1 = 0;
size_t maxUsed2 = 0;
bool active = false;
String Data_to_write = "";
String Dateiname_audio = "";
String Dateiname_accelerometer = "";

//Define Variables for Audio

// 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
// GUItool: end automatically generated code

//Define Input
const int myInput = AUDIO_INPUT_MIC;

void logData() 
{
  //Check if file is full
  n1 = rb1.bytesUsed();
  if ((n1 + file_accel.curPosition()) > (LOG_FILE_SIZE - 20)) 
  {
    Serial.println("File1 full - quitting.");
    active = false;
    return;
  }
  else
  {
    //Log Number of bytes in Ringbuffer
    if (n1 > maxUsed1) 
    {
      maxUsed1 = n1;
    }

    //If Ringbuffer is > 512 and File is not Bussy write Data to file
    if (n1 >= BYTES_TO_TWO_WRITE*2 && !file_accel.isBusy()) 
    {
      if (BYTES_TO_TWO_WRITE*2 != rb1.writeOut(BYTES_TO_TWO_WRITE*2)) 
      {
        Serial.println("writeOut 1 failed");
        active = false;
        return;
      }
      else
      {
        w_counter1++;
      }
    }
  }

  n2 = rb2.bytesUsed();
  if ((n2 + file_audio.curPosition()) > (LOG_FILE_SIZE - 20)) 
  {
    Serial.println("File2 full - quitting.");
    active = false;
    return;
  }
  else
  {
    //Log Number of bytes in Ringbuffer
    if (n2 > maxUsed2) 
    {
      maxUsed2 = n2;
    }

    //If Ringbuffer is > 512 and File is not Bussy write Data to file
    if (n2 >= BYTES_TO_TWO_WRITE && !file_audio.isBusy()) 
    {
      if (BYTES_TO_TWO_WRITE != rb2.writeOut(BYTES_TO_TWO_WRITE)) 
      {
        Serial.println("writeOut 2 failed");
        active = false;
        return;
      }
      else
      {
        w_counter2++;
      }
    }
  }

  //Get new Data if Data is avalible and time is up
  data_time = micros();
  if(digitalRead(Data_pin) && (data_time - last_data_time >= LOG_INTERVAL_USEC) )
  {
    getData();
    rb1.println(Data_to_write);
    rb2.println(Data_to_write);
    last_data_time = data_time;

    if (rb1.getWriteError()) 
    {
      // Error caused by too few free bytes in RingBuf.
      active = false;
      return;
    }
    if (rb2.getWriteError()) 
    {
      // Error caused by too few free bytes in RingBuf.
      active = false;
      return;
    }
  }
}

void getData()
{
  Wire2.beginTransmission(adxl357); 
  Wire2.write(0x08); //0x08 für start bei x // 0x0E für Start bei z
  Wire2.endTransmission();
  Wire2.requestFrom(adxl357, 9);

  XDATA3 = Wire2.read();
  XDATA2 = Wire2.read();
  XDATA1 = Wire2.read();
  
  YDATA3 = Wire2.read();
  YDATA2 = Wire2.read();
  YDATA1 = Wire2.read();
  
  ZDATA3 = Wire2.read();
  ZDATA2 = Wire2.read();
  ZDATA1 = Wire2.read();

  convert(&XDATA, &XDATA3, &XDATA2, &XDATA1);
  convert(&YDATA, &YDATA3, &YDATA2, &YDATA1);
  convert(&ZDATA, &ZDATA3, &ZDATA2, &ZDATA1);

  Data_to_write = String(micros()) + ";" + String(XDATA) + ";" + String(YDATA) + ";" + String(ZDATA);
}

void convert(long int* output, uint8_t* Data3, uint8_t* Data2, uint8_t* Data1)
{
  //-524288 bis 524287
  //Umrechnen in Dezimal (Zweierkomplement)
  *output = 0;
    *output = *Data3;
    *output <<= 8;
    *output |= *Data2;
    *output <<= 8;
    *output |= *Data1;
    *output >>= 4;

  if(bitRead(*Data3, 7) == 1) //negative Zahel
  {
    *output = *output - (2*524288);
  }
}

void Interrupt_Start()
{
  Serial.println("Starting");
  //---- INIT SD Card and Create File ----
  // Init SD Card
  if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial);
  }

  //Check for File Name
  Dateiname_accelerometer = String(counter) + ".csv";
  Dateiname_audio = String(counter) + "second.csv";
  while (sd.exists(Dateiname_accelerometer.c_str()) || sd.exists(Dateiname_audio.c_str()))
  {
    Serial.println("Datei mit gleichen Namen schon vorhanden, Namen abwandeln");
    counter ++;
    Dateiname_accelerometer = String(counter) + ".csv";
    Dateiname_audio = String(counter) + "second.csv";
    Serial.print("Neuer Dateinamen: ");
    Serial.print(Dateiname_accelerometer);
    Serial.print(" , ");
    Serial.println(Dateiname_audio);
  }

  //Create file
  if (!file_accel.open(Dateiname_accelerometer.c_str(), O_RDWR | O_CREAT | O_TRUNC)) 
  {
    Serial.print("Failed to open: ");
    Serial.println(Dateiname_accelerometer);
    return;
  }
  else
  {
    Serial.print("Start: ");
    Serial.println(Dateiname_accelerometer);
  }

  if (!file_audio.open(Dateiname_audio.c_str(), O_RDWR | O_CREAT | O_TRUNC)) 
  {
    Serial.print("Failed to open: ");
    Serial.println(Dateiname_audio);
    return;
  }
  else
  {
    //queue1.begin();
    Serial.print("Start: ");
    Serial.println(Dateiname_audio);
  }

  // File must be pre-allocated to avoid huge
  // delays searching for free clusters.
  if (!file_accel.preAllocate(LOG_FILE_SIZE)) {
     Serial.println("preAllocate failed\n");
     file_accel.close();
     return;
  }

  if (!file_audio.preAllocate(LOG_FILE_SIZE)) {
     Serial.println("preAllocate failed\n");
     file_audio.close();
     return;
  }

  // initialize the RingBuf.
  rb1.begin(&file_accel);
  rb2.begin(&file_audio);
  maxUsed1 = 0;
  maxUsed2 = 0;

  active = true;
  counter++;

  Serial.println("Recording");

}

void Interrupt_Stop()
{
  Serial.println("Stop");
  active = false;

  //Accelerometer Stop
  rb1.sync();
  rb2.sync();
  file_accel.truncate();
  file_audio.truncate();
  file_accel.rewind();
  file_audio.rewind();

  Serial.print("fileSize: ");
  Serial.println((uint32_t)file_accel.fileSize());
  Serial.print("maxBytesUsed: ");
  Serial.println(maxUsed1);
  file_accel.close();

  Serial.print("fileSize: ");
  Serial.println((uint32_t)file_audio.fileSize());
  Serial.print("maxBytesUsed: ");
  Serial.println(maxUsed2);
  file_audio.close();

  Serial.println(w_counter1);
  Serial.println(w_counter2);

  //Audio Stop
  /*queue1.end();
  while (queue1.available() > 0) 
  {
    file_audio.write((byte*)queue1.readBuffer(), 256);
    queue1.freeBuffer();
  }
  file_audio.close();*/
}

void continueRecording() 
{
   if (queue1.available() >= 2) {
    byte buffer[512];
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer+256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    file_audio.write(buffer, 512);
  }
}

void setup()
{
  // ---- Set up Serial ----
  Serial.begin(9600);
  while (!Serial) {}

  Serial.println("setup");

  // ---- Set up Accelerometer ---- 
  Wire2.begin();
  Wire2.setClock(1000000); //400000 für Fast Mode //1000000 für High Speed Mode
  delay(500);

  //Read  and set Range
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2C);
  Wire2.write(129); // 1 für Fast mode +-10g // 129 für High speed mode +110g // 2 für Fast mode +-20g
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  Range = Wire2.read();

  Serial.print("Range: ");
  Serial.println(Range);

  //Read DEVID_AD
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x00);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  DEVID_AD = Wire2.read();

  Serial.print("DEVID_AD: ");
  Serial.println(DEVID_AD);

  //Read REVID
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x03);
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  REVID = Wire2.read();

  Serial.print("REVID: ");
  Serial.println(REVID);

  //Read and set POWER_CTL
  Wire2.beginTransmission(adxl357);
  Wire2.write(0x2D);
  Wire2.write(0); //enable measurement mode
  Wire2.endTransmission();
  delay(100);
  Wire2.requestFrom(adxl357, 1);
  POWER_CTL = Wire2.read();

  Serial.print("POWER_CTL: ");
  Serial.println(POWER_CTL);

  // ---- Set up Audio ----
  /*AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.micGain(40);*/

  // ---- Set Interrupt for Data ready (Accelerometer) ----
  pinMode(Data_pin, INPUT_PULLDOWN);
  //attachInterrupt(digitalPinToInterrupt(Data_pin), Interrupt_Data, RISING);

  // ---- Set Interrupt for Start/Stop Recording ----
  //https://github.com/thomasfredericks/Bounce2
  Switch.attach(Switch_pin, INPUT_PULLUP);
  Switch.interval(25);
  //pinMode(Switch_pin, INPUT_PULLUP);
  //attachInterrupt(digitalPinToInterrupt(Switch_pin), Interrupt_Start_Stop, CHANGE);


}

void loop() 
{
  Switch.update();

  if (Switch.fell() && active == false)
  {
    Interrupt_Start();
  }
  else if(Switch.rose() && active == true)
  {
    Interrupt_Stop();
  }

  if(active == true)
  {
    logData();
    //continueRecording();
  }
}

Edit:
When I am writing only one file the problem is the same. When the buffer is written the code “stops”. And this causes a spike.

Bild4.jpg
 
Last edited:
Yes this code will stop for writes:
Code:
void loop() 
{
..
  if(active == true)
  {
    [B]logData();[/B]
...

That is expected and anything else in loop() will be held up while logData() runs.

Other time critical tasks - when possible - need to be performed with perhaps a timer interrupt to assure they happen with required regularity.

A USB stick will have similar issues of recurring longer duration writes as they use the same onboard manager processor to assure the integrity and functionality of the flash technology in use.

If the buffer space is available and not being filled, the logData() could wait for perhaps a 4K (or 8K) block to write and those long delays would happen less frequently. Perhaps the change would be related to this comment: //If Ringbuffer is > 512 and File is not Bussy write Data to file
On average the writes will take longer to transfer more data - but it will be more efficient in the long run.
That 4K would be 8 sets of 512 and this suggests there are 400?: #define RING_BUF_CAPACITY 400*512

There may be the option to 'pre-allocate' the disk space as well that will get some of the disk space management done up front and reduce delays as the file 'grows'?
 
Does anyone know if the audio library code changed between release 1.57 and 1.58? In our code, encoder response went from about 1 second/detent move to almost 30 seconds/detent move. (We are doing some processor-intensive DSP between interrupt calls to the encoder.) I do realize this is a pretty broad question with no code to support it, but knowing the audio library did not change would prevent me from going down that rabbit hole at least.
 
Does anyone know if the audio library code changed between release 1.57 and 1.58? In our code, encoder response went from about 1 second/detent move to almost 30 seconds/detent move. (We are doing some processor-intensive DSP between interrupt calls to the encoder.) I do realize this is a pretty broad question with no code to support it, but knowing the audio library did not change would prevent me from going down that rabbit hole at least.

The change since 1.58-beta4:

Fix AVR toolchain for Teensy 2.0 with Arduino 2.0.x
Fix SdVolume compatibility on Teensy 2.0
USBHost_t36 more cautious date transfer queuing (KurtE)


Changes since Teensyduino 1.57:

Updated toolchain to gcc 11.3.1 for Teensy LC, 3.x, 4.x
Update core library for gcc 11.3.1
Update Wire library for gcc 11.3.1
Update teensy_size for gcc 11.3.1
FlexIO_t4 FlexSerial support more baud rates (KurtE)
AudioEffectEnvelope fix release name conflict (Jonathan Oakley)
Add audio DynamicPatching example (Jonathan Oakley)
Audio design tool fix control name on export (Jonathan Oakley)
USBHost_t36 improved HID device diagnostic info (KurtE)
Improve C & C++ library access to Teensy 3 & 4 RTC hardware
Audio use IntervalTimer for updates if no hardware update available
automatically create .lst file after linking
include time.h with Arduino.h
fix FNET on gcc 11
update MFRC522
fix Snooze errors with gcc 11
update TeensyThreads
USBHost_t36 bluetooth and HID improvements (KurtE)
New gcc 11.3.1 toolchain supported on all systems
Fix compiler warnings, many libraries
Fix missing serial receive with Arduino 2.0.x on Windows after Teensy reboots
Fix unable to start Teensy Loader on MacOS Ventura with Arduino 1.8.x
fix USB MIDI transmit on Teensy 4.x when running at only 12 Mbit/sec speed
Arduino 2.0.x "Invalid FQBN" workaround
Print warning message is "serial port" not "teensy port" selected
Fix Teensy Loader startup problem on Raspberry Pi 4 running Raspbian Buster
FlexIO / FlexSerial improvements (KurtE)
USBHost_t36 - update storage examples (KurtE)
ST7735_t3 - fix screen width check (KurtE)
C++11 move semantics on File (ScottDuckworth)
MTP.loop() would wait 1ms with no messages (KurtE)
Allow unconnected AudioConnection (Jonathan Oakley)
Fix Serial1.availableForWrite() on Teensy 2.0
AudioSynthWavetable fixes & docs (Jonathan Oakley)
USBHost_t36 Bluetooth improvements (KurtE and mjs513)
Improve String support for 64 bit integers
Allow programs to override gettimeofday (Shawn Silverman)
Improve bare (without Serial, Serial1, File) printf() support
Handle null pointer gracefully in Serial.write(string)
Fix Serial.write() return value (Shawn Silverman)
Fix IntervalTimer end() when timer interrupt pending
Speed up HardwareSerial FIFO size calculation (Shawn Silverman)
Fix startup with -Os and -Og optimization
Allow programs to override sbrk (Timo Sandmann)
Stream String readStringUntil() default to allow unlimited length
Define WIRE_INTERFACES_COUNT for Arduino compatibility
Fix TIMSEL field width in FlexIO SHIFTCTL register (squidcc)
Allow SdVolume to access card, but with deprecated warning
Fix compiler warnings with -Wextra (Shawn Silverman)
Change Print::write_error for Arduino compatibility (Shawn Silverman)
Call yield() from second/third USB serial bool (Geert Uytterhoeven)
Audio design tool fix import with AudioEffectDelayExternal (Jonathan Oakley)
Audio design tool import space objects for better visibility (Jonathan Oakley)
Audio tutorial examples updated for Teensy 4.0
Aduio examples updated with comments for Teensy 4 hardware
USBHost_t36 fix compiler warnings
USBHost_t36 improve startup on USB disks (Warren Watson)
USBHost_t36 fix USB disks endpoint issue (jmarsh)
USBHost_t36 fix Ant+ infinite loop (Gbertaz)
USBHost_t36 fix compiler warning (Jonathan Oakley)
USBHost_t36 support more Xbox One controllers (Dave Madison)
USBHost_t36 support CP2105 USB serial (jammerx19)
ILI9488_t3 support multiple displays (mjs513)
ILI9488_t3 update Digitizer4 example (KurtE)
LittleFS fix FRAM on alternate SPI ports (mjs513)
RA8875 fix fft_example2 example
WS2812Serial Remove 400 Hz refresh rate limit
XPT2046_Touchscreen further document alternate SPI ports
Linux warning if 00-teensy.rules missing
Fix SdVolume compatibility on Teensy 2.0
USBHost_t36 more cautious date transfer queuing (KurtE)
Above are the changes from 1.57 to 1.58.
 
Back
Top