ST7735 Display Works Without SD, but SD Card Initialization Fails

Hi everyone,

I’m working on a project using an Arduino Nano (ATmega328P with the old bootloader), an ST7735 1.8” TFT display, and the display’s built-in SD card reader. I’m trying to load a 24-bit BMP image from the SD card and display it on the screen. However, while the TFT display works perfectly on its own, I’m unable to initialize the SD card. The Serial Monitor just shows SD init failed!.

Here’s the setup:

  • Wiring:

    • TFT Display:
      • LED → 3.3V
      • SCK → D13
      • SDA → D11
      • A0 (DC) → D9
      • RESET → D8
      • CS → D10
      • GND → GND
      • VCC → 5V (confirmed the module supports 5V)
    • SD Card Reader (on the TFT module):
      • SD_CS → D4
      • SD_MOSI → D11 (shared with TFT MOSI)
      • SD_MISO → D12
      • SD_SCK → D13 (shared with TFT SCK)
  • Code: I’m using the Adafruit ST7735, Adafruit GFX, and SD libraries. Below is the full code I’m using for this test:

#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

// ---- Display Pins ----
#define TFT_CS   10  // Chip select for TFT
#define TFT_DC   9   // Data/Command for TFT
#define TFT_RST  8   // Reset for TFT

// ---- SD Card Pin ----
#define SD_CS    4   // Chip select for SD card

// Create ST7735 object using hardware SPI
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// A helper function to convert 24-bit color (RGB) to 16-bit (565).
static uint16_t color565(uint8_t r, uint8_t g, uint8_t b) {
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

// Forward declarations
uint16_t read16(File &f);
uint32_t read32(File &f);
void drawBMP(char *filename, uint8_t x, uint8_t y);

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing...");

  // Initialize TFT
  tft.initR(INITR_BLACKTAB);  
  tft.setRotation(1);
  tft.fillScreen(ST77XX_BLACK);

  // Initialize SD card
  pinMode(SD_CS, OUTPUT);
  if (!SD.begin(SD_CS)) {
    Serial.println("SD init failed!");
    while (true) { } // halt
  }
  Serial.println("SD init OK!");
}

void loop() {
  // Just test loading one BMP for now
  tft.fillScreen(ST77XX_BLACK);
  drawBMP("test.bmp", 0, 0);

  delay(5000);
}

// ------------------------------------------------------------------
// DRAW BMP FUNCTION
// ------------------------------------------------------------------
void drawBMP(char *filename, uint8_t x, uint8_t y) {
  File bmpFile;
  int bmpWidth, bmpHeight;
  uint8_t bmpDepth;
  uint32_t bmpImageOffset;
  uint32_t rowSize;
  bool flip = true;

  bmpFile = SD.open(filename);
  if (!bmpFile) {
    Serial.print("File not found: ");
    Serial.println(filename);
    return;
  }

  // Parse BMP header
  if (read16(bmpFile) == 0x4D42) { // BMP signature = 'BM'
    (void)read32(bmpFile); // File size (unused)
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageOffset = read32(bmpFile); // Start of image data
    (void)read32(bmpFile); // DIB header size
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if (read16(bmpFile) == 1) { // # planes = 1
      bmpDepth = read16(bmpFile); // bits per pixel
      if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
        rowSize = (bmpWidth * 3 + 3) & ~3;
        if (bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }
        if ((x + bmpWidth)  >= tft.width())  bmpWidth  = tft.width()  - x;
        if ((y + bmpHeight) >= tft.height()) bmpHeight = tft.height() - y;

        bmpFile.seek(bmpImageOffset);

        uint8_t sdbuffer[3 * 20]; 
        uint8_t buffidx = sizeof(sdbuffer);

        for (int row = 0; row < bmpHeight; row++) {
          int pos = bmpImageOffset + (flip ? (bmpHeight - 1 - row) : row) * rowSize;
          if (bmpFile.position() != (unsigned)pos) {
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer);
          }

          for (int col = 0; col < bmpWidth; col++) {
            if (buffidx >= sizeof(sdbuffer)) {
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0;
            }
            uint8_t b = sdbuffer[buffidx++];
            uint8_t g = sdbuffer[buffidx++];
            uint8_t r = sdbuffer[buffidx++];
            uint16_t color = color565(r, g, b);

            tft.drawPixel(x + col, y + row, color);
          }
        }
      } else {
        Serial.println("BMP not 24-bit or compressed!");
      }
    } else {
      Serial.println("BMP planes != 1!");
    }
  } else {
    Serial.println("Not a BMP file!");
  }
  bmpFile.close();
}

// ------------------------------------------------------------------
// Helper functions for reading little-endian 16- and 32-bit values
// ------------------------------------------------------------------
uint16_t read16(File &f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File &f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

What Works:

  • Without the SD card code, I can use the TFT display to draw shapes, write text, and change colors. The screen initializes fine, and tft.fillScreen() and related functions work as expected.

What Doesn’t Work:

  • As soon as I add the SD card initialization (SD.begin(SD_CS)), it fails, showing “SD init failed!” in the Serial Monitor.
  • The SD card is formatted as FAT32, and I’ve tried multiple cards (2GB, 16GB, etc.).
  • I’ve tested the SD card independently using the CardInfo example, with the same wiring, and it also fails to initialize.

Troubleshooting Done So Far:

  1. Verified wiring multiple times. Both SD_CS (D4) and TFT_CS (D10) are correctly configured.
  2. Ensured the TFT display and SD reader share SPI pins (MOSI, MISO, SCK) but have unique CS pins.
  3. Temporarily disconnected the TFT (by setting its CS pin HIGH) to isolate the SD card—still fails.
  4. Confirmed the Arduino Nano is running code fine (basic Serial prints and TFT-only sketches work).
  5. Tested different SD cards and formatted them as FAT32.
  6. Powered the SD module with 5V (as the module documentation allows for 5V operation).

Questions:

  1. Since the TFT display works without any issues, could this be a timing or SPI conflict between the SD card reader and the display?
  2. Has anyone successfully used the built-in SD card reader on the ST7735 with an Arduino Nano? If so, are there any specific steps or configurations I might be missing?
  3. Could this issue be related to voltage levels or pull-up resistors on the SPI lines?

I’d appreciate any suggestions to debug or resolve this issue. Thanks in advance!

A couple of questions:

  1. Does your display have level shifters built in? If not, what are you using for level shifting? Please show a schematic of what you've done.
  2. Have you tested the display controller's MISO output to see if it's tristated when the controller is not selected?

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