Closed hannescam closed 1 year ago
do you feel like creating it?
you can take this example as a template, and use the GIFDraw()
function from this example.
I think there are enough examples to get you going. The output of the GIFDRAW call is very simple - all you have to do is use the existing code to convert your pixels into RGB565/RGB888 and copy them to your output device one line at a time.
but this example is for the m5 stack specific and was not meant for other boards mine is the esp32 capacitive touch camera from makerfabs
The use of M5 specifics is just a layer over standard components so it'll be fine.
I assume you already have a working TFT_eSPI configuration for the makerfabs device, so basically you only need to rename a few variables in the template sketch and comment out the specifics.
1) comment out the first include line and add yours:
// #include <ESP32-Chimera-Core.h> // comment this out
#include <SD.h>
#include "YOUR_TFT_eSPI_Configuration.h"
#include <TFT_eSPI.h>
2) in the setup(), replace M5.begin()
by Serial.begin( 115200 );
3) search every occurence of M5STACK_SD
and replace it by SD
, it was just an alias so it'll be fine.
4) comment out the GIFDraw()
and TFTDraw()
functions
5) copy the GIFDraw function from the other sketch
6) optional: implement esp_deep_sleep() to replace M5.powerOFF();
ok i will try that and i have allready a working tft_espi config (over hspi) and a working sd config (also over hspi)
it doesnt work it doesnt find std::vector please provide me a functional sketch
it doesnt find std::vector
adding #include <vector>
or #include <vector.h>
in your sketch should solve that
please provide me a functional sketch
I don't have your exact model of makerfabs board so I'm afraid the only help I can provide is theoritical.
so for the functional example i mean just for tft_espi with loading from sd
and i tried that with #include
I'm sorry I can't help you more than that, good luck in your research!
i managed to get it to compile and init both sd and TFT_eSPI successfully but it only displays a black screen with the serial output showing that it opens the file successfully (i combined the GIFDraw.ino from TFT_eSPI_memmory and the rest from adafruit_gfx_sdcard) the code:
#include <AnimatedGIF.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include <SD.h>
#include <FS.h>
SPIClass spiSD(HSPI);
#define BUFFER_SIZE 256
#define BUILTIN_SDCARD 4
#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;
TFT_eSPI tft = TFT_eSPI();
AnimatedGIF gif;
File f;
#define DISPLAY_WIDTH tft.width()
#define DISPLAY_HEIGHT tft.height()
void * GIFOpenFile(const char *fname, int32_t *pSize)
{
f = SD.open(fname);
if (f)
{
*pSize = f.size();
return (void *)&f;
}
return NULL;
} /* GIFOpenFile() */
void GIFCloseFile(void *pHandle)
{
File *f = static_cast<File *>(pHandle);
if (f != NULL)
f->close();
} /* GIFCloseFile() */
int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
{
int32_t iBytesRead;
iBytesRead = iLen;
File *f = static_cast<File *>(pFile->fHandle);
// Note: If you read a file all the way to the last byte, seek() stops working
if ((pFile->iSize - pFile->iPos) < iLen)
iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
if (iBytesRead <= 0)
return 0;
iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
pFile->iPos = f->position();
return iBytesRead;
} /* GIFReadFile() */
int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
{
int i = micros();
File *f = static_cast<File *>(pFile->fHandle);
f->seek(iPosition);
pFile->iPos = (int32_t)f->position();
i = micros() - i;
// Serial.printf("Seek time = %d us\n", i);
return pFile->iPos;
} /* GIFSeekFile() */
void GIFDraw(GIFDRAW *pDraw)
{
uint8_t *s;
uint16_t *d, *usPalette;
int x, y, iWidth, iCount;
// Display bounds check 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() */
void setup() {
Serial.begin(115200);
while (!Serial);
// Note - some systems (ESP32?) require an SPI.begin() before calling SD.begin()
// this code was tested on a Teensy 4.1 board
if(!SD.begin(BUILTIN_SDCARD, spiSD))
{
Serial.println("SD Card mount failed!");
return;
}
else
{
Serial.println("SD Card mount succeeded!");
}
// put your setup code here, to run once:
tft.begin();
tft.setRotation(1);
tft.fillScreen(0);
gif.begin(LITTLE_ENDIAN_PIXELS);
Serial.print("SD Card Type: ");
uint8_t cardType = SD.cardType();
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void loop() {
// put your main code here, to run repeatedly:
// Serial.println("About to call gif.open");
//listDir(SD, "/", 0);
if (gif.open("/et.gif", GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))
{
GIFINFO gi;
Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
if (gif.getInfo(&gi)) {
Serial.printf("frame count: %d\n", gi.iFrameCount);
Serial.printf("duration: %d ms\n", gi.iDuration);
Serial.printf("max delay: %d ms\n", gi.iMaxDelay);
Serial.printf("min delay: %d ms\n", gi.iMinDelay);
}
while (gif.playFrame(true, NULL))
{
}
gif.close();
}
else
{
Serial.printf("Error opening file = %d\n", gif.getLastError());
while (1)
{};
}
}
and i use platformio my screen is a ili9488 with the resolution of 480x320
and please reopen this issue
This issue isn't a bug in AnimatedGIF and isn't really a feature request. I publish my own LCD library (bb_spi_lcd) that has plenty of examples in combination with this code. I don't use TFT_eSPI. You're free to add this to his examples if you think it's necessary.
does bb_spi_lcd support the ILI9488 in hardware spi mode (the configuration of my board)
Yes
ok
it would be nice if a example for tft_espi gif from sd example would be provided