Help debugging a **black screen** issue on an **ESP32

Hi everyone,

I’m looking for help debugging a black screen issue on an ESP32 + TFT (TFT_eSPI) + FT6336 touch (I2C) + microSD (separate HSPI bus) project.

Hardware / setup

  • ESP32
  • TFT display driven by TFT_eSPI (480x320)
  • Touch controller FT6336 on I2C
    • SDA = GPIO32
    • SCL = GPIO25
    • RST = GPIO33
    • Address = 0x38
  • TFT backlight: GPIO21
  • microSD on HSPI (separate from TFT which is on VSPI)
    • SD_SCLK = GPIO14
    • SD_MISO = GPIO12
    • SD_MOSI = GPIO13
    • SD_CS = GPIO22 (can change if needed)

Problem / symptoms

  • Backlight turns on (so the panel is powered)
  • But the screen remains completely black (no text, no pixels)
  • Touch I2C responds (Wire.endTransmission() returns OK), so the MCU is running
  • The behavior seems related to SD/SPI initialization (sometimes it works until SD init runs)

What I suspect

  • Pin conflict between SD_CS (GPIO22) and TFT_eSPI pins (TFT_CS or TFT_DC in User_Setup.h)
  • Or SD initialization affecting the SPI bus (even though I’m using HSPI via SPIClass)

SD init code (HSPI)

SPIClass hspi(HSPI);

#define SD_SCLK 14
#define SD_MISO 12
#define SD_MOSI 13
#define SD_CS   22

void initSD() {
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);

  hspi.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
  delay(50);

  if (!SD.begin(SD_CS, hspi)) {
    Serial.println("SD init failed");
  } else {
    Serial.println("SD init OK");
  }
}

Questions

  1. Is GPIO22 commonly used by TFT_eSPI for TFT_DC/TFT_CS in many setups? (If yes, I’ll move SD_CS to another pin like GPIO27.)
  2. Any best practices to avoid SD init interfering with the display? (init order, different SPI frequency, etc.)
  3. If you’ve seen similar “black screen” behavior on ESP32 + TFT_eSPI, what were the usual causes?

If needed I can post:

  • my TFT_eSPI User_Setup.h pin mapping
  • wiring diagram / photos
  • full serial log

Thanks a lot!

Describe the steps you use to upload a sketch.

A wiring diagram would help. Just hand-draw the actual wires, not from the instructions, then post a photo of it.

I moved your topic to an appropriate forum category @louissioul.

The Development Tools > IDE 2.x forum category you chose is described as:

Discussion about the Arduino IDE software

Your post is not about Arduino IDE in any way, so why did you think it was appropriate to choose the Development Tools > IDE 2.x forum category???

In the future, when creating a topic please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

You have exhibited this same pattern of choosing a completely inappropriate category for every single one of the forum topics you have created. You are causing the forum maintainers to waste a lot of time cleaning up after you. People who do that tend to get account suspensions.

Thanks in advance for your cooperation.

give links to the particular TFT display, SD module, etc you are using?

Hi everyone — thanks. Here are the details you asked for.

1) Steps I use to upload the sketch

  • Arduino IDE 2.x on macOS
  • Boards Manager: ESP32 by Espressif Systems installed
  • Board selected: “ESP32 Dev Module” (ESP32-WROOM style board)
  • Tools:
    • Flash Mode: QIO
    • Flash Freq: 80 MHz (default)
    • Flash Size: 4MB (auto)
    • Partition: default (or “huge app” when needed)
    • Upload Speed: 921600 (sometimes I drop to 460800 if flaky)
  • Port: /dev/cu.usbserial-xxxx (or /dev/cu.SLAB_USBtoUART)
  • Click Upload
    • If it hangs on “Connecting…”, I hold BOOT, click Upload, then release BOOT when it starts writing.

2) Wiring (actual pin connections)

This is the real wiring I’m using (from the sketch + TFT_eSPI setup). Everything is 3.3V logic and all grounds are common.

### TFT (SPI) — on **VSPI**

* **TFT_MOSI → GPIO 23**
* **TFT_MISO → GPIO 19**
* **TFT_SCLK → GPIO 18**
* **TFT_CS → GPIO 15**
* **TFT_DC → GPIO 22**
* **TFT_RST → GPIO 4**
* **TFT Backlight (BL) → GPIO 21** (set HIGH in `setup()`)

### Touch FT6336 (I2C)

