diff --git a/README.md b/README.md index 023da2c..1c7f548 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ __[BUILD OPTIONS](/doc/BuildOptions.md) | [EXAMPLES](/examples/README.md)__ | [! # Introduction * This is an ESP32 Arduino/IDF library for HUB75 / HUB75E connection based RGB LED panels. * This library 'out of the box' (mostly) supports HUB75 panels where simple TWO rows/lines are updated in parallel... referred to as 'two scan' panels within this documentation. -* 'Four scan' panels are also supported - but please refer to the Four Scan Panel example sketch. +* 1/4 (aka. 'Four Scan') outdoor panels are also supported - but please refer to the VirtualMatrixPanel example. * The library uses the DMA functionality provided by the ESP32's 'LCD Mode' for fast data output. ## Features diff --git a/doc/VirtualMatrixPanel (old).odp b/doc/VirtualMatrixPanel (old).odp deleted file mode 100644 index 4e3a066..0000000 Binary files a/doc/VirtualMatrixPanel (old).odp and /dev/null differ diff --git a/doc/VirtualMatrixPanel.odp b/doc/VirtualMatrixPanel.odp index c9ce91f..ecb226f 100644 Binary files a/doc/VirtualMatrixPanel.odp and b/doc/VirtualMatrixPanel.odp differ diff --git a/doc/VirtualMatrixPanel.pdf b/doc/VirtualMatrixPanel.pdf index f6e7157..b8cd845 100644 Binary files a/doc/VirtualMatrixPanel.pdf and b/doc/VirtualMatrixPanel.pdf differ diff --git a/examples/Four_Scan_Panel/Four_Scan_Panel.ino b/examples/Four_Scan_Panel/Four_Scan_Panel.ino deleted file mode 100644 index 5086b62..0000000 --- a/examples/Four_Scan_Panel/Four_Scan_Panel.ino +++ /dev/null @@ -1,153 +0,0 @@ -/************************************************************************* - * Description: - * - * The underlying implementation of the ESP32-HUB75-MatrixPanel-I2S-DMA only - * supports output to HALF scan panels - which means outputting - * two lines at the same time, 16 or 32 rows apart if a 32px or 64px high panel - * respectively. - * This cannot be changed at the DMA layer as it would require a messy and complex - * rebuild of the library's internals. - * - * However, it is possible to connect QUARTER (i.e. FOUR lines updated in parallel) - * scan panels to this same library and - * 'trick' the output to work correctly on these panels by way of adjusting the - * pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA - * library. - * - **************************************************************************/ -#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" - -/* Use the Virtual Display class to re-map co-ordinates such that they draw - * correctly on a 32x16 1/8 Scan panel (or chain of such panels). - */ -#include "ESP32-VirtualMatrixPanel-I2S-DMA.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 - - // ^^^ NOTE: DEFAULT EXAMPLE SETUP IS FOR A CHAIN OF TWO x 1/8 SCAN PANELS - - // Change this to your needs, for details on VirtualPanel pls read the PDF! - #define SERPENT true - #define TOPDOWN false - - // placeholder for the matrix object - MatrixPanel_I2S_DMA *dma_display = nullptr; - - // placeholder for the virtual display object - VirtualMatrixPanel *FourScanPanel = nullptr; - - /****************************************************************************** - * Setup! - ******************************************************************************/ - void setup() - { - delay(250); - - Serial.begin(115200); - Serial.println(""); Serial.println(""); Serial.println(""); - Serial.println("*****************************************************"); - Serial.println("* 1/8 Scan Panel Demonstration *"); - 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*2, // DO NOT CHANGE THIS - PANEL_RES_Y/2, // 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 - - // OK, now we can create our matrix object - dma_display = new MatrixPanel_I2S_DMA(mxconfig); - - // let's adjust default brightness to about 75% - dma_display->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100% - - // Allocate memory and start DMA display - if( not dma_display->begin() ) - Serial.println("****** !KABOOM! I2S memory allocation failed ***********"); - - - dma_display->clearScreen(); - delay(500); - - // create FourScanPanellay object based on our newly created dma_display object - FourScanPanel = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y); - - // THE IMPORTANT BIT BELOW! - FourScanPanel->setPhysicalPanelScanRate(FOUR_SCAN_32PX_HIGH); - } - - - void loop() { - - // What the panel sees from the DMA engine! - for (int i=PANEL_RES_X*2+10; i< PANEL_RES_X*(NUM_ROWS*NUM_COLS)*2; i++) - { - dma_display->drawLine(i, 0, i, 7, dma_display->color565(255, 0, 0)); // red - delay(10); - } - - dma_display->clearScreen(); - delay(1000); -/* - // Try again using the pixel / dma memory remapper - for (int i=PANEL_RES_X+5; i< (PANEL_RES_X*2)-1; i++) - { - FourScanPanel->drawLine(i, 0, i, 7, dma_display->color565(0, 0, 255)); // blue - delay(10); - } -*/ - - // Try again using the pixel / dma memory remapper - int offset = PANEL_RES_X*((NUM_ROWS*NUM_COLS)-1); - for (int i=0; i< PANEL_RES_X; i++) - { - FourScanPanel->drawLine(i+offset, 0, i+offset, 7, dma_display->color565(0, 0, 255)); // blue - FourScanPanel->drawLine(i+offset, 8, i+offset, 15, dma_display->color565(0, 128,0)); // g - FourScanPanel->drawLine(i+offset, 16, i+offset, 23, dma_display->color565(128, 0,0)); // red - FourScanPanel->drawLine(i+offset, 24, i+offset, 31, dma_display->color565(0, 128, 128)); // blue - delay(10); - } - - delay(1000); - - - // Print on each chained panel 1/8 module! - // This only really works for a single horizontal chain - for (int i = 0; i < NUM_ROWS*NUM_COLS; i++) - { - FourScanPanel->setTextColor(FourScanPanel->color565(255, 255, 255)); - FourScanPanel->setCursor(i*PANEL_RES_X+7, FourScanPanel->height()/3); - - // Red text inside red rect (2 pix in from edge) - FourScanPanel->print("Panel " + String(i+1)); - FourScanPanel->drawRect(1,1, FourScanPanel->width()-2, FourScanPanel->height()-2, FourScanPanel->color565(255,0,0)); - - // White line from top left to bottom right - FourScanPanel->drawLine(0,0, FourScanPanel->width()-1, FourScanPanel->height()-1, FourScanPanel->color565(255,255,255)); - } - - delay(2000); - dma_display->clearScreen(); - - } // end loop diff --git a/examples/Four_Scan_Panel/README.md b/examples/Four_Scan_Panel/README.md deleted file mode 100644 index dd75176..0000000 --- a/examples/Four_Scan_Panel/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Using this library with 32x16 1/4 Scan Panels - -## Problem -ESP32-HUB75-MatrixPanel-I2S-DMA library will not display output correctly with 'Four Scan' 64x32 1/8 or 32x16 1/4 scan panels such [as this](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/154) by default. - -## Solution -It is possible to connect 1/8 scan panels to this library and 'trick' the output to work correctly on these panels by way of adjusting the pixel co-ordinates that are 'sent' to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA library (in this example, it is the 'dmaOutput' class). diff --git a/examples/VirtualMatrixPanel/README.md b/examples/VirtualMatrixPanel/README.md index c5aca88..7012f3f 100644 --- a/examples/VirtualMatrixPanel/README.md +++ b/examples/VirtualMatrixPanel/README.md @@ -1,4 +1,9 @@ -## Chained Panels example - Chaining individual LED matrix panels to make a larger panel ## +# The 'VirtualMatrixPanel_T' class +The `VirtualMatrixPanel_T` is used to perform pixel re-mapping in order to support the following use-cases that can be used together: +1. To create a larger display based on a chain of individual physical panels connected electrically in a Serpentine or Zig-Zag manner. +2. To provide support for physical panels with non-standard (i.e. Not a 1/2 scan panel) pixel mapping approaches. This is often seen with 1/4 scan outdoor panels. + +## 1. Chaining individual LED matrix panels to make a larger virtual display ## This is the PatternPlasma Demo adopted for use with multiple LED Matrix Panel displays arranged in a non standard order (i.e. a grid) to make a bigger display. @@ -19,33 +24,34 @@ For example: You bought four (4) 64x32px panels, and wanted to use them to creat 1. [Refer to this document](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/blob/master/doc/VirtualMatrixPanel.pdf) for an explanation and refer to this example on how to use. -2. In your Arduino sketch, configure these defines accordingly: +2. Read the `VirtualMatrixPanel.ino` code + +## 2. Using this library with 1/4 Scan Panels (Four Scan) + +This library does not natively support 'Four Scan' 64x32 1/8 or 32x16 1/4 scan panels such [as this](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/154) by default. + +### Solution +Read the `VirtualMatrixPanel.ino` code. + +The VirtualMatrixPanel_T class provides a way to additionally remap pixel for each individual panel by way of the `ScanTypeMapping` class. + +You can create your own custom per-panel pixel mapping class as well should you wish. + +```cpp +// --- Example 3: Single non-standard 1/4 Scan (Four-Scan 1/8) --- + +// Use an existing library user-contributed Scan Type pixel mapping +using MyScanTypeMapping = ScanTypeMapping<FOUR_SCAN_32PX_HIGH>; + +// Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class +VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>* virtualDisp = nullptr; ``` -#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 2 // Number of rows of chained INDIVIDUAL PANELS -#define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW +The library has these user-contributed additions, but given the variety of panels on the market, your success with any of these may vary. -#define PANEL_CHAIN NUM_ROWS*NUM_COLS // total number of panels chained one to another - -#define VIRTUAL_MATRIX_CHAIN_TYPE <INSERT CHAINING TYPE HERE - Refer to documentation or example> - -``` -VIRTUAL_MATRIX_CHAIN_TYPE's: - - - -3. In your Arduino sketch, use the 'VirtualMatrixPanel' class instance (virtualDisp) to draw to the display (i.e. drawPixel), instead of the underling MatrixPanel_I2S_DMA class instance (dma_display). - - -#### Thanks to #### -* Brian Lough for the Virtual to Real pixel co-ordinate code. - -YouTube: https://www.youtube.com/brianlough - -Tindie: https://www.tindie.com/stores/brianlough/ - -Twitter: https://twitter.com/witnessmenow - -* Galaxy-Man for the donation of hardware for testing. +```cpp + FOUR_SCAN_32PX_HIGH, ///< Four-scan mode, 32-pixel high panels. + FOUR_SCAN_16PX_HIGH, ///< Four-scan mode, 16-pixel high panels. + FOUR_SCAN_64PX_HIGH, ///< Four-scan mode, 64-pixel high panels. + FOUR_SCAN_40PX_HIGH ///< Four-scan mode, 40-pixel high panels. +``` \ No newline at end of file diff --git a/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp b/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp index 5936cb6..089bc06 100644 --- a/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp +++ b/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp @@ -39,10 +39,8 @@ #ifdef USE_GFX_LITE #include "GFX_Lite.h" -// #include <Fonts/FreeSansBold12pt7b.h> #elif !defined(NO_GFX) #include "Adafruit_GFX.h" -// #include <Fonts/FreeSansBold12pt7b.h> #endif // ---------------------------------------------------------------------- @@ -273,14 +271,40 @@ public: // this->setFont(&FreeSansBold12pt7b); this->setTextColor(display->color565(255, 255, 0)); // this->setTextSize(1); - for (int panel = 0; panel < vmodule_cols * vmodule_rows; panel++) { - int top_left_x = (panel == 0) ? 0 : (panel * panel_res_x); - this->drawRect(top_left_x, 0, panel_res_x, panel_res_y, this->color565(0, 255, 0)); - this->setCursor((panel * panel_res_x) + 2, panel_res_y - 10); - this->print((vmodule_cols * vmodule_rows) - panel); + for (int col = 0; col < vmodule_cols; col++) { + for (int row = 0; row < vmodule_rows; row++) { + + int start_x = col * panel_res_x; + int start_y = row * panel_res_y; + + int panel_id = col + (row * vmodule_cols) + 1; + //int top_left_x = panel * panel_res_x; + this->drawRect(start_x, start_y, panel_res_x, panel_res_y, this->color565(0, 255, 0)); + this->setCursor(start_x + panel_res_x/2 - 2, start_y + panel_res_y/2 - 4); + this->print(panel_id); + + log_d("drawDisplayTest() Panel: %d, start_x: %d, start_y: %d", panel_id, start_x, start_y); + } } } + + inline void drawDisplayTestDMA() + { + // Write to the underlying panels only via the dma_display instance. + // This only works on standard panels with a linear mapping (i.e. two-scan). + 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 * panel_res_x; + this->display->drawRect(top_left_x, 0, panel_res_x, panel_res_y, this->display->color565(0, 255, 0)); + this->display->setCursor((panel * panel_res_x) + 6, panel_res_y - 12); + this->display->print((vmodule_cols * vmodule_rows) - panel); + } + } + #endif inline void clearScreen() { display->clearScreen(); } @@ -427,16 +451,11 @@ public: coords.y = virt_y; } - //log_d("calcCoords post-chain: virt_x: %d, virt_y: %d", virt_x, virt_y); + //log_d("calcCoords post-chain: virt_x: %d, virt_y: %d", virt_x, virt_y); - if constexpr (ScanTypeMapping != STANDARD_TWO_SCAN) { + // --- Apply physical LED panel scan–type mapping / fix --- + coords = ScanTypeMapping::apply(coords, virt_y, panel_pixel_base); - // --- Apply physical LED panel scan–type mapping / fix --- - coords = ScanTypeMapping::apply(coords, virt_y, panel_pixel_base); - - } - - //return coords; } #ifdef NO_GFX