From 7c2d527dd8d92efe03d71b5743f46f230b309758 Mon Sep 17 00:00:00 2001 From: mrfaptastic <12006953+mrfaptastic@users.noreply.github.com> Date: Sun, 2 Apr 2023 13:12:53 +0100 Subject: [PATCH] Cleanup --- .../3_DoubleBuffer.ino} | 22 +- .../4_HueValueSpectrumDemo.ino | 75 ---- .../4_OtherShiftDriverPanel.ino} | 40 +- .../FM6126A.md | 0 .../README.md | 0 src/ESP32-VirtualMatrixPanel-I2S-DMA.h-old | 363 ------------------ 6 files changed, 40 insertions(+), 460 deletions(-) rename examples/{BouncingSquares/BouncingSquares.ino => 3_DoubleBuffer/3_DoubleBuffer.ino} (74%) delete mode 100644 examples/4_HueValueSpectrumDemo/4_HueValueSpectrumDemo.ino rename examples/{3_FM6126Panel/3_FM6126Panel.ino => 4_OtherShiftDriverPanel/4_OtherShiftDriverPanel.ino} (74%) rename examples/{3_FM6126Panel => 4_OtherShiftDriverPanel}/FM6126A.md (100%) rename examples/{3_FM6126Panel => 4_OtherShiftDriverPanel}/README.md (100%) delete mode 100644 src/ESP32-VirtualMatrixPanel-I2S-DMA.h-old diff --git a/examples/BouncingSquares/BouncingSquares.ino b/examples/3_DoubleBuffer/3_DoubleBuffer.ino similarity index 74% rename from examples/BouncingSquares/BouncingSquares.ino rename to examples/3_DoubleBuffer/3_DoubleBuffer.ino index 6a01225..5a41d67 100644 --- a/examples/BouncingSquares/BouncingSquares.ino +++ b/examples/3_DoubleBuffer/3_DoubleBuffer.ino @@ -1,3 +1,9 @@ +// Example uses the following configuration: mxconfig.double_buff = true; +// to enable double buffering, which means display->flipDMABuffer(); is required. + +// Bounce squares around the screen, doing the re-drawing in the background back-buffer. +// Double buffering is not always required in reality. + #include MatrixPanel_I2S_DMA *display = nullptr; @@ -32,14 +38,14 @@ void setup() Serial.println("...Starting Display"); HUB75_I2S_CFG mxconfig; - //mxconfig.double_buff = true; // Turn of double buffer - mxconfig.clkphase = false; + mxconfig.double_buff = true; // <------------- Turn on double buffer + //mxconfig.clkphase = false; // OK, now we can create our matrix object display = new MatrixPanel_I2S_DMA(mxconfig); display->begin(); // setup display with pins as pre-defined in the library - // Create some Squares + // Create some random squares for (int i = 0; i < numSquares; i++) { Squares[i].square_size = random(2,10); @@ -47,8 +53,6 @@ void setup() Squares[i].ypos = random(0, display->height() - Squares[i].square_size); Squares[i].velocityx = static_cast (rand()) / static_cast (RAND_MAX); Squares[i].velocityy = static_cast (rand()) / static_cast (RAND_MAX); - //Squares[i].xdir = (random(2) == 1) ? true:false; - //Squares[i].ydir = (random(2) == 1) ? true:false; int random_num = random(6); Squares[i].colour = colours[random_num]; @@ -57,9 +61,11 @@ void setup() void loop() { - display->flipDMABuffer(); // not used if double buffering isn't enabled - delay(25); - display->clearScreen(); + + display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) + display->clearScreen(); // Now clear the back-buffer + + delay(16); // <----------- Shouldn't see this clearscreen occur as it happens on the back buffer when double buffering is enabled. for (int i = 0; i < numSquares; i++) { diff --git a/examples/4_HueValueSpectrumDemo/4_HueValueSpectrumDemo.ino b/examples/4_HueValueSpectrumDemo/4_HueValueSpectrumDemo.ino deleted file mode 100644 index e64d419..0000000 --- a/examples/4_HueValueSpectrumDemo/4_HueValueSpectrumDemo.ino +++ /dev/null @@ -1,75 +0,0 @@ -#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 PANEL_CHAIN 1 // Total number of panels chained one to another - -#include - -MatrixPanel_I2S_DMA *dma_display = nullptr; - -void setup() { - HUB75_I2S_CFG::i2s_pins _pins={ - 25, //R1_PIN, - 26, //G1_PIN, - 27, //B1_PIN, - 14, //R2_PIN, - 12, //G2_PIN, - 13, //B2_PIN, - 23, //A_PIN, - 19, //B_PIN, - 5, //C_PIN, - 17, //D_PIN, - 18, //E_PIN, - 4, //LAT_PIN, - 15, //OE_PIN, - 16, //CLK_PIN - }; - HUB75_I2S_CFG mxconfig( - PANEL_RES_X, // Module width - PANEL_RES_Y, // Module height - PANEL_CHAIN, // chain length - _pins // pin mapping - ); - //mxconfig.clkphase = false; - //mxconfig.driver = HUB75_I2S_CFG::FM6126A; - - // Display Setup - dma_display = new MatrixPanel_I2S_DMA(mxconfig); - dma_display->begin(); - dma_display->clearScreen(); -} - -void loop() { - // Canvas loop - float t = (float)(millis()%4000)/4000.f; - float tt = (float)((millis()%16000)/16000.f; - - for(int x = 0; x < PANEL_RES_X*PANEL_CHAIN; x++){ - // calculate the overal shade - float f = ((sin(tt-(float)x/PANEL_RES_Y/32.)*2.f*PI)+1)/2)*255; - // calculate hue spectrum into rgb - float r = max(min(cosf(2.f*PI*(t+((float)x/PANEL_RES_Y+0.f)/3.f))+0.5f,1.f),0.f); - float g = max(min(cosf(2.f*PI*(t+((float)x/PANEL_RES_Y+1.f)/3.f))+0.5f,1.f),0.f); - float b = max(min(cosf(2.f*PI*(t+((float)x/PANEL_RES_Y+2.f)/3.f))+0.5f,1.f),0.f); - - // iterate pixels for every row - for(int y = 0; y < PANEL_RES_Y; y++){ - if(y*2 < PANEL_RES_Y){ - // top-middle part of screen, transition of value - float t = (2.f*y+1)/PANEL_RES_Y; - dma_display->drawPixelRGB888(x,y, - (r*t)*f, - (g*t)*f, - (b*t)*f - ); - }else{ - // middle to bottom of screen, transition of saturation - float t = (2.f*(PANEL_RES_Y-y)-1)/PANEL_RES_Y; - dma_display->drawPixelRGB888(x,y, - (r*t+1-t)*f, - (g*t+1-t)*f, - (b*t+1-t)*f - ); - } - } - } -} diff --git a/examples/3_FM6126Panel/3_FM6126Panel.ino b/examples/4_OtherShiftDriverPanel/4_OtherShiftDriverPanel.ino similarity index 74% rename from examples/3_FM6126Panel/3_FM6126Panel.ino rename to examples/4_OtherShiftDriverPanel/4_OtherShiftDriverPanel.ino index 3b706e1..e62cecc 100644 --- a/examples/3_FM6126Panel/3_FM6126Panel.ino +++ b/examples/4_OtherShiftDriverPanel/4_OtherShiftDriverPanel.ino @@ -1,19 +1,30 @@ -// How to use this library with a FM6126 panel, thanks goes to: -// https://github.com/hzeller/rpi-rgb-led-matrix/issues/746 +/********************************************************************** + * The library by default supports simple 'shift register' based panels + * with A,B,C,D,E lines to select a specific row, but there are plenty + * of examples of new chips coming on the market that work different. + * + * Please search through the project's issues. For some of these chips + * (you will need to look at the back of your panel to identify), this + * library has workarounds. This can be configured through using one of: + + // mxconfig.driver = HUB75_I2S_CFG::FM6126A; + //mxconfig.driver = HUB75_I2S_CFG::ICN2038S; + //mxconfig.driver = HUB75_I2S_CFG::FM6124; + //mxconfig.driver = HUB75_I2S_CFG::MBI5124; + */ + #include #include #include //////////////////////////////////////////////////////////////////// -// FM6126 support is still experimental // Output resolution and panel chain length 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 PANEL_CHAIN 1 // Total number of panels chained one to another - // placeholder for the matrix object MatrixPanel_I2S_DMA *dma_display = nullptr; @@ -33,14 +44,6 @@ CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlend } void setup(){ - - /* - The configuration for MatrixPanel_I2S_DMA object is held in HUB75_I2S_CFG structure, - All options has it's predefined default values. So we can create a new structure and redefine only the options we need - - Please refer to the '2_PatternPlasma.ino' example for detailed example of how to use the MatrixPanel_I2S_DMA configuration - if you need to change the pin mappings etc. - */ HUB75_I2S_CFG mxconfig( PANEL_RES_X, // module width @@ -48,7 +51,12 @@ void setup(){ PANEL_CHAIN // Chain length ); - 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 + // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object + mxconfig.driver = HUB75_I2S_CFG::FM6126A; + //mxconfig.driver = HUB75_I2S_CFG::ICN2038S; + //mxconfig.driver = HUB75_I2S_CFG::FM6124; + //mxconfig.driver = HUB75_I2S_CFG::MBI5124; + // OK, now we can create our matrix object dma_display = new MatrixPanel_I2S_DMA(mxconfig); @@ -99,4 +107,8 @@ void loop(){ fps_timer = millis(); fps = 0; } -} \ No newline at end of file +} + + +// FM6126 panel , thanks goes to: +// https://github.com/hzeller/rpi-rgb-led-matrix/issues/746 diff --git a/examples/3_FM6126Panel/FM6126A.md b/examples/4_OtherShiftDriverPanel/FM6126A.md similarity index 100% rename from examples/3_FM6126Panel/FM6126A.md rename to examples/4_OtherShiftDriverPanel/FM6126A.md diff --git a/examples/3_FM6126Panel/README.md b/examples/4_OtherShiftDriverPanel/README.md similarity index 100% rename from examples/3_FM6126Panel/README.md rename to examples/4_OtherShiftDriverPanel/README.md diff --git a/src/ESP32-VirtualMatrixPanel-I2S-DMA.h-old b/src/ESP32-VirtualMatrixPanel-I2S-DMA.h-old deleted file mode 100644 index cf5324a..0000000 --- a/src/ESP32-VirtualMatrixPanel-I2S-DMA.h-old +++ /dev/null @@ -1,363 +0,0 @@ -#ifndef _ESP32_VIRTUAL_MATRIX_PANEL_I2S_DMA -#define _ESP32_VIRTUAL_MATRIX_PANEL_I2S_DMA - -/******************************************************************* - Class contributed by Brian Lough, and expanded by Faptastic. - - Originally designed to allow CHAINING of panels together to create - a 'bigger' display of panels. i.e. Chaining 4 panels into a 2x2 - grid. - - However, the function of this class has expanded now to also manage - the output for - - 1) TWO scan panels = Two rows updated in parallel. - * 64px high panel = sometimes referred to as 1/32 scan - * 32px high panel = sometimes referred to as 1/16 scan - * 16px high panel = sometimes referred to as 1/8 scan - - 2) FOUR scan panels = Four rows updated in parallel - * 32px high panel = sometimes referred to as 1/8 scan - * 16px high panel = sometimes referred to as 1/4 scan - - YouTube: https://www.youtube.com/brianlough - Tindie: https://www.tindie.com/stores/brianlough/ - Twitter: https://twitter.com/witnessmenow - *******************************************************************/ - -#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" -#ifndef NO_GFX -#include -#endif - -struct VirtualCoords -{ - int16_t x; - int16_t y; - int16_t virt_row; // chain of panels row - int16_t virt_col; // chain of panels col - - VirtualCoords() : x(0), y(0) - { - } -}; - -enum PANEL_SCAN_RATE -{ - NORMAL_TWO_SCAN, NORMAL_ONE_SIXTEEN, // treated as the same - FOUR_SCAN_32PX_HIGH, - FOUR_SCAN_16PX_HIGH -}; - -#ifdef USE_GFX_ROOT -class VirtualMatrixPanel : public GFX -#elif !defined NO_GFX -class VirtualMatrixPanel : public Adafruit_GFX -#else -class VirtualMatrixPanel -#endif -{ - -public: - int16_t virtualResX; - int16_t virtualResY; - - int16_t vmodule_rows; - int16_t vmodule_cols; - - int16_t panelResX; - int16_t panelResY; - - int16_t dmaResX; // The width of the chain in pixels (as the DMA engine sees it) - - MatrixPanel_I2S_DMA *display; - - VirtualMatrixPanel(MatrixPanel_I2S_DMA &disp, int _vmodule_rows, int _vmodule_cols, int _panelResX, int _panelResY, bool serpentine_chain = true, bool top_down_chain = false) -#ifdef USE_GFX_ROOT - : GFX(_vmodule_cols * _panelResX, _vmodule_rows * _panelResY) -#elif !defined NO_GFX - : Adafruit_GFX(_vmodule_cols * _panelResX, _vmodule_rows * _panelResY) -#endif - { - this->display = &disp; - - panelResX = _panelResX; - panelResY = _panelResY; - - vmodule_rows = _vmodule_rows; - vmodule_cols = _vmodule_cols; - - virtualResX = vmodule_cols * _panelResX; - virtualResY = vmodule_rows * _panelResY; - - dmaResX = panelResX * vmodule_rows * vmodule_cols; - - /* Virtual Display width() and height() will return a real-world value. For example: - * Virtual Display width: 128 - * Virtual Display height: 64 - * - * So, not values that at 0 to X-1 - */ - - _s_chain_party = serpentine_chain; // serpentine, or 'S' chain? - _chain_top_down = top_down_chain; - - coords.x = coords.y = -1; // By default use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer - } - - // equivalent methods of the matrix library so it can be just swapped out. - virtual void drawPixel(int16_t x, int16_t y, uint16_t color); - virtual void fillScreen(uint16_t color); // overwrite adafruit implementation - virtual void fillScreenRGB888(uint8_t r, uint8_t g, uint8_t b); - - void clearScreen() { display->clearScreen(); } - void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b); - -#ifdef USE_GFX_ROOT - // 24bpp FASTLED CRGB colour struct support - void fillScreen(CRGB color); - void drawPixel(int16_t x, int16_t y, CRGB color); -#endif - - uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { return display->color444(r, g, b); } - uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { return display->color565(r, g, b); } - uint16_t color333(uint8_t r, uint8_t g, uint8_t b) { return display->color333(r, g, b); } - - void flipDMABuffer() { display->flipDMABuffer(); } - void drawDisplayTest(); - void setRotate(bool rotate); - - void setPhysicalPanelScanRate(PANEL_SCAN_RATE rate); - -protected: - virtual VirtualCoords getCoords(int16_t &x, int16_t &y); - VirtualCoords coords; - - bool _s_chain_party = true; // Are we chained? Ain't no party like a... - bool _chain_top_down = false; // is the ESP at the top or bottom of the matrix of devices? - bool _rotate = false; - - PANEL_SCAN_RATE _panelScanRate = NORMAL_TWO_SCAN; - -}; // end Class header - -/** - * Calculate virtual->real co-ordinate mapping to underlying single chain of panels connected to ESP32. - * Updates the private class member variable 'coords', so no need to use the return value. - * Not thread safe, but not a concern for ESP32 sketch anyway... I think. - */ -inline VirtualCoords VirtualMatrixPanel::getCoords(int16_t &x, int16_t &y) -{ - // Serial.println("Called Base."); - coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer - - // Do we want to rotate? - if (_rotate) - { - int16_t temp_x = x; - x = y; - y = virtualResY - 1 - temp_x; - } - - if (x < 0 || x >= virtualResX || y < 0 || y >= virtualResY) - { // Co-ordinates go from 0 to X-1 remember! otherwise they are out of range! - // Serial.printf("VirtualMatrixPanel::getCoords(): Invalid virtual display coordinate. x,y: %d, %d\r\n", x, y); - return coords; - } - - // Stupidity check - if ((vmodule_rows == 1) && (vmodule_cols == 1)) // single panel... - { - coords.x = x; - coords.y = y; - } - else - { - uint8_t row = (y / panelResY) + 1; // a non indexed 0 row number - if ((_s_chain_party && !_chain_top_down && (row % 2 == 0)) // serpentine vertically stacked chain starting from bottom row (i.e. ESP closest to ground), upwards - || - (_s_chain_party && _chain_top_down && (row % 2 != 0)) // serpentine vertically stacked chain starting from the sky downwards - ) - { - // First portion gets you to the correct offset for the row you need - // Second portion inverts the x on the row - coords.x = ((y / panelResY) * (virtualResX)) + (virtualResX - x) - 1; - - // inverts the y the row - coords.y = panelResY - 1 - (y % panelResY); - } - else - { - // Normal chain pixel co-ordinate - coords.x = x + ((y / panelResY) * (virtualResX)); - coords.y = y % panelResY; - } - } - - // Reverse co-ordinates if panel chain from ESP starts from the TOP RIGHT - if (_chain_top_down) - { - /* - const HUB75_I2S_CFG _cfg = this->display->getCfg(); - coords.x = (_cfg.mx_width * _cfg.chain_length - 1) - coords.x; - coords.y = (_cfg.mx_height-1) - coords.y; - */ - coords.x = (dmaResX - 1) - coords.x; - coords.y = (panelResY - 1) - coords.y; - } - - /* START: Pixel remapping AGAIN to convert TWO parallel scanline output that the - * the underlying hardware library is designed for (because - * there's only 2 x RGB pins... and convert this to 1/4 or something - */ - if (_panelScanRate == FOUR_SCAN_32PX_HIGH) - { - /* Convert Real World 'VirtualMatrixPanel' co-ordinates (i.e. Real World pixel you're looking at - on the panel or chain of panels, per the chaining configuration) to a 1/8 panels - double 'stretched' and 'squished' coordinates which is what needs to be sent from the - DMA buffer. - - Note: Look at the FourScanPanel example code and you'll see that the DMA buffer is setup - as if the panel is 2 * W and 0.5 * H ! - */ - - /* - Serial.print("VirtualMatrixPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") "); - // to - Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") "); - */ - if ((y & 8) == 0) - { - coords.x += ((coords.x / panelResX) + 1) * panelResX; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer - } - else - { - coords.x += (coords.x / panelResX) * panelResX; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer - } - - // http://cpp.sh/4ak5u - // Real number of DMA y rows is half reality - // coords.y = (y / 16)*8 + (y & 0b00000111); - coords.y = (y >> 4) * 8 + (y & 0b00000111); - - /* - Serial.print("OneEightScanPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") "); - // to - Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") "); - */ - } - else if (_panelScanRate == FOUR_SCAN_16PX_HIGH) - { - if ((y & 8) == 0) - { - coords.x += (panelResX >> 2) * (((coords.x & 0xFFF0) >> 4) + 1); // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer - } - else - { - coords.x += (panelResX >> 2) * (((coords.x & 0xFFF0) >> 4)); // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer - } - - if (y < 32) - coords.y = (y >> 4) * 8 + (y & 0b00000111); - else - { - coords.y = ((y - 32) >> 4) * 8 + (y & 0b00000111); - coords.x += 256; - } - } - - // Serial.print("Mapping to x: "); Serial.print(coords.x, DEC); Serial.print(", y: "); Serial.println(coords.y, DEC); - return coords; -} - -inline void VirtualMatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t color) -{ // adafruit virtual void override - getCoords(x, y); - this->display->drawPixel(coords.x, coords.y, color); -} - -inline void VirtualMatrixPanel::fillScreen(uint16_t color) -{ // adafruit virtual void override - this->display->fillScreen(color); -} - -inline void VirtualMatrixPanel::fillScreenRGB888(uint8_t r, uint8_t g, uint8_t b) -{ - this->display->fillScreenRGB888(r, g, b); -} - -inline void VirtualMatrixPanel::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b) -{ - getCoords(x, y); - this->display->drawPixelRGB888(coords.x, coords.y, r, g, b); -} - -#ifdef USE_GFX_ROOT -// Support for CRGB values provided via FastLED -inline void VirtualMatrixPanel::drawPixel(int16_t x, int16_t y, CRGB color) -{ - getCoords(x, y); - this->display->drawPixel(coords.x, coords.y, color); -} - -inline void VirtualMatrixPanel::fillScreen(CRGB color) -{ - this->display->fillScreen(color); -} -#endif - -inline void VirtualMatrixPanel::setRotate(bool rotate) -{ - _rotate = rotate; - -#ifndef NO_GFX - // We don't support rotation by degrees. - if (rotate) - { - setRotation(1); - } - else - { - setRotation(0); - } -#endif -} - -inline void VirtualMatrixPanel::setPhysicalPanelScanRate(PANEL_SCAN_RATE rate) -{ - _panelScanRate = rate; -} - -#ifndef NO_GFX -inline void VirtualMatrixPanel::drawDisplayTest() -{ - this->display->setFont(&FreeSansBold12pt7b); - this->display->setTextColor(this->display->color565(255, 255, 0)); - this->display->setTextSize(1); - - for (int panel = 0; panel < vmodule_cols * vmodule_rows; panel++) - { - int top_left_x = (panel == 0) ? 0 : (panel * panelResX); - this->display->drawRect(top_left_x, 0, panelResX, panelResY, this->display->color565(0, 255, 0)); - this->display->setCursor(panel * panelResX, panelResY - 3); - this->display->print((vmodule_cols * vmodule_rows) - panel); - } -} -#endif - -/* -// need to recreate this one, as it wouldn't work to just map where it starts. -inline void VirtualMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t icon_cols, int16_t icon_rows) { - int i, j; - for (i = 0; i < icon_rows; i++) { - for (j = 0; j < icon_cols; j++) { - // This is a call to this libraries version of drawPixel - // which will map each pixel, which is what we want. - //drawPixelRGB565 (x + j, y + i, ico[i * module_cols + j]); - drawPixel (x + j, y + i, ico[i * icon_cols + j]); - } - } -} -*/ - -#endif