-1

I'm trying to write to a sd card but it fails when I use FreeRTOS tasks.

This is what I have:

#include "FS.h"
#include "SD.h"

const int32_t SD_SS_PIN = 2;
const int32_t SD_CS_PIN = 23;
const int32_t SD_MO_PIN = 5;
const int32_t SD_MI_PIN = 4;

void append_file(fs::FS &fs, const char * path, const char * message) {
  
  File file = fs.open(path, FILE_APPEND);

  if (!file)
  {
    Serial.println("Failed to open file for appending");
    
    return;
  } 
  else {
    file.print(message);
    file.close();
  }
}

void task_1(void * parameters){
  for (;;){
    Serial.println("Task 1.");

    append_file(SD, "/log.txt", "This will be the message.");

    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

void task_2(void * parameters){
  for (;;){
    Serial.println("Task 2.");

    append_file(SD, "/log.txt", "This will be the message.");
    
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

void setup(){
  Serial.begin(115200);

  SPIClass serial_peripheral_interface = SPIClass(VSPI);
  serial_peripheral_interface.begin(SD_SS_PIN, SD_MI_PIN, SD_MO_PIN, SD_CS_PIN);

  if(!SD.begin(SD_CS_PIN, serial_peripheral_interface, 80000000)){
    Serial.println("SD card mount failed.");
  }
  else{
    Serial.println("SD card mounted.");
  }

  TaskHandle_t task_1_handle;
  TaskHandle_t task_2_handle;

  xTaskCreatePinnedToCore(task_1, "Task 1", 4096, NULL, 6, &task_1_handle, 0);
  xTaskCreatePinnedToCore(task_2, "Task 2", 4096, NULL, 6, &task_2_handle, 0);
}

void loop(){ }

I checked and the log.txt file does exist on the sd card.

This is the result when running on an ESP32 dev module:

SD card mounted.

Task 1.

Task 2.

[ 533][E][sd_diskio.cpp:126] sdSelectCard(): Select Failed

[ 533][E][sd_diskio.cpp:621] ff_sd_status(): Check status failed

assert failed: xQueueSemaphoreTake queue.c:1545 (( pxQueue ))

Edit: When replacing #include "SD.h" with #include "SPIFFS.h" then calling SPIFFS.begin(true) in the setup everything works. But now it's not using the sd card.

Ayayron
  • 25
  • 5
  • Please copy your program, rewrite it so that the code in the tasks is at the end of `setup()` and remove all the code associated with the tasks. Does it work now or does it still fail? Please edit the question to include the result. – romkey Sep 02 '22 at 14:44
  • 1
    Just to verify, you want me to test if it works when not using tasks? I'm sorry, I should have clarified that it does work when not using tasks. I am able to write to the file when adding the `append_file(SD, "/log.txt", "This will be the message.");` to the standard `loop()` – Ayayron Sep 02 '22 at 14:50
  • The file write functions are probably not thread-safe. GIven the last error message, I assume the SD library you used is single-threaded. When calling the same functions from multiple threads (or tasks), the semaphore cannot be taken so the code fails. – wovano Sep 02 '22 at 14:58
  • I tried adding my own mutex and calling take before trying to write and give after but it still fails with the same error. – Ayayron Sep 02 '22 at 15:06
  • That was what I was asking, thanks. – romkey Sep 02 '22 at 16:24
  • I tried the mutex before asking the question. I removed it as I was unsure if I was doing it correctly. – Ayayron Sep 05 '22 at 05:20

1 Answers1

-1

I got it working. I added a QueueHandle_t and, using a task, continuously polled if something was added to the queue.

This is what I have:

#include "FS.h"
#include "SD.h"

const int32_t SD_SS_PIN = 2;
const int32_t SD_CS_PIN = 23;
const int32_t SD_MO_PIN = 5;
const int32_t SD_MI_PIN = 4;

const int32_t QUEUE_SIZE = 5;

SPIClass serial_peripheral_interface = SPIClass(VSPI);

QueueHandle_t message_queue;

bool append_file(fs::FS &fs, const char* path, const char* message){
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);

  if(!file){
    Serial.println("Failed to open file for writing.");
    file.close();

    return false;
  }

  if(file.print(message)){
    Serial.println("File written.");
    file.close();

    return true;
  }
  else{
    Serial.println("Write failed.");
    file.close();

    return false;
  }
}

void msg_task(void * parameters){
  const char* message;

  for (;;){
    if(xQueueReceive(message_queue, (void *)&message, 0) == pdTRUE){
      if(!SD.begin(SD_CS_PIN, serial_peripheral_interface, 80000000)){
        Serial.println("SD card mount failed.");
      }
      else{
        append_file(SD, "/log.txt", message);

        SD.end();
      }
    }

    vTaskDelay(200 / portTICK_PERIOD_MS);
  }

  vTaskDelete(NULL);
}

void task_1(void * parameters){
  for (;;){
    const char* message = "Task 1\n";

    if(xQueueSend(message_queue, (void *)&message, 10) != pdTRUE){
      Serial.println("Fail");
    }

    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }

  vTaskDelete(NULL);
}

void task_2(void * parameters){
  for (;;){
    const char* message = "Task 2\n";

    if(xQueueSend(message_queue, (void *)&message, 10) != pdTRUE){
      Serial.println("Fail");
    }

    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }

  vTaskDelete(NULL);
}

void setup(){
  Serial.begin(115200);

  serial_peripheral_interface.begin(SD_SS_PIN, SD_MI_PIN, SD_MO_PIN, SD_CS_PIN);

  if(!SD.begin(SD_CS_PIN, serial_peripheral_interface, 80000000)){
    Serial.println("SD card mount failed.");
  }
  else{
    Serial.println("SD card mounted.");

    SD.end();
  }

  message_queue = xQueueCreate(QUEUE_SIZE, sizeof(int32_t));

  TaskHandle_t task_msg_handle;
  TaskHandle_t task_1_handle;
  TaskHandle_t task_2_handle;

  xTaskCreatePinnedToCore(msg_task, "Task MSG", 4096, NULL, 1, &task_msg_handle, 0);
  xTaskCreatePinnedToCore(task_1, "Task 1", 8192, NULL, 2, &task_1_handle, 0);
  xTaskCreatePinnedToCore(task_2, "Task 2", 8192, NULL, 2, &task_2_handle, 0);
}

void loop(){ }
Ayayron
  • 25
  • 5