Closed ifengchao closed 2 years ago
I need a bit more detail to see why it's crashing. I can tell you already that the 8266 is troublesome because of the way it uses RAM to execute code and can have an acute lack of RAM at inopportune times. If you could, I would try the same code on something with more RAM, like the ESP32. If the ESP8266 is all you've got, then try by a process of elimination such as having an empty GIFDraw() callback as your first test. If that works, then you know it's in your code that the problem lies.
Thanks for the quick reply. Here is the main.cpp in my PlatformIO project.
// TFT_eSPI_memory // // Example sketch which shows how to display an // animated GIF image stored in FLASH memory // // written by Larry Bank // bitbank@pobox.com // // Adapted by Bodmer for the TFT_eSPI Arduino library: // https://github.com/Bodmer/TFT_eSPI // // To display a GIF from memory, a single callback function // must be provided - GIFDRAW // This function is called after each scan line is decoded // and is passed the 8-bit pixels, RGB565 palette and info // about how and where to display the line. The palette entries // can be in little-endian or big-endian order; this is specified // in the begin() method. // // The AnimatedGIF class doesn't allocate or free any memory, but the // instance data occupies about 22.5K of RAM.
//#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
// Load GIF library
AnimatedGIF gif;
// Example AnimatedGIF library images
//#include "../test_images/homer.h" //#include "../test_images/homer_tiny.h" //#include "../test_images/pattern.h"
// ESP32 40MHz SPI single frame rendering performance // Note: no DMA performance gain on smaller images or transparent pixel GIFs
//#define GIF_IMAGE ucHomer // No DMA 162 fps, DMA: 141 fps //#define GIF_IMAGE homer_tiny // No DMA 564 fps, DMA: 481 fps //#define GIF_IMAGE ucPattern // No DMA 90 fps, DMA: 78 fps
TFT_eSPI tft = TFT_eSPI();
void setup() { Serial.begin(115200);
tft.begin();
tft.initDMA();
tft.setRotation(1); tft.fillScreen(TFT_BLACK);
gif.begin(LITTLE_ENDIAN_PIXELS); }
// GIFDraw is called by AnimatedGIF library frame to screen
uint16_t usTemp[2][BUFFER_SIZE]; // Global to support DMA use
uint16_t usTemp[1][BUFFER_SIZE]; // Global to support DMA use
bool dmaBuf = 0;
// Draw a line of image directly on the LCD void GIFDraw(GIFDRAW pDraw) { return ; 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++];
tft.dmaWait();
tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
dmaBuf = !dmaBuf;
tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
tft.pushPixels(&usTemp[0][0], iCount);
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++];
tft.dmaWait();
tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
dmaBuf = !dmaBuf;
tft.pushPixels(&usTemp[0][0], iCount);
iWidth -= iCount;
}
} } / GIFDraw() /
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 Serial.printf(" tft size = %d x %d\n",tft.width(), tft.height()); while (gif.playFrame(true, NULL)) { Serial.printf(" yield\n"); yield(); } gif.close(); tft.endWrite(); // Release TFT chip select for other SPI devices } }
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"); } }
Empty GIFDraw() will still crash, but if i comment "while (gif.playFrame(false, NULL))" in loop(),crash stopped.
I don't use platformio, so I don't know if that's affecting things, but I'm still not seeing anything that could help me diagnose the problem. If you can zip up the whole project including the GIF files you're using, I can take a look this weekend. Email it to bitbank@pobox.com
I don't use platformio, so I don't know if that's affecting things, but I'm still not seeing anything that could help me diagnose the problem. If you can zip up the whole project including the GIF files you're using, I can take a look this weekend. Email it to bitbank@pobox.com
Actually main.cpp could be renamed to main.ino (almost the same with your example code in TFT_eSPI_memory.ino) and open in Arduino IDE, the gif image i'm using is defined in #include "../test_images/badgers.h". I tried in Arduino, but also crashed. Do you happen to have arduino enviroment and an esp8266 board, it's easy to reproduce the crash.
I hope this will not take you too much time, if it could not be reproduced in your enviroment, i may move to esp32 few days later, need to do some screen soldering work. :)
I don't use platformio, so I don't know if that's affecting things, but I'm still not seeing anything that could help me diagnose the problem. If you can zip up the whole project including the GIF files you're using, I can take a look this weekend. Email it to bitbank@pobox.com
Another thing i forgot to clarify is i made some changes to User_Setup.h in TFT_eSPI library to make the st7789 spi screen work, and it worked with test code without AnimatedGif library. So i think this part may not be the reason caused crash.
I do have an 8266 in my collection of parts; I'll give it a try later today. FYI - I have investigated these kinds of problems before across various github repos that I've released and 99.9999999% of the time, the problem is not with my code. In this case, my best guess is that you're running out of RAM somewhere; maybe even a stack overrun.
Found the issue... ESP8266 is a Harvard architecture and my generic open function treats the source memory like RAM. In my JPEG decoder I added a specific function to deal with FLASH reads from a different address space. A quick fix for you is to edit gif.inl and change the memcpy() in readMem() to be memcpy_P(). I'll have to add a new function called "openFLASH()" to deal with the 8266 specifically.
Crash fix confirmed, now it can display small smooth gif animations. Great job, i'll do more test. Thanks Larry .
I did a new release (1.4.5) which adds the openFLASH method
Hi, nice work first !
I think it crashed here in git.playFrame(true,NULL);
Changes i made: gif.begin(LITTLE_ENDIAN_PIXELS);// little endian for esp8266, board esp-12e void GIFDraw(GIFDRAW *pDraw) copyed from GIFDRAW.ino
define GIF_IMAGE ucBadgers // No DMA 63 fps, DMA: 71fps // tested this gif image
TFT Screen is st7789 240x240 size.
Logs printed on serial console: Successfully opened GIF; Canvas size = 160 x 120 tft size = 240 x 240
--------------- CUT HERE FOR EXCEPTION DECODER --------------- ...
Any help will be appreciated, thanks.