aboutsummaryrefslogtreecommitdiff
path: root/examples/ChainedPanelsScreenBuffer
diff options
context:
space:
mode:
authorEmil Muratov <gpm@hotplug.ru>2022-01-10 22:14:58 +0300
committerEmil Muratov <gpm@hotplug.ru>2022-01-10 22:14:58 +0300
commit9cc68377bbf3b37d89d8baa9b2a9ab27fbb7c2d1 (patch)
tree12dfd9bb74651bfedd8cbc05ed00ed4d60996d92 /examples/ChainedPanelsScreenBuffer
parent7f8050763f036e83f881728fc66c56fff0e32381 (diff)
parent4dd02329c83671055bcd3ee4918551c47ab6458a (diff)
Merge branch 'master' into dev
Diffstat (limited to 'examples/ChainedPanelsScreenBuffer')
-rw-r--r--examples/ChainedPanelsScreenBuffer/ChainedPanelsScreenBuffer.ino146
-rw-r--r--examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.cpp116
-rw-r--r--examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.h51
3 files changed, 313 insertions, 0 deletions
diff --git a/examples/ChainedPanelsScreenBuffer/ChainedPanelsScreenBuffer.ino b/examples/ChainedPanelsScreenBuffer/ChainedPanelsScreenBuffer.ino
new file mode 100644
index 0000000..b5de3c3
--- /dev/null
+++ b/examples/ChainedPanelsScreenBuffer/ChainedPanelsScreenBuffer.ino
@@ -0,0 +1,146 @@
+/*************************************************************************
+ * IMPORANT PLEASE READ THE INFORMATION BELOW!
+ *
+ * This example implements a 'pixel buffer' which is essentally an
+ * off-screen copy of what is intended to be sent to output (LED panels)
+ *
+ * This essentially means DOUBLE THE AMOUNT OF MEMORY is required to
+ * to store the off-screen image/pixel/display buffer WITH a similar
+ * amount of memory used for the DMA output buffer for the physical panels.
+ *
+ * This means the practical resolution you will be able to output with the
+ * ESP32 will be CUT IN HALF. Do not try to run huge chains of
+ * LED Matrix Panels using this buffer, you will run out of memory.
+ *
+ * Please DO NOT raise issues @ github about running out of memory,
+ * we can't do anything about it. It's an ESP32, not a Raspberry Pi!
+ *
+ *************************************************************************/
+
+/* Use the FastLED_Pixel_Buffer class to handle panel chaining
+ * (it's based on the VirtualMatrixPanel class) AND also create an
+ * off-screen CRGB FastLED pixel buffer.
+ */
+#include "FastLED_Pixel_Buffer.h"
+
+ // Panel configuration
+ #define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module.
+ #define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
+
+ #define NUM_ROWS 1 // Number of rows of chained INDIVIDUAL PANELS
+ #define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW
+
+ // Change this to your needs, for details please read the PDF in
+ // the 'ChainedPanels'example folder!
+ #define SERPENT true
+ #define TOPDOWN false
+
+ // placeholder for the matrix object
+ MatrixPanel_I2S_DMA *dma_display = nullptr;
+
+ // placeholder for the virtual display object
+ VirtualMatrixPanel_FastLED_Pixel_Buffer *FastLED_Pixel_Buff = nullptr;
+
+ /******************************************************************************
+ * Setup!
+ ******************************************************************************/
+ void setup()
+ {
+ delay(250);
+
+ Serial.begin(115200);
+ Serial.println(""); Serial.println(""); Serial.println("");
+ Serial.println("*****************************************************");
+ Serial.println("* FastLED Pixel BufferDemonstration *");
+ Serial.println("*****************************************************");
+
+/*
+ // 62x32 1/8 Scan Panels don't have a D and E pin!
+
+ HUB75_I2S_CFG::i2s_pins _pins = {
+ R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN,
+ A_PIN, B_PIN, C_PIN, D_PIN, E_PIN,
+ LAT_PIN, OE_PIN, CLK_PIN
+ };
+*/
+ HUB75_I2S_CFG mxconfig(
+ PANEL_RES_X, // DO NOT CHANGE THIS
+ PANEL_RES_Y, // DO NOT CHANGE THIS
+ NUM_ROWS*NUM_COLS // DO NOT CHANGE THIS
+ //,_pins // Uncomment to enable custom pins
+ );
+
+ mxconfig.clkphase = false; // Change this if you see pixels showing up shifted wrongly by one column the left or right.
+ //mxconfig.driver = HUB75_I2S_CFG::FM6126A; // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object
+
+ // Do NOT use mxconfig.double_buffer when using this pixel buffer.
+
+ // OK, now we can create our matrix object
+ dma_display = new MatrixPanel_I2S_DMA(mxconfig);
+
+ // let's adjust default physical panel brightness to about 75%
+ dma_display->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100%
+
+ // Allocate memory and start DMA electrical output to physical panels
+ if( not dma_display->begin() )
+ Serial.println("****** !KABOOM! I2S memory allocation failed ***********");
+
+ dma_display->clearScreen();
+ delay(500);
+
+ // NOW, create the 'Virtual Matrix Panel' class with a FastLED Pixel Buffer! Pass it a dma_display hardware library pointer to use.
+ FastLED_Pixel_Buff = new VirtualMatrixPanel_FastLED_Pixel_Buffer((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
+
+ if( not FastLED_Pixel_Buff->allocateMemory() )
+ Serial.println("****** !KABOOM! Unable to find enough memory for the FastLED pixel buffer! ***********");
+
+ }
+
+
+ // Borrowed from the SimpleTextShapes example.
+ uint16_t colorWheel(uint8_t pos) {
+ if(pos < 85) {
+ return dma_display->color565(pos * 3, 255 - pos * 3, 0);
+ } else if(pos < 170) {
+ pos -= 85;
+ return dma_display->color565(255 - pos * 3, 0, pos * 3);
+ } else {
+ pos -= 170;
+ return dma_display->color565(0, pos * 3, 255 - pos * 3);
+ }
+ }
+
+ /* A crap demonstration of using the pixel buffer.
+ * 1) Draw text at an incrementing (going down) y coordinate
+ * 2) Move down a pixel row
+ * 3) Draw the text again, fade the 'old' pixels. Using the pixel buffer to update all pixels on screen.
+ * 4) 'show' (send) the pixel buffer to the DMA output.
+ * 5) LOOP
+ */
+
+ uint8_t y_coord = 0;
+ uint8_t wheel = 0;
+
+ void loop()
+ {
+ // draw text with a rotating colour
+ FastLED_Pixel_Buff->dimAll(200); // Dim all pixels by 250/255
+
+ FastLED_Pixel_Buff->setTextSize(1); // size 1 == 8 pixels high
+ FastLED_Pixel_Buff->setTextWrap(false); // Don't wrap at end of line - will do ourselves
+
+ FastLED_Pixel_Buff->setCursor(FastLED_Pixel_Buff->width()/4, y_coord); // start at top left, with 8 pixel of spacing
+ FastLED_Pixel_Buff->setTextColor(colorWheel(wheel++));
+
+ FastLED_Pixel_Buff->print("MythicalForce");
+
+ FastLED_Pixel_Buff->show(); // IMPORTANT -> SEND Pixel Buffer to DMA / Panel Output!
+
+ y_coord++;
+
+ if ( y_coord >= FastLED_Pixel_Buff->height())
+ y_coord = 0;
+
+ delay(35);
+
+ } // end loop
diff --git a/examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.cpp b/examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.cpp
new file mode 100644
index 0000000..79e19c9
--- /dev/null
+++ b/examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.cpp
@@ -0,0 +1,116 @@
+/**
+ * Experimental layer class to do play with pixel in an off-screen buffer before painting to the DMA
+ *
+ * Requires FastLED
+ *
+ * Faptastic 2020-2021
+ **/
+
+#include "FastLED_Pixel_Buffer.h"
+
+/**
+ * The one for 256+ matrices
+ * otherwise this:
+ * for (uint8_t i = 0; i < MATRIX_WIDTH; i++) {}
+ * turns into an infinite loop
+ */
+inline uint16_t VirtualMatrixPanel_FastLED_Pixel_Buffer::XY16( uint16_t x, uint16_t y) {
+
+ if (x >= virtualResX) return 0;
+ if (y >= virtualResY) return 0;
+
+ return (y * virtualResX) + x + 1; // everything offset by one to compute out of bounds stuff - never displayed by ShowFrame()
+}
+
+// For adafruit
+void VirtualMatrixPanel_FastLED_Pixel_Buffer::drawPixel(int16_t x, int16_t y, uint16_t color) {
+
+ //Serial.println("calling our drawpixel!");
+
+ // 565 color conversion
+ uint8_t r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6;
+ uint8_t g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6;
+ uint8_t b = (((color & 0x1F) * 527) + 23) >> 6;
+
+ this->drawPixel(x, y, CRGB(r,g,b));
+}
+
+void VirtualMatrixPanel_FastLED_Pixel_Buffer::drawPixel(int16_t x, int16_t y, int r, int g, int b) {
+ this->drawPixel(x, y, CRGB(r,g,b));
+}
+
+// We actually just draw to ourselves... to our buffer
+void VirtualMatrixPanel_FastLED_Pixel_Buffer::drawPixel(int16_t x, int16_t y, CRGB color)
+{
+ //Serial.printf("updated x y : %d %d", x, y);
+ buffer[XY16(x,y)] = color;
+}
+
+CRGB VirtualMatrixPanel_FastLED_Pixel_Buffer::getPixel(int16_t x, int16_t y)
+{
+ return buffer[XY16(x,y)];
+}
+
+/**
+ * Dim all the pixels on the layer.
+ */
+void VirtualMatrixPanel_FastLED_Pixel_Buffer::dimAll(byte value) {
+
+ //Serial.println("performing dimall");
+ // nscale8 max value is 255, or it'll flip back to 0
+ // (documentation is wrong when it says x/256), it's actually x/255
+ /*
+ for (int y = 0; y < LAYER_HEIGHT; y++) {
+ for (int x = 0; x < LAYER_WIDTH; x++) {
+ pixels->data[y][x].nscale8(value);
+ }}
+ */
+ dimRect(0,0, virtualResX, virtualResY, value);
+}
+
+/**
+ * Dim all the pixels in a rectangular option of the layer the layer.
+ */
+void VirtualMatrixPanel_FastLED_Pixel_Buffer::dimRect(int16_t x, int16_t y, int16_t w, int16_t h, byte value) {
+ for (int16_t i = x; i < x + w; i++)
+ {
+ for (int16_t j = y; j < y + h; j++)
+ {
+ buffer[XY16(i,j)].nscale8(value);
+ }
+ }
+}
+
+void VirtualMatrixPanel_FastLED_Pixel_Buffer::clear() {
+ memset(buffer, CRGB(0,0,0), (virtualResX * virtualResY) );
+}
+
+/**
+ * Actually Send the CRGB FastLED buffer to the DMA engine / Physical Panels!
+ * Do this via the underlying 'VirtualMatrixPanel' that does all the pixel-remapping for
+ * all sorts of chained panels, and panel scan types.
+ */
+void VirtualMatrixPanel_FastLED_Pixel_Buffer::show() {
+
+ //Serial.println("Doing Show");
+
+ CRGB _pixel = 0;
+ for (int16_t y = 0; y < virtualResY; y++) {
+ for (int16_t x = 0; x < virtualResX; x++)
+ {
+ //VirtualMatrixPanel::getCoords(x, y); // call to base to update coords for chaining approach
+ _pixel = buffer[XY16(x,y)];
+ drawPixelRGB888( x, y, _pixel.r, _pixel.g, _pixel.b); // call VirtualMatrixPanel::drawPixelRGB888(...)
+ //drawPixelRGB888( x, y, 0, 0, 128); // call VirtualMatrixPanel::drawPixelRGB888(...)
+ } // end loop to copy fast led to the dma matrix
+ }
+
+} // show
+
+/**
+ * Cleanup should we delete this buffer class. Unlikely during runtime.
+ */
+VirtualMatrixPanel_FastLED_Pixel_Buffer::~VirtualMatrixPanel_FastLED_Pixel_Buffer(void)
+{
+ delete(buffer);
+} \ No newline at end of file
diff --git a/examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.h b/examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.h
new file mode 100644
index 0000000..28db7d5
--- /dev/null
+++ b/examples/ChainedPanelsScreenBuffer/FastLED_Pixel_Buffer.h
@@ -0,0 +1,51 @@
+#ifndef VIRTUAL_MATRIX_PANEL_FASTLED_LAYER
+#define VIRTUAL_MATRIX_PANEL_FASTLED_LAYER
+
+#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>
+#include <FastLED.h>
+
+class VirtualMatrixPanel_FastLED_Pixel_Buffer : public VirtualMatrixPanel
+{
+ public:
+ using VirtualMatrixPanel::VirtualMatrixPanel; // perform VirtualMatrixPanel class constructor
+
+ bool allocateMemory() // allocate memory
+ {
+ // https://www.geeksforgeeks.org/how-to-declare-a-2d-array-dynamically-in-c-using-new-operator/
+ buffer = new CRGB[virtualResX * virtualResY]; // These are defined in the underliny
+
+ if (!buffer) { return false; }
+
+ Serial.printf("Allocated %d bytes of memory for pixel buffer.\r\n", sizeof(CRGB)*((virtualResX * virtualResY)+1));
+ this->clear();
+
+ return true;
+
+ } // end Buffer
+
+ virtual void drawPixel(int16_t x, int16_t y, uint16_t color); // overwrite adafruit implementation
+ void drawPixel(int16_t x, int16_t y, int r, int g, int b); // Buffer implementation
+ void drawPixel(int16_t x, int16_t y, CRGB color); // Buffer implementation
+ CRGB getPixel(int16_t x, int16_t y); // Returns a pixel value from the buffer.
+
+
+ void dimAll(byte value);
+ void dimRect(int16_t x, int16_t y, int16_t w, int16_t h, byte value);
+
+ void clear();
+
+ void show(); // Send buffer to physical hardware / DMA engine.
+
+ // Release Memory
+ ~VirtualMatrixPanel_FastLED_Pixel_Buffer(void);
+
+ protected:
+ uint16_t XY16( uint16_t x, uint16_t y);
+
+ private:
+ CRGB* buffer = nullptr;
+};
+
+
+
+#endif \ No newline at end of file