Hi folks, i have a ESP32 S3 board that has a TFT screen and trying to load an animate GIF on it. I have its bigger brother and managed to use this code, but select the ESP32 Dev Board and load it. With this particular board, the first error was i had the wrong board, so i selected the ESP32s3 Dev Board, amended the animated GIF to suit the the smaller panel and loaded it. My issue is i have a blank screen and no warnings or issues.
below is the board i'm using and for the life of me i dont know where i went wrong. Any guidance?
The TFT Backlight is on GPIO 14 I believe. That would need to be pulled high in order to turn on the backlight for your screen.
I can't read the tiny screenshot your code is posted in to see if it's right. You need to post code as text and use the pre-formatted "<CODE>" option to format it as code. Then folks can read it better.
Ok, thanks, this is the code, which appears to include another piece of code called GIFDraw.ino. I dont quite understand some of the terminology, like when you say "pulled high" im a bit lost as the screen is part of the dev board like a Lillygo
//#define USE_DMA // ESP32 ~1.25x single frame rendering performance boost for badgers.h
// Note: Do not use SPI DMA if reading GIF images from SPI SD card on same bus as TFT
#define NORMAL_SPEED // Comment out for rame rate for render speed test
// Load GIF library
#include <AnimatedGIF.h>
AnimatedGIF gif;
// Example AnimatedGIF library images
#include "f.h"
// ESP32 40MHz SPI single frame rendering performance
// Note: no DMA performance gain on smaller images or transparent pixel GIFs
#define GIF_IMAGE f // No DMA 63 fps, DMA: 71fps
#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
void setup() {
Serial.begin(115200);
tft.begin();
#ifdef USE_DMA
tft.initDMA();
#endif
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
gif.begin(BIG_ENDIAN_PIXELS);
}
#ifdef NORMAL_SPEED // Render at rate that is GIF controlled
void loop()
{
// Put your main code here, to run repeatedly:
if (gif.open((uint8_t *)GIF_IMAGE, sizeof(GIF_IMAGE), GIFDraw))
{
Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
tft.startWrite(); // The TFT chip slect is locked low
while (gif.playFrame(true, NULL))
{
yield();
}
gif.close();
tft.endWrite(); // Release TFT chip select for other SPI devices
}
}
#else // Test maximum rendering speed
void loop()
{
long lTime = micros();
int iFrames = 0;
if (gif.open((uint8_t *)GIF_IMAGE, sizeof(GIF_IMAGE), GIFDraw))
{
tft.startWrite(); // For DMA the TFT chip slect is locked low
while (gif.playFrame(false, NULL))
{
// Each loop renders one frame
iFrames++;
yield();
}
gif.close();
tft.endWrite(); // Release TFT chip select for other SPI devices
lTime = micros() - lTime;
Serial.print(iFrames / (lTime / 1000000.0));
Serial.println(" fps");
}
}
#endif
But the microcontroller, the esp32, is connected to the display through the controller's GPIO pins. That's the only interface in/out of the microcontroller chip. Those pin are just not broken out to large, full-scale I/O pins on the dev board.
What board are you selecting in the Arduino IDE to program the board with? Depending on what you select, you may have to specify all the pins that the display uses. According to the product page they are:
Where did you get the code you are trying to use? You say it "includes" another file...are these two files in the same folder or separate folders? Do you know how the file structure of the Arduino IDE works? There are some great basic tutorials out there on how the IDE works. You may want to brush up on the basics first.
Hi, ok the board i bought was the one in the aliexpress link. I selected ESP32S3 Dev Module from the list, originally i had the ESP32 Dev Module for the bigger brother i successfully flashed the animated GIF to. So i bought this one thinking that it was identical almost but smaller in size. For me i have a bigger one that is going to be in a 3d printed Sharp Ghettoblaster that i can toggle on and off and display a cassette tape running to go with BT functionality of the amplifier itself. I watched some youtube on the animated GIF process with the previous board and have an extremely basic concept of sketch process, to a level that i could add additional *.h files for my GIF and comment out some lines of text. I'm really just wanting to get my gif going and liking the fact this has a pin out that i could try and put some additional code to controll some basic light strips (neopixels) as well, but subject to me trying to work it out.
This was the other code which is uploaded as a separate file, along the the converted gifs as *.h files that sit in the project folder.
// GIFDraw is called by AnimatedGIF library frame to screen
#define DISPLAY_WIDTH tft.width()
#define DISPLAY_HEIGHT tft.height()
#define BUFFER_SIZE 256 // Optimum is >= GIF width or integral division of width
#ifdef USE_DMA
uint16_t usTemp[2][BUFFER_SIZE]; // Global to support DMA use
#else
uint16_t usTemp[1][BUFFER_SIZE]; // Global to support DMA use
#endif
bool dmaBuf = 0;
// Draw a line of image directly on the LCD
void GIFDraw(GIFDRAW *pDraw)
{
uint8_t *s;
uint16_t *d, *usPalette;
int x, y, iWidth, iCount;
// Displ;ay bounds chech and cropping
iWidth = pDraw->iWidth;
if (iWidth + pDraw->iX > DISPLAY_WIDTH)
iWidth = DISPLAY_WIDTH - pDraw->iX;
usPalette = pDraw->pPalette;
y = pDraw->iY + pDraw->y; // current line
if (y >= DISPLAY_HEIGHT || pDraw->iX >= DISPLAY_WIDTH || iWidth < 1)
return;
// Old image disposal
s = pDraw->pPixels;
if (pDraw->ucDisposalMethod == 2) // restore to background color
{
for (x = 0; x < iWidth; x++)
{
if (s[x] == pDraw->ucTransparent)
s[x] = pDraw->ucBackground;
}
pDraw->ucHasTransparency = 0;
}
// Apply the new pixels to the main image
if (pDraw->ucHasTransparency) // if transparency used
{
uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
pEnd = s + iWidth;
x = 0;
iCount = 0; // count non-transparent pixels
while (x < iWidth)
{
c = ucTransparent - 1;
d = &usTemp[0][0];
while (c != ucTransparent && s < pEnd && iCount < BUFFER_SIZE )
{
c = *s++;
if (c == ucTransparent) // done, stop
{
s--; // back up to treat it like transparent
}
else // opaque
{
*d++ = usPalette[c];
iCount++;
}
} // while looking for opaque pixels
if (iCount) // any opaque pixels?
{
// DMA would degrtade performance here due to short line segments
tft.setAddrWindow(pDraw->iX + x, y, iCount, 1);
tft.pushPixels(usTemp, iCount);
x += iCount;
iCount = 0;
}
// no, look for a run of transparent pixels
c = ucTransparent;
while (c == ucTransparent && s < pEnd)
{
c = *s++;
if (c == ucTransparent)
x++;
else
s--;
}
}
}
else
{
s = pDraw->pPixels;
// Unroll the first pass to boost DMA performance
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
if (iWidth <= BUFFER_SIZE)
for (iCount = 0; iCount < iWidth; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];
else
for (iCount = 0; iCount < BUFFER_SIZE; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];
#ifdef USE_DMA // 71.6 fps (ST7796 84.5 fps)
tft.dmaWait();
tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
dmaBuf = !dmaBuf;
#else // 57.0 fps
tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
tft.pushPixels(&usTemp[0][0], iCount);
#endif
iWidth -= iCount;
// Loop if pixel buffer smaller than width
while (iWidth > 0)
{
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
if (iWidth <= BUFFER_SIZE)
for (iCount = 0; iCount < iWidth; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];
else
for (iCount = 0; iCount < BUFFER_SIZE; iCount++) usTemp[dmaBuf][iCount] = usPalette[*s++];
#ifdef USE_DMA
tft.dmaWait();
tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
dmaBuf = !dmaBuf;
#else
tft.pushPixels(&usTemp[0][0], iCount);
#endif
iWidth -= iCount;
}
}
} /* GIFDraw() */
i really appreciate you are taking the time to respond and showing some paitence
oh ok, im very new to this side of things so in my first code above i would need to define pins similar in to it, but make sure the correct ones are selected