No Image TFT ST7735s

Downloaded the following code to try a "slideshow" as part of a future project.

I took photos from my files here and converted them to the correct 160 x 128 pixel size and saved them on an sd card as 24 bit and named them as in the sketch below.

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <SD.h>

#define TFT_CS  10  // Chip select line for TFT display
#define TFT_RST  8  // Reset line for TFT (or see below...)
#define TFT_DC   9 // Data/command line for TFT
#define SD_CS    4  // Chip select line for SD card
#define Color565(r, g, b) color565(r, g, b)

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

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

  delay(2000);

  tft.initR(INITR_BLACKTAB);
  

  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
    Serial.println("failed!");
    return;
  }
  Serial.println("OK!");

  tft.setRotation(1); // Landscape(1)

}

void loop() {

  bmpDraw("jackpot.bmp",0,0);
  delay(3000);
  bmpDraw("toosafe.bmp",0,0);
  delay(3000);
  bmpDraw("sawita.bmp",0,0);
  delay(3000);
  bmpDraw("jeff.bmp",0,0);
  delay(3000);
  bmpDraw("mum.bmp",0,0);
  delay(3000);
  bmpDraw("nad.bmp",0,0);
  delay(3000);
  bmpDraw("ton.bmp",0,0);
  delay(3000);
  bmpDraw("opo.bmp",0,0);
  delay(3000);

}


#define BUFFPIXEL 20

void bmpDraw(char *filename, uint8_t x, uint8_t y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print("Loading image '");
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print("File not found");
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print("File size: "); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print("Header size: "); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print("Bit Depth: "); Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print("Image size: ");
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        tft.setAddrWindow(x, y, x+w-1, y+h-1);

        for (row=0; row<h; row++) { // For each scanline...

          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col=0; col<w; col++) { // For each pixel...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.Color565(r,g,b));  //had error come up here compiling ...added the define Color565 at top of program
          } // end pixel
        } // end scanline
        Serial.print("Loaded in ");
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println("BMP format not recognized.");
}

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

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;
}

First, compile errors came up about not having access to Adafruit_i2c device.h so installed the Adafruit busio library and that error was fixed.

Then came an error saying this line was wrong and compiler asked if it should it be lower case "c" ...... tft.pushColor(tft.Color565(r,g,b)); so I did an include at the top of the sketch as some on the web suggested to another person's query on the same subject.

Compiles now and program runs.
Serial monitor shows the images loading from the SD card but the TFT screen is bright white, no images at all.
Checked and double checked connections and all seem ok.
Tried running the sketch on both a Uno and a pro mini....same thing.
Tried (for example) the Adafruit ST7735 and ST7789 example sketch "graphicstest" and that runs fine and displays really well.
Starting to think perhaps some original sketch error not compatible with the required current day libraries as sketch is 7 years old.
Have been looking for a similar "slide show using the ST7735S with SD card" but seems a bit thin on the web.
Link to original video..... https://www.youtube.com/watch?v=X8syt55ITUo&t=4s

Serial monitor output example....... note not all but it repeats the same anyhow........

Initializing SD card...OK!

Loading image 'jackpot.bmp'
File size: 36918
Image Offset: 54
Header size: 40
Bit Depth: 24
Image size: 96x128
Loaded in 757 ms

Loading image 'toosafe.bmp'
File size: 60726
Image Offset: 54
Header size: 40
Bit Depth: 24
Image size: 128x158
Loaded in 858 ms

Libraries are up to date and the version of the Arduino IDE is 1:8:19
SD card formatted to Fat32

I put in a query to the original author but ...no reply.

Schematic......
Schematic 9_2_2024

Since found another sketch which has the same outcome as above ...i.e. no image displayed, display bright white, serial monitor shows images as loaded and next image when button 2 pressed.

[code]
/*
 * Draw Bitmap images on ST7735 TFT display using Arduino.
 * The Arduino loads BMP format images from SD card and display
 *   them on the ST7735 TFT.
 * Reference: Adafruit spitftbitmap.ino example.
 * This is a free software with NO WARRANTY.
 * https://simple-circuit.com/
 */

#include <Adafruit_GFX.h>    // include Adafruit graphics library
#include <Adafruit_ST7735.h> // include Adafruit ST7735 display library
#include <SPI.h>             // include Arduino SPI library
#include <SD.h>              // include Arduino SD library

// define ST7735 TFT display connections
#define TFT_RST  8   // reset line (optional, pass -1 if not used)
#define TFT_CS   10   // chip select line
#define TFT_DC   9   // data/command line
#define SD_CS    4 


#define button   2  // button pin


// initialize Adafruit ST7735 TFT library
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

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

  pinMode(TFT_CS, OUTPUT);
  digitalWrite(TFT_CS, HIGH);
  digitalWrite(SD_CS,HIGH);
  pinMode(button, INPUT_PULLUP);

  // initialize ST7735S TFT display
  tft.initR(INITR_BLACKTAB);

  tft.fillScreen(ST77XX_BLUE);

  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
    Serial.println("failed!");
    while(1);  // stay here
  }
  Serial.println("OK!");

  File root = SD.open("/");  // open SD card main root
  printDirectory(root, 0);   // print all files names and sizes
  root.close();              // close the opened root

}

