Connect SD module and TFT display to ESP32 30 pin

Dear guys,

I am now to this ESP32 stuff and need your help. I would like to make an living photo frame with esp32, TFT display and SD card module. The idea is to format and copy photos to SD card and let it loop or shuffle always.

The display pins include VCC, GND, SDA, SCL, RST, DC, CS, BL and SDA-O (ST7796S, 3.5in, non touch)
The SD module pins include VCC, CS, MOSI, MISO, SCK, and GND

Wiring as below

|ESP32 | Display | SD module |
|VCC3.3 | VCC | VCC |
|GND | GND | GND |
|GPIO23 | SDA | MOSI |
|GPIO19 | (blank) | MISO |
|GPIO18 | SCL | SCK |
|GPIO15 | | CS |
|GPIO04 | RST | |
|GPIO02 | DC | |
|GPIO05 | CS | |
|VCC3.3 | BL | |

I tried the code for SD module only --> it works, for tft display only --> it works
But tried to combine it, the TFT initiate and inform the SDcard failed. Please show me some light at the end of the road.

my user_setup.h for tft

#define ST7796_DRIVER
#define TFT_WIDTH  320
#define TFT_HEIGHT 480
#define TFT_CS   5
#define TFT_DC   2
#define TFT_RST  4
#define TFT_SCLK 18 // SCL
#define TFT_MOSI 23 // MOSI
#define SPI_FREQUENCY 5000000
#define LOAD_GLCD    // Font 1
#define LOAD_FONT2   // Font 2
#define LOAD_GFXFF   // Bật FreeFont
#define TFT_BACKLIGHT_ON HIGH 
#define TFT_RGB_ORDER TFT_BGR
#define TFT_INVERSION_OFF

can you give a link to the TFT?
is the SD reader onboard the TFT or a separate module - if so give a link?
if the TFT has an onboard regulator it may need 5V power (BL is usually 3.3V)
you may have to connect the TFT to VSPI and the SD reader to HSPI

Did you add the TFT code to the working SD module code or did you add the SD module code to the working TFT code?

Here is the link to the TFT 3.5 Inch 320x480 SPI TFT Display Serial Port Module 3-5V PCB ST7796S LCD | eBay
the SD reader is separated module, it looks like this SD Card Module - Senith Electronics
I tried the Hspi and Vspi already, the code cannot upload to esp32

I did 1-by-1. Create the code working with SD, then add the TFT element and vice versa. still failed.

Run the TFT on the standard default SPI and the SD card on the HSPI bus, long term reliability is better that way.

I am guessing here, because you have not posted the code (hint!) but if your thinking of using the TFT_eSPI library to display images on the TFT, you might find it only works with earlier versions (2.0.14 and below) of the ESP32 Core.

I am sorry for not uploading the code, I write a short code to test the tft and sd card as below

#include <TFT_eSPI.h>
#include <SD.h>
#include <SPI.h>

// Define CS pins
#define TFT_CS 5
#define SD_CS 15

TFT_eSPI tft = TFT_eSPI(); // Initialize TFT object
SPIClass vspi = SPIClass(VSPI); // Use VSPI bus

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

  // Initialize TFT
  tft.begin();
  tft.setRotation(3); // Adjust rotation (0-3) as needed
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(2);
  tft.setCursor(10, 10);
  tft.println("ST7796 Initialized");

  // Initialize SD card
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH); // Deselect SD card initially
  vspi.begin(18, 19, 23, SD_CS); // SCK, MISO, MOSI, CS
  if (!SD.begin(SD_CS, vspi)) {
    Serial.println("SD Card Mount Failed");
    tft.setCursor(10, 50);
    tft.println("SD Card Failed");
    return;
  }
  Serial.println("SD Card Initialized");
  tft.setCursor(10, 50);
  tft.println("SD Card OK");

  // Example: Read a file from SD card
  File file = SD.open("/test.txt");
  if (file) {
    tft.setCursor(10, 90);
    tft.println("Reading test.txt:");
    while (file.available()) {
      String line = file.readStringUntil('\n');
      Serial.println(line);
      tft.println(line);
    }
    file.close();
  } else {
    Serial.println("Failed to open test.txt");
    tft.setCursor(10, 90);
    tft.println("No test.txt");
  }
}

void loop() {
  // Your application logic here (e.g., display images from SD card)
}

the screen shows
"ST7796 Initialized
SD Card Failed"

Wiring check twice already

What happens when you dont do the;

SPIClass vspi = SPIClass(VSPI); // Use VSPI bus

Stuff and just use the dafault SPI setup, as in;

SPI.begin(18, 19, 23);

and

SD.begin(SD_CS);