* **SDA → GPIO 32**
* **SCL → GPIO 25**
* **Touch RST → GPIO 33**
* I2C address: **0x38**

### microSD (SPI) — on **HSPI** (separate bus)

* **SD_SCLK → GPIO 14**
* **SD_MISO → GPIO 12**
* **SD_MOSI → GPIO 13**
* **SD_CS → GPIO 22**
* Code: `hspi.begin(14,12,13,22); SD.begin(22, hspi, 4000000);`

:white_check_mark: Important note: GPIO 22 is shared in my project: it’s TFT_DC (VSPI) and SD_CS (HSPI).
That is intentional on my side (I was trying to save pins), but it could absolutely cause conflicts / black screen / weird behavior depending on timing and library behavior. If you suspect this, I can rewire SD_CS to another free GPIO and retest.

3) Hardware I’m using (links / part identification)

I don’t want to pretend I know the exact listing you bought, so here’s the exact component description:

  • TFT module: MSP4031-type 3.5” SPI TFT, ST7796S driver, 480×320 (rotated in code), with FT6336U capacitive touch (I2C, addr 0x38).
  • SD module: generic microSD SPI module (3.3V logic preferred).

If you want me to be precise, I can paste the exact URLs of the store pages I bought from — I just don’t have them in front of me right now.

About the forum category

Understood — my mistake on category selection. This is a hardware display / wiring issue, not Arduino IDE.

If you want the fastest progress on the black screen: the first thing I’ll do is move SD_CS off GPIO 22 (so TFT_DC is not shared), then confirm TFT works without SD initialized, then add SD back.

4.0inch_SPI_MSP4030_MSP4031_ESP32_Demo_Instructions_EN.pdf (1,6 Mo)
this is what I use

did you run separate programs to test

  1. TFT display
  2. touch
  3. SD
    before attempting the program of post 1

if the separate programs worked did you try

  1. test TFT display + touch
  2. test TFT + touch + SD
    when did it fail?

I know there are many ESP32xyz, and many differences. My two ESP32 have me hold BOOT until my ESP goes into boot mode (USB disconnect/reconnect), click upload, then after upload is finished, press RESET. I hope this helps. Also, make your code send something to the Serial Monitor.

void setup () {
  Serial.begin(115200);
  delay(2000); // safer than while (!Serial)
  Serial.println("Hello, Lois!");
}

Hmm, DC is Direct Command on the display, for the telling the display whether it is receiving a command or data, whereas CS is Chip Select. It seems to me that if the program selects the SD card, its not going to be able to send anything to the display. Since you have not posted your code, we cannot see how you have arranged that switching, but one way for sure to find out would e to disconnect the SD card CS signal and see whether your display then shows something.

Let us know the results of the request in post #8, connecting one piece of hardware at a time and testing each one individually.

Detailed breakdown

1) TFT display only

:white_check_mark: PASS

  • Simple TFT_eSPI test sketch
  • Display initializes correctly
  • Backlight ON
  • Colors / text render as expected

2) Touch only (FT6336, I2C)

:white_check_mark: PASS

  • I2C scan detects device at 0x38
  • Raw touch coordinates read correctly over Wire
  • No lockups

3) SD card only (HSPI)

:white_check_mark: PASS

  • SD initialized on HSPI
  • File create / write / read works
  • Card type and size detected correctly

Combined tests

4) TFT + touch (no SD connected)

:white_check_mark: PASS

  • Display works
  • Touch works
  • UI renders and reacts correctly

5) TFT + touch + SD

:cross_mark: FAIL / unstable

  • This is where the problem appears
  • Symptoms range from:
    • black screen
    • display not responding
    • inconsistent behavior depending on timing

Root cause I am now strongly suspecting

I previously mentioned this, but after your comment I fully agree this is very likely the issue:

  • GPIO 22 is shared
    • TFT_DC (display command/data select on VSPI)
    • SD_CS (chip select on HSPI)

Even though they are on different SPI buses, sharing DC and CS is a bad idea, because:

  • DC must be stable and strictly controlled during display transfers
  • When SD is selected, DC can be unintentionally toggled
  • That would explain why:
    • TFT works alone
    • SD works alone
    • but both together cause failures

Next step (in progress)

  • I am rewiring SD_CS to a dedicated free GPIO
  • Keeping TFT_DC isolated
  • Then I will re-run the exact same test sequence:
    1. TFT only
    2. TFT + touch
    3. TFT + touch + SD