[ESP32] Sending I2S data from an SD card using tasks is too slow

I've been doing some research on how to send data taken from a .wav file on an SD card, and I found this library: GitHub - schreibfaul1/ESP32-audioI2S: Play mp3 files from SD via I2S .
I'm trying to build a little game console, and I'm trying to get the whole I2S routines to run on the seconday core, core 0.
I managed to do that, modifying the code from an exaple included in the library itself. Here's the code:

// audioI2S-- I2S audiodecoder for ESP32,

#include "Arduino.h"
//#include "WiFiMulti.h"
#include "Audio.h"
#include "SPI.h"
#include "SD.h"
#include "FS.h"

// Digital I/O used
 //For the SD card:
#define SD_CS          5
#define SPI_MOSI      23
#define SPI_MISO      19
#define SPI_SCK       18
 //For the I2S output:
#define I2S_DOUT      25
#define I2S_BCLK      27
#define I2S_LRC       26

Audio audio;
//Create a task handle
TaskHandle_t Task1;

void setup() {
    pinMode(SD_CS, OUTPUT);      digitalWrite(SD_CS, HIGH);
    SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
    SPI.setFrequency(1000000);
    Serial.begin(115200);
    SD.begin(SD_CS);

    audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
    audio.setVolume(6); // 0...21

    audio.connecttoFS(SD, "wavfile.wav");


    xTaskCreatePinnedToCore(
      Task1code, /* Function to implement the task */
      "Task1", /* Name of the task */
      10000,  /* Stack size in words */
      NULL,  /* Task input parameter */
      tskIDLE_PRIORITY,  /* Priority of the task */
      &Task1,  /* Task handle. */
      0  /* Core where the task should run */
      );
}

void loop()
{
  //Here I keep the main loop busy.
  long startAtMillis = millis();
  long endAtMillis = millis();
  Serial.println(endAtMillis - startAtMillis);
}

void Task1code (void *pvParameters) {
  while(true) {
    //This function needs to be called continuously.
    audio.loop();
  }
}

(The function does work correctly when used in the main loop, and I'm also able to get core zero busy with simple tasks in the meantime).
The problem is that, on core zero, the task runs too slow, and the I2S signal isn't continuous. I've already tried rising the priority of the task, but after another day of research I couldn't find any way to make this work.

I was practically convinced that it is possible to run this at the right speed, seen all the work the WiFi and bluetooth libraries do on that secondary core. So ultimately, is it actually possible? If so, what am I getting wrong?

Thanks in advance for any kind of help :smiley:

when using freeRTOS loop() should be empty.

Have you looked into the library being used and to why it runs so slow?

Why is the task assigned an idle priority when a 1 or 2 would suffice?

Why save a task handle when its not being used?

First of all, thanks a ton for answering!

when using freeRTOS loop() should be empty.

The project I'm working on is a tiny game console, and I need to find a way to read a .wav file and send it to an external DAC trough I2S communication. The game is supposed to run on loop(), so that's why I'm trying to keep it busy in this example.

Have you looked into the library being used and to why it runs so slow?

I have tried both this library and some "library-free" code provided by XTronical (https://www.xtronical.com/i2s_ep4/), and they both run very slowly. It runs fine on the main loop() but as soon as it's assigned to a task, it becomes extremely slow. I tried increasing the number of bytes read and sent through I2S, but it didn't help either, actually it didn't work at all. The only thing I can understand in all this, is that the library requires some really fast reading speed, and the task isn't fast enought to keep up.

Why is the task assigned an idle priority when a 1 or 2 would suffice?

I searched online for the best priority I could give this task, and this is what I found. From what I've read, it should run before anything else. Thanks for the information though, I'll sure set the priority to either 1 or 2 if sufficient!

Why save a task handle when its not being used?

The majority of the guides I found online didn't use handles, only one used it to delete the task. I've ran a lot of sketches without defining the task handle, and the result doesn't seem to change at all, unfortunately.. I just left the handle there, unused, and I'm sorry if that confused you in any way.

Thanks again for answering (and sorry for the late response, I had a lot to do these last three days).

EDIT: I've tried leaving the loop() empty and also changing the priority, but it still hasn't sped up a bit, unfortunately.
EDIT (2): Changing the priority to 2 actually seems to get the job done, woah! I'll try to understand why it didn't prior to the latest test. Thank you very much for all the help, I'll update on the situation.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.