I am not the most experienced working with microcontrollers and Arduino libraries but I will do my best to describe what I want to achieve and what troubles I am encountering with my current way of solving the problem.
My goal is to try and upload an mp3 file from a Flask server to an SD card connected to an ESP32 C3. I want to play the first mp3 file that is already stored on the SD card while also uploading the second mp3 file to the SD card. I want to do this so that after the first mp3 has finished playing the second mp3 can immediately start playing once the first mp3 is finished playing to avoid a 3-5 second silence while the second mp3 is being uploaded.
At the moment I am trying to use freeRTOS to read and write at the same time but the problem is that when the audio plays, the mp3 file is only partially uploaded and only when the audio has finished playing does the mp3 get correctly uploaded. I have tested my testPlayAudio and testUploadFiletoSD functions and they work as expected without freeRTOS.
Not sure what is causing this issue but perhaps the SD card I am using only allows for half duplex SPI communication. I have thought about switching to an ESP32 as it has two cores but I am not sure if that will fix the issue. I am open to any suggestions. The SD card that I am using is SPI SMT 512M SD from Adafruit. In case it is needed I am using a I2S 3W Class D Amplifier Module DFRobot.
Here is the arduino code that I have been running. If any clarification is need please let me know.
#include <Arduino.h>
String _url = "http://";
void testUploadFileToSD(void);
void testPlayAudio(void* parameters);
TaskHandle_t xPlayAudioHandle = NULL;
void setup() {
Serial.begin(115200);
delay(3000);
Serial.println("serial began...");
//Code establishing wifi connection and server connection etc
}
void loop() {
testUploadFileToSD();
}
void testPlayAudio(void* parameters) {
for(;;) {
Serial.println("About to initialise play audio");
String filename = "/SD_welcome_files/welcome_file.mp3";
AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3();
AudioFileSourceSD *file = new AudioFileSourceSD(filename.c_str());
AudioOutputI2S *out = new AudioOutputI2S();
Serial.println("MP3 initialised");
Serial.println(filename.c_str());
out->SetPinout(0, 1, 8);
Serial.println("initialised audio i2s");
mp3->begin(file, out);
Serial.println("About to loop");
bool looping = true;
while (looping) {
Serial.println("Looping");
if (mp3->isRunning()) {
if (!mp3->loop()) mp3->stop();
} else {
looping = false;
}
delay(20) ;
}
Serial.println("Played");
has_audio_finished_playing = true;
vTaskDelete(NULL);
}
void testUploadFileToSD(void) {
Serial.println("Creating playing audio task");
Serial.println();
xTaskCreate(
testPlayAudio,
"Playing audio",
4096,
NULL,
1,
&xPlayAudioHandle);
Serial.println("Uploading file to SD");
uploadFileToSD("asdf.mp3", "/SD_welcome_files", "tmp");
Serial.println("Waiting for audio to finish playing");
playAudio("/SD_welcome_files/asdf.mp3");
return;
}
void uploadFileToSD(String filename, String SD_path, String server_path) {
String url = _url + "/api/get_file";
String requestBody = "{\"filename\": \"" + filename + "\", \"server_path\": \"" + server_path + "\"}";
Serial.println(requestBody);
Serial.println("Uploading story file to the SD card");
bool retryFlag = true;
filename = SD_path + "/" + filename;
Serial.print("SD path ");
Serial.println(filename);
while (retryFlag) {
_http.begin(url.c_str());
_http.setTimeout(10000);
Serial.println(url);
_http.setAuthorization(_api_email.c_str(), _api_key.c_str());
_http.addHeader("Content-Type", "application/json");
int uploadedBytes = 0;
int httpResponseCode = _http.POST(requestBody);
if (httpResponseCode > 0) {
if (SD.exists(filename)) {
SD.remove(filename);
}
File file = SD.open(filename, FILE_WRITE);
int len = _http.getSize();
Serial.print("Content size: ");
Serial.println(len);
uint8_t buff[2048] = { 0 };
WiFiClient *stream = _http.getStreamPtr();
while (_http.connected() && ((len > 0 || len == -1) && uploadedBytes != len)) {
Serial.println("Uploading");
while(!stream->available()) {
delay(1);
}
size_t size = stream->available();
if (size) {
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
size_t writtenBytes = 0;
writtenBytes = file.write(buff, c);
if (writtenBytes != c) {
Serial.print("File write error: ");
Serial.println(file.getWriteError());
Serial.println("Error writing to SD card");
break;
}
if (len > 0) {
len -= c;
}
uploadedBytes += c;
}
}
if (uploadedBytes != _http.getSize()) {
Serial.println("File not uploaded correctly, attempting to upload again");
Serial.print(uploadedBytes);
Serial.print(" ");
Serial.println(len);
retryFlag = true; // Set the retry flag to attempt the request again
} else {
retryFlag = false; // Request succeeded, so no need to retry
}
file.close();
Serial.println("Received all data");
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
_http.end();
}
}