VirtualMatrixPanel_T
Initial release
This commit is contained in:
parent
d18758c9e4
commit
5af3d83a10
8 changed files with 69 additions and 204 deletions
|
@ -30,7 +30,7 @@ __[BUILD OPTIONS](/doc/BuildOptions.md) | [EXAMPLES](/examples/README.md)__ | [!
|
||||||
# Introduction
|
# Introduction
|
||||||
* This is an ESP32 Arduino/IDF library for HUB75 / HUB75E connection based RGB LED panels.
|
* 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.
|
* 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.
|
* The library uses the DMA functionality provided by the ESP32's 'LCD Mode' for fast data output.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
|
|
@ -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).
|
|
|
@ -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.
|
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.
|
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
|
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 NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW
|
|
||||||
|
|
||||||
#define PANEL_CHAIN NUM_ROWS*NUM_COLS // total number of panels chained one to another
|
```cpp
|
||||||
|
FOUR_SCAN_32PX_HIGH, ///< Four-scan mode, 32-pixel high panels.
|
||||||
#define VIRTUAL_MATRIX_CHAIN_TYPE <INSERT CHAINING TYPE HERE - Refer to documentation or example>
|
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.
|
||||||
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.
|
|
|
@ -39,10 +39,8 @@
|
||||||
|
|
||||||
#ifdef USE_GFX_LITE
|
#ifdef USE_GFX_LITE
|
||||||
#include "GFX_Lite.h"
|
#include "GFX_Lite.h"
|
||||||
// #include <Fonts/FreeSansBold12pt7b.h>
|
|
||||||
#elif !defined(NO_GFX)
|
#elif !defined(NO_GFX)
|
||||||
#include "Adafruit_GFX.h"
|
#include "Adafruit_GFX.h"
|
||||||
// #include <Fonts/FreeSansBold12pt7b.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
@ -273,14 +271,40 @@ public:
|
||||||
// this->setFont(&FreeSansBold12pt7b);
|
// this->setFont(&FreeSansBold12pt7b);
|
||||||
this->setTextColor(display->color565(255, 255, 0));
|
this->setTextColor(display->color565(255, 255, 0));
|
||||||
// this->setTextSize(1);
|
// this->setTextSize(1);
|
||||||
for (int panel = 0; panel < vmodule_cols * vmodule_rows; panel++) {
|
for (int col = 0; col < vmodule_cols; col++) {
|
||||||
int top_left_x = (panel == 0) ? 0 : (panel * panel_res_x);
|
for (int row = 0; row < vmodule_rows; row++) {
|
||||||
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);
|
int start_x = col * panel_res_x;
|
||||||
this->print((vmodule_cols * vmodule_rows) - panel);
|
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
|
#endif
|
||||||
|
|
||||||
inline void clearScreen() { display->clearScreen(); }
|
inline void clearScreen() { display->clearScreen(); }
|
||||||
|
@ -427,16 +451,11 @@ public:
|
||||||
coords.y = virt_y;
|
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
|
#ifdef NO_GFX
|
||||||
|
|
Loading…
Add table
Reference in a new issue