// Include the jpeg decoder library
#include <TJpg_Decoder.h>
// Include the SD card library
#include <SD.h>
// Include Adafruit ILI9341 TFT display library
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// Pin definitions
#define SD_CS 4 // SD card chip select
#define TFT_CS 10 // TFT chip select
#define TFT_DC 9 // TFT data/command
#define TFT_RST -1 // Reset pin, -1 for no reset pin
#define BUFFPIXEL 20 // Buffer size for reading BMP
// Function to read a 16-bit value from the file with byte swap
uint16_t read16(File &f) {
uint16_t val;
f.read((uint8_t*)&val, 2); // Read 2 bytes from file into val
return (val >> 8) | (val << 8); // Swap bytes
}
// Function to read a 32-bit value from the file with byte swap
uint32_t read32(File &f) {
uint32_t val;
f.read((uint8_t*)&val, 4); // Read 4 bytes from file into val
return (val >> 24) | ((val >> 8) & 0x0000FF00) | ((val << 8) & 0x00FF0000) | (val << 24); // Swap bytes
}
// Initialize TFT display
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
void listFiles(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (!entry) {
// No more files, exit the loop
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print("\t"); // Print indentation for directories
}
Serial.print(entry.name()); // Print file name
if (entry.isDirectory()) {
Serial.println("/");
listFiles(entry, numTabs + 1); // Recursive call to list files in subdirectories
} else {
Serial.print("\t\t");
Serial.println(entry.size(), DEC); // Print file size
}
entry.close();
}
}
// This function opens a BMP file and displays it at the given coordinates
void drawBMP(char *filename, int x, int y) {
File bmpFile = SD.open(filename);
if (!bmpFile) {
Serial.println("File not found!");
return;
}
// BMP header check
if (read16(bmpFile) == 0x4D42) { // "BM" header
uint32_t fileSize = read32(bmpFile);
uint32_t imageOffset = read32(bmpFile);
uint32_t headerSize = read32(bmpFile);
int32_t bmpWidth = read32(bmpFile);
int32_t bmpHeight = read32(bmpFile);
uint16_t planes = read16(bmpFile);
uint16_t depth = read16(bmpFile);
if (planes != 1 || depth != 24) {
Serial.println("Unsupported BMP format!");
bmpFile.close();
return;
}
// Skip to the image data
bmpFile.seek(imageOffset);
// Calculate row size (including padding)
uint32_t rowSize = (bmpWidth * 3 + 3) & ~3;
// Allocate buffer for one row
uint8_t rowBuffer[3 * BUFFPIXEL];
// Set TFT window for the image area
tft.setAddrWindow(x, y, x + bmpWidth - 1, y + bmpHeight - 1);
// Read and display pixel data row by row
for (int row = 0; row < bmpHeight; row++) {
uint32_t pos = imageOffset + (bmpHeight - 1 - row) * rowSize; // BMP stores rows bottom to top
bmpFile.seek(pos);
int pixelCount = 0;
while (pixelCount < bmpWidth) {
int toRead = min(BUFFPIXEL, bmpWidth - pixelCount);
bmpFile.read(rowBuffer, 3 * toRead);
for (int i = 0; i < toRead; i++) {
uint8_t b = rowBuffer[3 * i]; // Blue
uint8_t g = rowBuffer[3 * i + 1]; // Green
uint8_t r = rowBuffer[3 * i + 2]; // Red
uint16_t color = tft.color565(r, g, b);
tft.pushColor(color); // Push the pixel to the screen
}
pixelCount += toRead;
}
}
bmpFile.close();
Serial.println("BMP Loaded!");
} else {
Serial.println("Not a valid BMP file.");
bmpFile.close();
}
}
void setup()
{
// Start serial communication for debugging
Serial.begin(115200);
Serial.println("\n\nTesting TJpg_Decoder library");
// Initialize SD card
if (!SD.begin(SD_CS)) {
Serial.println(F("SD.begin failed!"));
while (1) delay(0); // Infinite loop if SD fails
}
Serial.println("\r\nSD initialization successful.");
// Initialize TFT display
tft.begin();
tft.setRotation(3); // Set orientation if needed
tft.fillScreen(ILI9341_BLACK); // Clear screen with black color
File root = SD.open("/");
listFiles(root, 0); // List files starting from the root directory
root.close();
drawBMP("/test.bmp", 0,0);
}
void loop()
{
// Wait for 2 seconds before loading the next image
delay(2000);
}