diff options
Diffstat (limited to 'examples/VirtualMatrixPanel')
| -rw-r--r-- | examples/VirtualMatrixPanel/README.md | 48 | ||||
| -rw-r--r-- | examples/VirtualMatrixPanel/VirtualMatrixPanel.ino | 381 |
2 files changed, 242 insertions, 187 deletions
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: -``` -#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. +2. Read the `VirtualMatrixPanel.ino` code -#define NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS -#define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW +## 2. Using this library with 1/4 Scan Panels (Four Scan) -#define PANEL_CHAIN NUM_ROWS*NUM_COLS // total number of panels chained one to another +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. -#define VIRTUAL_MATRIX_CHAIN_TYPE <INSERT CHAINING TYPE HERE - Refer to documentation or example> - -``` -VIRTUAL_MATRIX_CHAIN_TYPE's: - +### 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. -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). +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) --- -#### Thanks to #### -* Brian Lough for the Virtual to Real pixel co-ordinate code. +// Use an existing library user-contributed Scan Type pixel mapping +using MyScanTypeMapping = ScanTypeMapping<FOUR_SCAN_32PX_HIGH>; -YouTube: https://www.youtube.com/brianlough - -Tindie: https://www.tindie.com/stores/brianlough/ +// Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class +VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>* virtualDisp = nullptr; +``` -Twitter: https://twitter.com/witnessmenow +The library has these user-contributed additions, but given the variety of panels on the market, your success with any of these may vary. -* 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/examples/VirtualMatrixPanel/VirtualMatrixPanel.ino b/examples/VirtualMatrixPanel/VirtualMatrixPanel.ino index 1343d9b..787df1f 100644 --- a/examples/VirtualMatrixPanel/VirtualMatrixPanel.ino +++ b/examples/VirtualMatrixPanel/VirtualMatrixPanel.ino @@ -1,169 +1,218 @@ -/****************************************************************************** - ------------------------------------------------------------------------- - Steps to create a virtual display made up of a chain of panels in a grid - ------------------------------------------------------------------------- - - Read the documentation! - https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/tree/master/examples/ChainedPanels - - tl/dr: - - - Set values for NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, PANEL_CHAIN_TYPE. - - - Other than where the matrix is defined and matrix.begin in the setup, you - should now be using the virtual display for everything (drawing pixels, writing text etc). - You can do a find and replace of all calls if it's an existing sketch - (just make sure you don't replace the definition and the matrix.begin) - - - If the sketch makes use of MATRIX_HEIGHT or MATRIX_WIDTH, these will need to be - replaced with the width and height of your virtual screen. - Either make new defines and use that, or you can use virtualDisp.width() or .height() - -*****************************************************************************/ -// 1) Include key virtual display library - #include <ESP32-VirtualMatrixPanel-I2S-DMA.h> - -// 2) Set 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 2 // Number of rows of chained INDIVIDUAL PANELS - #define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW - #define PANEL_CHAIN NUM_ROWS*NUM_COLS // total number of panels chained one to another - - /* Configure the serpetine chaining approach. Options are: - CHAIN_TOP_LEFT_DOWN - CHAIN_TOP_RIGHT_DOWN - CHAIN_BOTTOM_LEFT_UP - CHAIN_BOTTOM_RIGHT_UP - - The location (i.e. 'TOP_LEFT', 'BOTTOM_RIGHT') etc. refers to the starting point where - the ESP32 is located, and how the chain of panels will 'roll out' from there. - - In this example we're using 'CHAIN_BOTTOM_LEFT_UP' which would look like this in the real world: - - Chain of 4 x 64x32 panels with the ESP at the BOTTOM_LEFT: - - +---------+---------+ - | 4 | 3 | - | | | - +---------+---------+ - | 1 | 2 | - | (ESP) | | - +---------+---------+ - +/** + * @file VirtualMatrixPanel.ino + * @brief Example of using the VirtualMatrixPanel_T template class. + * + * The VirtualMatrixPanel_T class can be used for two purposes: + * + * 1) Create a much larger display out of a number of physical LED panels + * chained in a Serpentine or Zig-Zag manner; + * + * 2) Provide a way to deal with weird individual physical panels that do not have a + * simple linear X, Y pixel mapping. For example, 1/4 scan panels, or outdoor panels. + * + * 1) and 2) can be combined and utilsied together. + * + * There are THREE examples contained within this library. What example gets built depends + * on the value of the "#define EXAMPLE_NUMBER X" value. Where X = Example number. + * + * Example 1: STANDARD 1/2 Scan (i.e. 1/16, 1/32) LED matrix panels, 64x32 pixels each, + * in a grid of 2x2 panels, chained in a Serpentine manner. + * + * Example 2: Non-Standard 1/4 Scan (i.e. Four-Scan 1/8) outdoor LED matrix panels, 64x32 pixels each, + * in a grid of 2x2 panels, chained in a Serpentine manner. + * + * Example 3: A single non-standard 1/4 Scan (i.e. Four-Scan 1/8) outdoor LED matrix panel, 64x32 pixels. + */ + + #include <Arduino.h> + #include <ESP32-HUB75-VirtualMatrixPanel_T.hpp> + + // Select example to compile! + #define EXAMPLE_NUMBER 1 + //#define EXAMPLE_NUMBER 2 + //#define EXAMPLE_NUMBER 3 + + /** + * Configuration of the LED matrix panels number and individual pixel resolution. + **/ + #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 VDISP_NUM_ROWS 2 // Number of rows of individual LED panels + #define VDISP_NUM_COLS 2 // Number of individual LED panels per row + + #define PANEL_CHAIN_LEN (VDISP_NUM_ROWS*VDISP_NUM_COLS) // Don't change + + + /** + * Configuration of the approach used to chain all the individual panels together. + * Refer to the documentation or check the enum 'PANEL_CHAIN_TYPE' in VirtualMatrixPanel_T.hpp for options. + **/ + #define PANEL_CHAIN_TYPE CHAIN_TOP_RIGHT_DOWN + + /** + * Optional config for the per-panel pixel mapping, for non-standard panels. + * i.e. 1/4 scan panels, or outdoor panels. They're a pain in the a-- and all + * have their own weird pixel mapping that is not linear. + * + * This is used for Examples 2 and 3. + * + **/ + #define PANEL_SCAN_TYPE FOUR_SCAN_32PX_HIGH + + /** + * Mandatory declaration of the dma_display. DO NOT CHANGE + **/ + MatrixPanel_I2S_DMA *dma_display = nullptr; + + + /** + * Template instantiation for the VirtualMatrixPanel_T class, depending on use-case. + **/ + #if EXAMPLE_NUMBER == 1 + // --- Example 1: STANDARD 1/2 Scan --- + + // Declare a pointer to the specific instantiation: + VirtualMatrixPanel_T<PANEL_CHAIN_TYPE>* virtualDisp = nullptr; + + #endif + + + #if EXAMPLE_NUMBER == 2 + // --- Example 2: Non-Standard 1/4 Scan (Four-Scan 1/8) --- + + // Use an existing library user-contributed Scan Type pixel mapping + using MyScanTypeMapping = ScanTypeMapping<PANEL_SCAN_TYPE>; + + // Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class + VirtualMatrixPanel_T<PANEL_CHAIN_TYPE, MyScanTypeMapping>* virtualDisp = nullptr; + + #endif + + #if EXAMPLE_NUMBER == 3 + // --- 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<PANEL_SCAN_TYPE>; + + // Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class + VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>* virtualDisp = nullptr; + + #endif + + + + // Bonus non-existnat example. Create your own per-panel custom pixel mapping! + #if EXAMPLE_NUMBER == 4 + + // --- Custom Scan–Type Pixel Mapping --- + // This policy adds a fixed offset to the coordinates. + struct CustomScanTypeMapping { + static constexpr VirtualCoords apply(VirtualCoords coords, int virt_y, int panel_pixel_base) { + // For demonstration, add a fixed offset of +5 to x and +3 to y. + coords.x += 5; + coords.y += 3; + return coords; + } + }; + #endif + + void setup() + { + Serial.begin(115200); + delay(2000); + + #if EXAMPLE_NUMBER == 3 + /** + * HACK ALERT! + * For 1/4 scan panels (namely outdoor panels), electrically the pixels are connected in a chain that is + * twice the physical panel's pixel width, and half the pixel height. As such, we need to configure + * the underlying DMA library to match the same. Then we use the VirtualMatrixPanel_T class to map the + * physical pixels to the virtual pixels. + */ + HUB75_I2S_CFG mxconfig( + PANEL_RES_X*2, // DO NOT CHANGE THIS + PANEL_RES_Y/2, // DO NOT CHANGE THIS + 1 // A Single panel + ); + + #elif EXAMPLE_NUMBER == 2 + + /** + * HACK ALERT! + * For 1/4 scan panels (namely outdoor panels), electrically the pixels are connected in a chain that is + * twice the physical panel's pixel width, and half the pixel height. As such, we need to configure + * the underlying DMA library to match the same. Then we use the VirtualMatrixPanel_T class to map the + * physical pixels to the virtual pixels. + */ + HUB75_I2S_CFG mxconfig( + PANEL_RES_X*2, // DO NOT CHANGE THIS + PANEL_RES_Y/2, // DO NOT CHANGE THIS + PANEL_CHAIN_LEN + ); + + #else + + // Standard panel type natively supported by this library (Example 1) + HUB75_I2S_CFG mxconfig( + PANEL_RES_X, + PANEL_RES_Y, + PANEL_CHAIN_LEN + ); + + #endif + + mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M; + mxconfig.clkphase = false; + //mxconfig.driver = HUB75_I2S_CFG::FM6126A; + + + /** + * Setup physical DMA LED display output. */ - #define VIRTUAL_MATRIX_CHAIN_TYPE CHAIN_BOTTOM_LEFT_UP - -// 3) Create the runtime objects to use - - // placeholder for the matrix object - MatrixPanel_I2S_DMA *dma_display = nullptr; - - // placeholder for the virtual display object - VirtualMatrixPanel *virtualDisp = nullptr; - - -/****************************************************************************** - * Setup! - ******************************************************************************/ -void setup() { - - delay(2000); - Serial.begin(115200); - Serial.println(""); Serial.println(""); Serial.println(""); - Serial.println("*****************************************************"); - Serial.println(" HELLO !"); - Serial.println("*****************************************************"); - - - /****************************************************************************** - * Create physical DMA panel class AND virtual (chained) display class. - ******************************************************************************/ - - /* - 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 - */ - - HUB75_I2S_CFG mxconfig( - PANEL_RES_X, // module width - PANEL_RES_Y, // module height - 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 - - // Sanity checks - if (NUM_ROWS <= 1) { - Serial.println(F("There is no reason to use the VirtualDisplay class for a single horizontal chain and row!")); - } - - // 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(192); // 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 ***********"); - - // create VirtualDisplay object based on our newly created dma_display object - virtualDisp = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, VIRTUAL_MATRIX_CHAIN_TYPE); - - // So far so good, so continue - virtualDisp->fillScreen(virtualDisp->color444(0, 0, 0)); - virtualDisp->drawDisplayTest(); // draw text numbering on each screen to check connectivity - - // delay(1000); - - Serial.println("Chain of 4x 64x32 panels for this example:"); - Serial.println("+---------+---------+"); - Serial.println("| 4 | 3 |"); - Serial.println("| | |"); - Serial.println("+---------+---------+"); - Serial.println("| 1 | 2 |"); - Serial.println("| (ESP32) | |"); - Serial.println("+---------+---------+"); - - // draw blue text - virtualDisp->setFont(&FreeSansBold12pt7b); - virtualDisp->setTextColor(virtualDisp->color565(0, 0, 255)); - virtualDisp->setTextSize(3); - virtualDisp->setCursor(0, virtualDisp->height()- ((virtualDisp->height()-45)/2)); - virtualDisp->print("ABCD"); - - // Red text inside red rect (2 pix in from edge) - virtualDisp->drawRect(1,1, virtualDisp->width()-2, virtualDisp->height()-2, virtualDisp->color565(255,0,0)); - - // White line from top left to bottom right - virtualDisp->drawLine(0,0, virtualDisp->width()-1, virtualDisp->height()-1, virtualDisp->color565(255,255,255)); - + dma_display = new MatrixPanel_I2S_DMA(mxconfig); + dma_display->begin(); + dma_display->setBrightness8(128); //0-255 + dma_display->clearScreen(); + + /** + * Setup the VirtualMatrixPanel_T class to map the virtual pixels to the physical pixels. + */ + + #if EXAMPLE_NUMBER == 1 + virtualDisp = new VirtualMatrixPanel_T<PANEL_CHAIN_TYPE>(VDISP_NUM_ROWS, VDISP_NUM_COLS, PANEL_RES_X, PANEL_RES_Y); + #elif EXAMPLE_NUMBER == 2 + virtualDisp = new VirtualMatrixPanel_T<PANEL_CHAIN_TYPE, MyScanTypeMapping>(VDISP_NUM_ROWS, VDISP_NUM_COLS, PANEL_RES_X, PANEL_RES_Y); + #elif EXAMPLE_NUMBER == 3 + virtualDisp = new VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>(1, 1, PANEL_RES_X, PANEL_RES_Y); // Single 1/4 scan panel + #endif + + // Pass a reference to the DMA display to the VirtualMatrixPanel_T class + virtualDisp->setDisplay(*dma_display); + + for (int y = 0; y < virtualDisp->height(); y++) { + for (int x = 0; x < virtualDisp->width(); x++) { + + uint16_t color = virtualDisp->color565(96, 0, 0); // red + + if (x == 0) color = virtualDisp->color565(0, 255, 0); // g + if (x == (virtualDisp->width()-1)) color = virtualDisp->color565(0, 0, 255); // b + + virtualDisp->drawPixel(x, y, color); + delay(2); + } + } + + delay(3000); + virtualDisp->clearScreen(); virtualDisp->drawDisplayTest(); // re draw text numbering on each screen to check connectivity -} - -void loop() { - - -} // end loop - - -/***************************************************************************** - - Thanks to: - - * Brian Lough for the original example as raised in this issue: - https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/26 - - YouTube: https://www.youtube.com/brianlough - Tindie: https://www.tindie.com/stores/brianlough/ - Twitter: https://twitter.com/witnessmenow - - * Galaxy-Man for the kind donation of panels make/test that this is possible: - https://github.com/Galaxy-Man - -*****************************************************************************/
\ No newline at end of file + } + + + void loop() { + + // Do nothing here. + delay (100); + + }
\ No newline at end of file |