void loop() {
  File root = SD.open("/");  // open SD card main root

  while (true) {
    File entry =  root.openNextFile();  // open file

    if (! entry) {
      // no more files
      root.close();
      return;
    }

    uint8_t nameSize = String(entry.name()).length();  // get file name size
    String str1 = String(entry.name()).substring( nameSize - 4 );  // save the last 4 characters (file extension)

    if ( str1.equalsIgnoreCase(".bmp") )  // if the file has '.bmp' extension
      bmpDraw(entry.name(), 0, 0);        // draw it

    entry.close();  // close the file

    delay(500);
    while( digitalRead(button) ) ;  // wait for button press
  }
}

// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates.  It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel).  Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster.  20 pixels seems a
// good balance.

#define BUFFPIXEL 20

void bmpDraw(char *filename, uint8_t x, uint16_t y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print(F("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print(F("File not found"));
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("Image size: "));
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        tft.startWrite();
        tft.setAddrWindow(x, y, w, h);

        for (row=0; row<h; row++) { // For each scanline...

          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            tft.endWrite();
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col=0; col<w; col++) { // For each pixel...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
              tft.startWrite();
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.color565(r,g,b));
          } // end pixel
        } // end scanline
        tft.endWrite();
        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println(F("BMP format not recognized."));
}


// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

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;
}


void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

// end of code.
[/code]

No answers there...ok.
Try this then....would anyone know which library would have been used for the ST7735S display shown and the code used. As before, I tried to contact the original sketch writer but no answer there.
I'll include the display again so people do not have to go searching.


In the details below the purchase description it says to modify the settings.h file but no such settings within the setting.h
Contacted the seller, perhaps he has an answer, perhaps not, we'll see I guess.

Arduino library:
Recommended Arduino Library for TFT_ST7735
Change the following file _settings/TFT_ST7735_settings.h after installation:
144_NETTIGO for 1.44-inch display
18_NETTIGO for 1.8" display

There have been a few "solved" topics on the forum in the past two years with "tft white screen"... I just can't "search" for anything on the forum that is recent or relevant... so I go to the internet.

@bluejets I have a display similar to the one you show but the one I have does not include a SD card slot.

I hooked the display up to an ESP32, I have never used the Adafruit library but I did get some results with the following code. For some reason it did not fully fill the display it left a gap of 1 pixel along the right side and 1 pixel along the bottom edge, I wasn't too worried about that for now I just wanted to make sure the wires were landed in the right place.

My tft also had 8 pins for the display and if I look at your picture they are labelled from left to right

BL CS DC RES SDA SCL VCC GND

I did not hook up the BL (backlight) pin but the remaining 7 I connected like this

CS=5 DC=4 RES=2 SDA=SPI_MOSI SCL=SPI_CLOCK VCC=3.3V GND=GND

Yours may not be exactly the same but the above should give you a hint to how it should be connected.

This got me to a point where the display was cycling between red green and black, see if you can achieve the same.

Code:

#include <Adafruit_ST7735.h> // include Adafruit ST7735 display library
#include <SPI.h>             // include Arduino SPI library

// define ST7735 TFT display connections
#define TFT_RST  2   // reset line (optional, pass -1 if not used)
#define TFT_CS   5   // chip select line
#define TFT_DC   4   // data/command line
 
// initialize Adafruit ST7735 TFT library
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

void setup(void) {
  
  SPI.begin();

  pinMode(TFT_CS, OUTPUT);
  digitalWrite(TFT_CS, HIGH);
  
  // initialize ST7735S TFT display
  tft.initR(INITR_BLACKTAB);

  tft.fillScreen(ST77XX_BLUE);

}

void loop() {

  delay(5000);
  tft.fillScreen(ST77XX_RED);  
  delay(5000);
  tft.fillScreen(ST77XX_GREEN);  
  delay(5000);
  tft.fillScreen(ST77XX_BLACK);  

}

@bluejets if that works you can then go to Arduino/libraries/Adafruit_st7735/examples/ and see if there is anything there to help you further, in particular the example "shieldtest.uno" discusses loading images from a SD card.

I'll give your suggestion a try.
Same problem though regarding the library you quote as there are several and some may not work.

Did you have a link to the library you used?
The one that comes up in a search is for ST7735 and ST7789 library.

Yes that is the library I installed yesterday, I did the little color test and hoped you would say it worked for you, after that I might look at the transfer of images.

Like I said the software side is as new to me as it is you, this is just the way I would start out.

Link....??????

@bluejets I installed the library using the arduino IDE.

Yesterday I attached a SD card module to the setup to match your TFT/SD combo. I am now at the situation that you are, it does not write the image to the screen.

I am using the "shieldtest.ino" from the st7735 library examples folder, this uses the same "bmpDraw" method that you are using in your original post.

This is what I have seen so far, I can use the library functions to tft.fillScreen(), tft.setTextSize(),tft.setTextColor(), tft.setCursor() and tft.print(). The bmpDraw method prints the following output in the serial monitor

Loading image '/myimage'
File size: 61494
Image offset: 54
Header size: 40
Bit Depth: 24
Image size: 160x128

during this period it sets the boolean "goodBmp" to true.

After all of the above it seems to leave the drawing method without any obvious signs of a problem but not running to completion. So I feel the library is probably fine but this method is not quite right. If I get chance later I might look into the different options, maybe a different function or fix the current function. One very encouraging thing is the fact that the program parses the information at least up until the bitmap data. Printing an image to a tft screen is a common thing so there has to be an alternative method somewhere online.

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