Hi Jean-Marc,
I'm trying to use your library together with an eInk display to display gif files from an SD card (using the AnimatedGIF library - I increased the max image size buffer to 880 in the header fileThis text will be hidden). In my case I'm using a 7.5 inch b/w 880x528 from Waveshare with the e-Paper driver HAT and an ESP32 Adafruit HUZZAH32.
When reading images from an SD card, some are displayed as the full image, but most of the images are displayed only partially (1 out of 4 pages) and during the picture loop the connection to the SD card is lost and I have to fully restart the board (it does not crash though). A wake up from deep sleep will not be enough to reconnect the SD card.
This code will always work (reading the image and parsing the gif) as long as it is not painted using display.drawPixel in the GIFDraw function.
Meaning, when the display.drawPixel lines are removed, it will work, otherwise, it will cause the above described issue.
I assume this is a problem related to memory, do you have any ideas what could cause the issue.
Best
#include <SPI.h>
#include <SD.h>
/* Animated GIF */
#include "src/AnimatedGIF/AnimatedGIF.h"
AnimatedGIF gif;
/* Enable or disable GxEPD2_GFX base class */
#define ENABLE_GxEPD2_GFX 1
#define DISPLAY_WIDTH 880
#define DISPLAY_HEIGHT 528
/* Display Dependencies */
#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <U8g2_for_Adafruit_GFX.h>
#define MAX_DISPLAY_BUFFER_SIZE 32768ul
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
/* Connections for Adafruit Feather */
static const uint8_t EPD_BUSY = 32; // to EPD BUSY
static const uint8_t EPD_CS = 15; // to EPD CS
static const uint8_t EPD_RST = 27; // to EPD RST
static const uint8_t EPD_DC = 33; // to EPD DC
static const uint8_t EPD_SCK = 5; // to EPD CLK
static const uint8_t EPD_MISO = 19; // Master-In Slave-Out not used, as no data from display
static const uint8_t EPD_MOSI = 18; // to EPD DIN
/* Mapping of the ESP32 Driver Board */
GxEPD2_3C < GxEPD2_750c_Z90, GxEPD2_750c_Z90::HEIGHT / 4 > display(GxEPD2_750c_Z90(/*CS=D8*/ EPD_CS, /*DC=D3*/ EPD_DC, /*RST=D4*/ EPD_RST, /*BUSY=D2*/ EPD_BUSY)); // GDEH075Z90 880x528
U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;
/* Files */
File f;
/* Setup */
void setup()
{
// Serial Port
Serial.begin(115200);
Serial.println();
Serial.println(F("Setup"));
// Display
display.init(115200);
display.setRotation(0);
display.setFullWindow();
u8g2Fonts.begin(display);
// Variables
int error = -1;
// Prepare GIF
gif.begin(LITTLE_ENDIAN_PIXELS); //BIG_ENDIAN_PIXELS
// SD Card
if (!SD.begin())
{
Serial.println(F("Error: SD not initialization failed!"));
while(1);
}
Serial.print("Start Free Heap: ");
Serial.println(ESP.getFreeHeap());
if ( gif.open( "/movie/thumbnail013.gif" , GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw) )
{
GIFINFO gi;
Serial.printf("GIF opened (%dx%d)\n", gif.getCanvasWidth(), gif.getCanvasHeight());
if (gif.getInfo(&gi)) {
Serial.printf("Frames: %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);
}
}
else{
Serial.print(F("GIF display Error: "));
Serial.println( gif.getLastError() );
}
// Build the View
int page = 1;
display.firstPage();
do
{
Serial.printf("Page: %d\n", page);
while (gif.playFrame(true, NULL))
{
if( gif.getLastError() > 0 )
{
Serial.printf("Issue: %d\n", gif.getLastError() );
break;
}
}
gif.reset();
Serial.printf("Free Heap: %d bytes\n", ESP.getFreeHeap() );
page++;
}
while (display.nextPage());
gif.close();
/* Power off the display and put ESP32 into sleep mode */
display.powerOff();
int delayTime = 60 * 60 * 24; // Deep sleep for a day;
esp_sleep_enable_timer_wakeup( 120 * 1000000LL);
Serial.printf("Deep-sleep: %d seconds\n", delayTime );
esp_deep_sleep_start();
}
/* Program Loop */
void loop()
{
}
/* Open file from SD card */
void * GIFOpenFile(const char *fname, int32_t *pSize)
{
f = SD.open(fname);
// Serial.println("GIF: Open File...");
if (f)
{
*pSize = f.size();
return (void *)&f;
}
return NULL;
} /* GIFOpenFile() */
/* Close file */
void GIFCloseFile(void *pHandle)
{
// Serial.println("GIF: Close File...");
File *f = static_cast<File *>(pHandle);
if (f != NULL)
f->close();
} /* GIFCloseFile() */
/* Read a given GIF file */
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() */
/* Seek a position in a given GIF file */
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() */
// Draw a line of image directly on the display
void GIFDraw(GIFDRAW *pDraw)
{
int x, y, iWidth;
iWidth = pDraw->iWidth;
if (iWidth + pDraw->iX > DISPLAY_WIDTH)
iWidth = DISPLAY_WIDTH - pDraw->iX;
y = pDraw->iY + pDraw->y; // current line
if (y >= DISPLAY_HEIGHT || pDraw->iX >= DISPLAY_WIDTH || iWidth < 1)
return;
String out = "";
for (x=0; x<iWidth; x++)
{
if( pDraw->pPixels[x] == 0)
{
display.drawPixel(x, y, GxEPD_BLACK);
}
else{
display.drawPixel(x, y, GxEPD_WHITE);
}
}
} /* GIFDraw() */