Skip to content

SDMMC write causing ESP32-S3 to reboot #9318

@wbadry

Description

@wbadry

Board

ESP32-S3-DevKitC-1

Device Description

  • ESP32-S3-DevKitC-1
  • SD CARD Shield (SDIO , 4-bit with pulklups)

Hardware Configuration

SD card shield with pullup resistors, and the pin configuration is as described in the code.

Version

v2.0.13

IDE Name

Visual Studio Code

Operating System

Windows 11

Flash frequency

80MHz

PSRAM enabled

no

Upload speed

921600

Description

The issue is divided into two sections:

Writing more than 1000 lines (string) causes ESP32-S3 to reboot

I made a simple example that:

  1. Creates a directory
  2. Opens a file for writing
  3. Writes a string to it number of times
  4. Shows some statistics about the min and max time to check if I can log the data while acquiring it.
#include "FS.h"
#include "SD_MMC.h"

int clk = 14;
int cmd = 15;
int d0 = 2;
int d1 = 4;
int d2 = 12;
int d3 = 13;

String data = "2269536694 0.23:50980:50980:0.07:203921:1.40:27450:3.21:196078:17.48:22.66:10.56:1.67:0.24:4.61:-28.23:-9.23:-69.87:30.51:4.91:75.92:1899.59:569.50:5652.00:258745:0";

/**
 * @brief Does statistics on the write times.
 *
 * This function does statistics on the write times.
 *
 * @param write_times An array of the time it takes to write the string to the file.
 * @param num_of_writes The number of writes.
 */
void statistics(long write_times[], long num_of_writes)
{
    long min = write_times[0];
    long max = write_times[0];
    long sum = 0;
    long num_of_writes_above_3000 = 0;
    for (long i = 0; i < num_of_writes; i++)
    {
        if (write_times[i] < min)
        {
            min = write_times[i];
        }
        if (write_times[i] > max)
        {
            max = write_times[i];
        }
        sum += write_times[i];
        if (write_times[i] > 3000)
        {
            num_of_writes_above_3000++;
        }
    }
    long average = sum / num_of_writes;
    float percentage_of_writes_above_1000 = (float)num_of_writes_above_3000 / num_of_writes * 100;
    Serial0.println("Min Write Time: " + String(min) + " us");
    Serial0.println("Max Write Time: " + String(max) + " us");
    Serial0.println("Average Write Time: " + String(average) + " us");
    Serial0.println("Number of Writes Above 3000us: " + String(num_of_writes_above_3000));
    Serial0.println("Percentage of Writes Above 3000us: " + String(percentage_of_writes_above_1000) + " %");
}

void setup()
{
    // INitialize Serial port
    Serial0.begin(115200);
    while (!Serial0)
    {
        delay(10);
    }

    // Wait until * is received
    while (Serial0.read() != '*')
    {
        Serial0.println("Waiting for *");
        delay(1000);
    }

    // Set the pins for the SDMMC Interface
    if (!SD_MMC.setPins(clk, cmd, d0, d1, d2, d3))
    {
        Serial0.println("Pin change failed!");
        return;
    }

    // Check if the SD Card is mounted successfully
    if (!SD_MMC.begin("/sdcard", false, false, 5000, 5))
        Serial0.println("Card Mount Failed !");
    else
        Serial0.println("Card Mounted Successfully !");

    // Create a directory inside the SD Card
    SD_MMC.mkdir("/test_directory_3");

    // Create a file inside the directory
    File file = SD_MMC.open("/test_directory_3/test_file_1.txt", FILE_WRITE, false);

    // Write data multiple times to the file
    long num_of_writes = 100;
    long write_times[num_of_writes];
    Serial0.println("Writing Data to File...");
    Serial0.println("Please Wait...");
    for (long i = 0; i < num_of_writes; i++)
    {
        long start_time = micros();
        file.println(data);
        // Check i is multiple of 1000
        if (i % 1000 == 0)
        {
            file.flush();
        }
        long end_time = micros();
        write_times[i] = end_time - start_time;
    }

    // Close the file
    file.close();

    // Do statistics on the write times
    Serial0.println("Statistics on Write Times:");
    statistics(write_times, num_of_writes);
}

void loop()
{
}

If the data is repeated up to around 1000, I get statistics like

Card Mounted Successfully !
Writing Data to File...
Please Wait...
Statistics on Write Times:
Min Write Time: 26 us
Max Write Time: 36193 us
Average Write Time: 1824 us
Number of Writes Above 3000us: 5
Percentage of Writes Above 3000us: 5.00 %

However, if increase the number of writes, let's assume 5000 even with file.flush() every 1000, I get ESP32 reboot

Card Mounted Successfully !
Writing Data to File...
Please Wait...

***ERROR*** A stack overflow in task loopTask has been detected.

Backtrace: 0x4037713e:0x3fce6900 0x4037a5d1:0x3fce6920 0x4037d336:0x3fce6940 0x4037be44:0x3fce69c0 0x4037a688:0x3fce69f0 0x4037a67e:0x55f2d858 |<-CORRUPTED

