I’m currently using the following code to load a JPEG image from the SD card and display it on a 2.8-inch TFT screen with an ESP32. However, I’m concerned that my approach might not be fully optimized. Occasionally, the ESP32 crashes while displaying the image. It typically completes about 90% of the image before crashing, but this issue doesn't happen every time, which makes it difficult to reproduce and debug consistently.
I’m wondering if the ESP32 might be running out of resources (RAM or CPU) during the image rendering process, or if there’s another underlying cause.
Could anyone provide suggestions or optimizations to improve stability and prevent these crashes? Any advice on how to better handle memory usage or optimize image rendering would be greatly appreciated!
Thanks in advance!
TFT_IMG("/default/fullscreen.jpg", 0, 0);
void TFT_IMG(const char *filename, int xpos, int ypos) {
File jpegFile = SD.open(filename, FILE_READ); // or, file handle reference for SD library
if (!jpegFile) {
debug_print(0, "ERROR: File not found\"");
debug_print(1,filename);
return;
}
// Use one of the following methods to initialise the decoder:
bool decoded = JpegDec.decodeSdFile(jpegFile); // Pass the SD file handle to the decoder,
if (decoded) {
jpegRender(xpos, ypos);
}
jpegFile.close();
}
void jpegRender(int xpos, int ypos) {
//jpegInfo(); // Print information from the JPEG file (could comment this line out)
uint16_t *pImg;
uint16_t mcu_w = JpegDec.MCUWidth;
uint16_t mcu_h = JpegDec.MCUHeight;
uint32_t max_x = JpegDec.width;
uint32_t max_y = JpegDec.height;
bool swapBytes = tft.getSwapBytes();
tft.setSwapBytes (true);
// Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
// Typically these MCUs are 16x16 pixel blocks
// Determine the width and height of the right and bottom edge image blocks
uint32_t min_w = jpg_min(mcu_w, max_x % mcu_w);
uint32_t min_h = jpg_min(mcu_h, max_y % mcu_h);
// save the current image block size
uint32_t win_w = mcu_w;
uint32_t win_h = mcu_h;
// save the coordinate of the right and bottom edges to assist image cropping
// to the screen size
max_x += xpos;
max_y += ypos;
// Fetch data from the file, decode and display
while (JpegDec.read()) { // While there is more data in the file
pImg = JpegDec.pImage; // Decode a MCU (Minimum Coding Unit, typically a 8x8 or 16x16 pixel block)
// Calculate coordinates of top left corner of current MCU
int mcu_x = JpegDec.MCUx * mcu_w + xpos;
int mcu_y = JpegDec.MCUy * mcu_h + ypos;
// check if the image block size needs to be changed for the right edge
if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
else win_w = min_w;
// check if the image block size needs to be changed for the bottom edge
if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
else win_h = min_h;
// copy pixels into a contiguous block
if (win_w != mcu_w) {
uint16_t *cImg;
int p = 0;
cImg = pImg + win_w;
for (int h = 1; h < win_h; h++) {
p += mcu_w;
for (int w = 0; w < win_w; w++) {
*cImg = *(pImg + w + p);
cImg++;
}
}
}
// calculate how many pixels must be drawn
// uint32_t mcu_pixels = win_w * win_h;
// draw image MCU block only if it will fit on the screen
if ((mcu_x + win_w) <= tft.width() && (mcu_y + win_h) <= tft.height())
tft.pushImage(mcu_x, mcu_y, win_w, win_h, pImg);
else if ((mcu_y + win_h) >= tft.height())
JpegDec.abort(); // Image has run off bottom of screen so abort decoding
}
tft.setSwapBytes(swapBytes);
}
libraries used:
//SD
#include <SPI.h>
#include <SD.h>
const int SD_cs = 5; // Pin connected to the CS line of SD card module
File file;
//TFT
#include <FS.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
#include <JPEGDecoder.h>