SD Library Issue

Hi, I'm using an ESP32 Nano and trying to communicate with a 3.3v SD card module via SPI. I've found that SD card initialisation always fails when using the default SD library with board definitions from 3.2 all the way back to 2.0.11. When using the Adafruit fork of SdFat I am able to initialise the SD. In both cases I am using example sketches from each library and using the standard sck, mosi, miso and cs pins (D13, D11, D12 and D10 respectively.

Is this a known issue with the ESP32 SD library?

It seems the issue is with the SD.begin method as I am able to initialise an SD card using the following code:

#include "SD.h"
#include "sdios.h"

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
#define SPI_CLOCK SD_SCK_MHZ(50)

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif  ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif  // HAS_SDIO_CLASS
//==============================================================================
// Serial output stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
uint32_t cardSectorCount = 0;
uint8_t  sectorBuffer[512];
//------------------------------------------------------------------------------
// SdCardFactory constructs and initialises the appropriate card.
SdCardFactory cardFactory;
// Pointer to generic SD card.
SdCard* sd = nullptr;

//------------------------------------------------------------------------------

void setup() {
  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    yield();
  }

  // Select and initialise proper card driver.
  sd = cardFactory.newCard(SD_CONFIG);
  if (!sd) {
    Serial.println("SD initialisation failed.");
    return;
  }

  Serial.println("SD initialised");  

}
void loop() {
}

But the filesystem will not mount using the following:

  // Mount filesystem
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("Filesystem mount failed.");
    return;
  }

Hi @jamesg60. Please provide the full sketch that produces the "SD card initialisation always fails when using the default SD library" problem.

See below for the example sketch (SD_Test):

/*
 * Connect the SD card to the following pins:
 *
 * SD Card | ESP32
 *    D2       -
 *    D3       SS
 *    CMD      MOSI
 *    VSS      GND
 *    VDD      3.3V
 *    CLK      SCK
 *    VSS      GND
 *    D0       MISO
 *    D1       -
 */
#include "FS.h"
#include "SD.h"
#include "SPI.h"

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("Failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println("Not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.path(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("  SIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}

void createDir(fs::FS &fs, const char * path){
    Serial.printf("Creating Dir: %s\n", path);
    if(fs.mkdir(path)){
        Serial.println("Dir created");
    } else {
        Serial.println("mkdir failed");
    }
}

void removeDir(fs::FS &fs, const char * path){
    Serial.printf("Removing Dir: %s\n", path);
    if(fs.rmdir(path)){
        Serial.println("Dir removed");
    } else {
        Serial.println("rmdir failed");
    }
}

void readFile(fs::FS &fs, const char * path){
    Serial.printf("Reading file: %s\n", path);

    File file = fs.open(path);
    if(!file){
        Serial.println("Failed to open file for reading");
        return;
    }

    Serial.print("Read from file: ");
    while(file.available()){
        Serial.write(file.read());
    }
    file.close();
}

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

    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }
    if(file.print(message)){
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
    file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Appending to file: %s\n", path);

    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("Failed to open file for appending");
        return;
    }
    if(file.print(message)){
        Serial.println("Message appended");
    } else {
        Serial.println("Append failed");
    }
    file.close();
}

void renameFile(fs::FS &fs, const char * path1, const char * path2){
    Serial.printf("Renaming file %s to %s\n", path1, path2);
    if (fs.rename(path1, path2)) {
        Serial.println("File renamed");
    } else {
        Serial.println("Rename failed");
    }
}

void deleteFile(fs::FS &fs, const char * path){
    Serial.printf("Deleting file: %s\n", path);
    if(fs.remove(path)){
        Serial.println("File deleted");
    } else {
        Serial.println("Delete failed");
    }
}

void testFileIO(fs::FS &fs, const char * path){
    File file = fs.open(path);
    static uint8_t buf[512];
    size_t len = 0;
    uint32_t start = millis();
    uint32_t end = start;
    if(file){
        len = file.size();
        size_t flen = len;
        start = millis();
        while(len){
            size_t toRead = len;
            if(toRead > 512){
                toRead = 512;
            }
            file.read(buf, toRead);
            len -= toRead;
        }
        end = millis() - start;
        Serial.printf("%u bytes read for %u ms\n", flen, end);
        file.close();
    } else {
        Serial.println("Failed to open file for reading");
    }


    file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }

    size_t i;
    start = millis();
    for(i=0; i<2048; i++){
        file.write(buf, 512);
    }
    end = millis() - start;
    Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
    file.close();
}

void setup(){
    Serial.begin(115200);
    if(!SD.begin()){
        Serial.println("Card Mount Failed");
        return;
    }
    uint8_t cardType = SD.cardType();

    if(cardType == CARD_NONE){
        Serial.println("No SD card attached");
        return;
    }

    Serial.print("SD Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    Serial.printf("SD Card Size: %lluMB\n", cardSize);

    listDir(SD, "/", 0);
    createDir(SD, "/mydir");
    listDir(SD, "/", 0);
    removeDir(SD, "/mydir");
    listDir(SD, "/", 2);
    writeFile(SD, "/hello.txt", "Hello ");
    appendFile(SD, "/hello.txt", "World!\n");
    readFile(SD, "/hello.txt");
    deleteFile(SD, "/foo.txt");
    renameFile(SD, "/hello.txt", "/foo.txt");
    readFile(SD, "/foo.txt");
    testFileIO(SD, "/test.txt");
    Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
    Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}

void loop(){

}

This gives the following output:

Removing Dir: /mydir
rmdir failed
Listing directory: /
Failed to open directory
Writing file: /hello.txt
Failed to open file for writing
Appending to file: /hello.txt
Failed to open file for appending
Reading file: /hello.txt
Failed to open file for reading
Deleting file: /foo.txt
Delete failed
Renaming file /hello.txt to /foo.txt
Rename failed
Reading file: /foo.txt
Failed to open file for reading
Failed to open file for reading
Failed to open file for writing
Total space: 0MB
Used space: 0MB

Pins are connected as shown in the attached data sheet.

Arduino Nano ESP32 Pinout.pdf (1.9 MB)

It works perfectly for me using the official "Arduino ESP32 Boards" platform (I didn't test using the 3rd party "esp32" platform). Does the problem occur if you select Tools > Board > Arduino ESP32 Boards > Arduino Nano ESP32 from the Arduino IDE menus and then upload the sketch to the board again?

The connections you described previously are correct:

In other words:

Nano ESP32 SD Card
D10 CS
D11 MOSI
D12 MISO
D13 SCK
3.3V 3V3
GND GND

I am currently using the official v2.018. The board definition makes no difference other than later espressif definitions no longer supporting arduino pin numbering - wont compile unless using GPIO numbering.

Starting to think this board is DOA.

Looks like this thread describes the exact same issue:

If it was DOA then I would not expect that you would be able to initialize the SD using an alternative library.

I would be more suspicious of a problem with the SD card. The SdFat library is quite advanced , so it might be that the "SdFat - Adafruit Fork" library is compatible with the specific characteristics of your SD card, while the "SD" library is not.

If you have other SD cards, I recommend trying those cards to see if the problem is specific to the card you are using now.

So far I have tried 3 different cards from 3 different manufacturers, the latest being a 2Gb Sandisk class 2 micro SD. If the library is unable to mount certain cards then it is the fault of the library. Manufacturers cannot be expected to produce cards with a particular library compatibility in mind. The library should be robust enough to handle sd cards that are actually available on the market in 2025.