mirror of
https://github.com/thelastoutpostworkshop/ESP32ManyRoundScreenTest.git
synced 2025-09-26 23:09:22 +08:00
initial
This commit is contained in:
parent
a5f57cf1d3
commit
8f489017ac
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
build
|
||||
.vscode
|
72
ESP32ManyRoundScreenTest.ino
Normal file
72
ESP32ManyRoundScreenTest.ino
Normal file
@ -0,0 +1,72 @@
|
||||
// Animated GIF with Multiple Displays
|
||||
//
|
||||
// ESP32 40MHz SPI single frame rendering performance
|
||||
|
||||
#include <SPI.h>
|
||||
#include <TFT_eSPI.h> // Install this library with the Arduino IDE Library Manager
|
||||
#include <AnimatedGIF.h> // Install this library with the Arduino IDE Library Manager
|
||||
#include "images/darthvader.h"
|
||||
#include "images/x_wing.h"
|
||||
#include "images/nostromo.h"
|
||||
#include "images/hud_6.h"
|
||||
|
||||
const int NUM_DISPLAYS = 3; // Adjust this value based on the number of displays
|
||||
AnimatedGIF gifs[NUM_DISPLAYS];
|
||||
|
||||
// Define CS pins for all displays
|
||||
const int CS_PINS[NUM_DISPLAYS] = {19,22,21}; // Add more pins if you have more displays
|
||||
|
||||
// Define the images for all displays
|
||||
const uint8_t *GIF_IMAGES[NUM_DISPLAYS] = {x_wing,darthvader,hud_6}; // Add more images if needed
|
||||
const size_t GIF_SIZES[NUM_DISPLAYS] = {sizeof(x_wing),sizeof(darthvader),sizeof(hud_6)}; // Add more sizes if needed
|
||||
|
||||
TFT_eSPI tft;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
tft.init();
|
||||
for (int i = 0; i < NUM_DISPLAYS; i++)
|
||||
{
|
||||
pinMode(CS_PINS[i], OUTPUT);
|
||||
digitalWrite(CS_PINS[i], HIGH); // Deselect the display
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_DISPLAYS; i++)
|
||||
{
|
||||
digitalWrite(CS_PINS[i], LOW); // Select the display
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setRotation(2); // Adjust Rotation of your screen (0-3)
|
||||
gifs[i].begin(BIG_ENDIAN_PIXELS);
|
||||
if (!gifs[i].open((uint8_t *)GIF_IMAGES[i], GIF_SIZES[i], GIFDraw))
|
||||
{
|
||||
Serial.printf("Failed to open GIF%d\n", i + 1);
|
||||
Serial.printf("Last Error=%d", gifs[i].getLastError());
|
||||
Serial.printf("Image size=%d", sizeof(GIF_IMAGES[i]));
|
||||
}
|
||||
digitalWrite(CS_PINS[i], HIGH); // Deselect the display
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
for (int i = 0; i < NUM_DISPLAYS; i++)
|
||||
{
|
||||
digitalWrite(CS_PINS[i], LOW); // Select the display
|
||||
|
||||
tft.startWrite();
|
||||
|
||||
int res = gifs[i].playFrame(false, NULL);
|
||||
if (res == 0)
|
||||
{
|
||||
// If no more frames are available, reset the GIF to the beginning
|
||||
gifs[i].reset();
|
||||
gifs[i].playFrame(false, NULL);
|
||||
}
|
||||
|
||||
tft.endWrite();
|
||||
|
||||
digitalWrite(CS_PINS[i], HIGH); // Deselect the display
|
||||
}
|
||||
}
|
131
GIFDraw.ino
Normal file
131
GIFDraw.ino
Normal file
@ -0,0 +1,131 @@
|
||||
// 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() */
|
7077
images/darthvader.h
Normal file
7077
images/darthvader.h
Normal file
File diff suppressed because it is too large
Load Diff
57196
images/hud_1.h
Normal file
57196
images/hud_1.h
Normal file
File diff suppressed because it is too large
Load Diff
45061
images/hud_2.h
Normal file
45061
images/hud_2.h
Normal file
File diff suppressed because it is too large
Load Diff
60361
images/hud_5.h
Normal file
60361
images/hud_5.h
Normal file
File diff suppressed because it is too large
Load Diff
19389
images/hud_6.h
Normal file
19389
images/hud_6.h
Normal file
File diff suppressed because it is too large
Load Diff
55191
images/hud_7.h
Normal file
55191
images/hud_7.h
Normal file
File diff suppressed because it is too large
Load Diff
15313
images/hyperspace.h
Normal file
15313
images/hyperspace.h
Normal file
File diff suppressed because it is too large
Load Diff
23045
images/nostromo.h
Normal file
23045
images/nostromo.h
Normal file
File diff suppressed because it is too large
Load Diff
26996
images/x_wing.h
Normal file
26996
images/x_wing.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user