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......

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]