ELF file SHA256: 125554da4bf286eb

Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0xb (SPI_FAST_FLASH_BOOT)
Saved PC:0x42030e62
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3808,len:0x44c
load:0x403c9700,len:0xbd8
load:0x403cc700,len:0x2a80
entry 0x403c98d0
Waiting for *

I expect that when I flush, that data will be cleared from the memory, but there must be something I am missing.

data is flushed automatically. How do I control it?

I also noticed that, based on the time above, at a certain point, the library performs file.flush() automatically, even without calling it. Is there a way to control when to flush the data and disable this automatic behaviour?

Sketch

#include "FS.h"
#include "SD_MMC.h"

int clk = 14;
int cmd = 15;
int d0 = 2;
int d1 = 4;
int d2 = 12;
int d3 = 13;

String data = "2269536694 0.23:50980:50980:0.07:203921:1.40:27450:3.21:196078:17.48:22.66:10.56:1.67:0.24:4.61:-28.23:-9.23:-69.87:30.51:4.91:75.92:1899.59:569.50:5652.00:258745:0";

/**
 * @brief Does statistics on the write times.
 *
 * This function does statistics on the write times.
 *
 * @param write_times An array of the time it takes to write the string to the file.
 * @param num_of_writes The number of writes.
 */
void statistics(long write_times[], long num_of_writes)
{
    long min = write_times[0];
    long max = write_times[0];
    long sum = 0;
    long num_of_writes_above_3000 = 0;
    for (long i = 0; i < num_of_writes; i++)
    {
        if (write_times[i] < min)
        {
            min = write_times[i];
        }
        if (write_times[i] > max)
        {
            max = write_times[i];
        }
        sum += write_times[i];
        if (write_times[i] > 3000)
        {
            num_of_writes_above_3000++;
        }
    }
    long average = sum / num_of_writes;
    float percentage_of_writes_above_1000 = (float)num_of_writes_above_3000 / num_of_writes * 100;
    Serial0.println("Min Write Time: " + String(min) + " us");
    Serial0.println("Max Write Time: " + String(max) + " us");
    Serial0.println("Average Write Time: " + String(average) + " us");
    Serial0.println("Number of Writes Above 3000us: " + String(num_of_writes_above_3000));
    Serial0.println("Percentage of Writes Above 3000us: " + String(percentage_of_writes_above_1000) + " %");
}

void setup()
{
    // INitialize Serial port
    Serial0.begin(115200);
    while (!Serial0)
    {
        delay(10);
    }

    // Wait until * is received
    while (Serial0.read() != '*')
    {
        Serial0.println("Waiting for *");
        delay(1000);
    }

    // Set the pins for the SDMMC Interface
    if (!SD_MMC.setPins(clk, cmd, d0, d1, d2, d3))
    {
        Serial0.println("Pin change failed!");
        return;
    }

    // Check if the SD Card is mounted successfully
    if (!SD_MMC.begin("/sdcard", false, false, 5000, 5))
        Serial0.println("Card Mount Failed !");
    else
        Serial0.println("Card Mounted Successfully !");

    // Create a directory inside the SD Card
    SD_MMC.mkdir("/test_directory_3");

    // Create a file inside the directory
    File file = SD_MMC.open("/test_directory_3/test_file_1.txt", FILE_WRITE, false);

    // Write data multiple times to the file
    long num_of_writes = 5000;
    long write_times[num_of_writes];
    Serial0.println("Writing Data to File...");
    Serial0.println("Please Wait...");
    for (long i = 0; i < num_of_writes; i++)
    {
        long start_time = micros();
        file.println(data);
        // Check i is multiple of 1000
        if (i % 1000 == 0)
        {
            file.flush();
        }
        long end_time = micros();
        write_times[i] = end_time - start_time;
    }

    // Close the file
    file.close();

    // Do statistics on the write times
    Serial0.println("Statistics on Write Times:");
    statistics(write_times, num_of_writes);
}

void loop()
{
}

Debug Message

When number of data records is 100


Card Mounted Successfully !
Writing Data to File...
Please Wait...
Statistics on Write Times:
Min Write Time: 26 us
Max Write Time: 36193 us
Average Write Time: 1824 us
Number of Writes Above 3000us: 5
Percentage of Writes Above 3000us: 5.00 %


When number of data records are above 2000

```shell
Card Mounted Successfully !
Writing Data to File...
Please Wait...

***ERROR*** A stack overflow in task loopTask has been detected.

Backtrace: 0x4037713e:0x3fce6900 0x4037a5d1:0x3fce6920 0x4037d336:0x3fce6940 0x4037be44:0x3fce69c0 0x4037a688:0x3fce69f0 0x4037a67e:0x55f2d858 |<-CORRUPTED

ELF file SHA256: 125554da4bf286eb

Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0xb (SPI_FAST_FLASH_BOOT)
Saved PC:0x42030e62
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3808,len:0x44c
load:0x403c9700,len:0xbd8
load:0x403cc700,len:0x2a80
entry 0x403c98d0
Waiting for *


### Other Steps to Reproduce

_No response_

### I have checked existing issues, online documentation and the Troubleshooting Guide

- [X] I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions