ESP32-WROOM-32D, 2.4" TFT, SD Card not working

I am looking for some ideas as to why my SD Card will not initialise and a possible solution if anyone else has run into this same scenario with similar hardware.

I am using a ESP32-WROOM-32D module with a 2.4" TFT (240x320) display using the TFT_eSPI and recommended SD library (the example one that comes with the Arduino IDE). I have also tried the SDFat library too with the same result. Note I also tried connecting 5v directly to the SD card Vdd pin and that also did not work. The SD_CS is still on pin 5 as per the example.

I do have a standalone SD card module that I am sure will work, I would just prefer the one on the display itself. I have other projects that use similar displays and would like to utilize it without needing to resort to additional modules.

#include <Arduino.h>
//#include <NimBLEDevice.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"

TFT_eSPI tft = TFT_eSPI();

/*
  MUST USE ILI9341_2_DRIVER in User_Setup.h
*/

// #define REASSIGN_PINS
// byte sck = 18;
// byte miso = 19;
// byte mosi = 23;
// byte cs = 5;

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 %lu 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 %lu ms\n", 2048 * 512, end);
  file.close();
}

void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:
  tft.init();
  tft.invertDisplay(true);
  tft.setRotation(3);
  tft.textsize = 1;
  tft.fillScreen(TFT_RED);

#ifdef REASSIGN_PINS
  SPI.begin(sck, miso, mosi, cs);
  if (!SD.begin(cs)) {
#else
  if (!SD.begin()) {
#endif
    Serial.println("Card Mount Failed");
    tft.print("SD Card 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));
  tft.print("Done");
}

void loop() {
  // put your main code here, to run repeatedly:

}

(The SD Card functions are actually in a separate tab called SD_Card.ino, I just moved them above the setup function)

The little green board in the second image is a 3.3v to 5v boost convertor.

Have you checked to see if the display controller's MISO line is being tristated when the display is not selected? It's all too common for that not to happen, and it'll manifest itself by no other SPI slaves being able to be read.

A Q&D test is to remove the connection to the display's MISO line. As long as your code isn't reading from the display but only writing to it, it won't have any affect on the display and the SD interface will suddenly start working.

If you need to read from the display, a 74AHC125 can be used to add proper tristating to the display's MISO line.

Hmm, I hadn't considered that. I'll give it a try.

Still failed

One last thought before I surrender to the arms of Morpheus; what values are R1, R2 and R3 on the back of the display? If they're anything much more than 0 ohms, consider replacing each of them with a short piece of wire. I had one display here that had 10K resistors in line with all the signals in what I assume was a half hearted attempt to allow the SD card to be used with 5V signals. Your ESP32 will be putting out the proper 3.3V levels so a high resistance might be enough to make it fail.

All 3 are 1K (102)

Removed the resistors and added solder blobs. I also removed the 5v bodge wire.

Same thing, it failed. :man_shrugging:

Oh no. You had 5V applied to the SD card? That's very likely why it doesn't work. And if you didn't cut the 3.3V trace leading to it beforehand you also shorted out the 3.3V regulator and applied 5V to the display as well. Ouch.

Well it wasn't working even when it was powered by the 3.3v. And yes, I did make sure the trace was severed before I connected the 5v.

Oh and I also tried jumping the J1 jumper and that just made things worse, the Esp32 started to overheat.

Before you applied 5V to the card, possibly the problem was the MISO non tristating issue. Or the too large resistors issue. Or both. Or something else. Now that you have applied 5V, I would imagine that the card not working reliably or at all by having 5V supplied to it is the main problem. A new card is likely be the only solution to that. But possible collateral damage caused by any over voltage SPI signals from the 5V'd card to the ESP32 then comes into question.

And yes, jumpering J1 if you were applying 5V to the Vcc line would cause problems as well by supplying 5V directly to the display.

Ok, I am now supplying 3.3v to the display, I have the MISO lifted and a fresh 256MB card in the slot, I also fixed the severed connection to the SD card... Still failed.

Does the card need to be formatted to FAT32 for it to even initialize?

After some poking around, I found that if I don't initialize the display, the SD card works. But once the display is initialized, the SD card stops working. My only conclusion is there is too much chatter going out to the display from the TFT_eSPI library that it inhibits the SD card library from working. This is even after I switched over to the external SD Card module. I still have yet to test the one on the display but I will get to that in a minute.

If I can't get the SD Card to work with the display, I am not sure what else to do other than use another arduino and a flash module and use it to flash the data I need for my other project.

I don't currently own a flash module so I will get to that when I can, hopefully it works.

UPDATE: It seems I need to initialize the SD card first, wait 500ms then initialize the TFT and now they both seem to work. I'll need to see what happens if I try to read a file after the display is initialized but for on startup, they work.

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