Enhance VirtualMatrixPanel_T example

This commit is contained in:
mrcodetastic 2025-03-19 22:20:23 +00:00
parent c9a8c50702
commit aed04adfcd
2 changed files with 141 additions and 60 deletions

View file

@ -12,7 +12,7 @@
* *
* 1) and 2) can be combined and utilsied together. * 1) and 2) can be combined and utilsied together.
* *
* There are THREE examples contained within this library. What example gets built depends * There are FOUR examples contained within this library. What example gets built depends
* on the value of the "#define EXAMPLE_NUMBER X" value. Where X = Example number. * 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, * Example 1: STANDARD 1/2 Scan (i.e. 1/16, 1/32) LED matrix panels, 64x32 pixels each,
@ -22,6 +22,9 @@
* in a grid of 2x2 panels, chained in a Serpentine manner. * 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. * Example 3: A single non-standard 1/4 Scan (i.e. Four-Scan 1/8) outdoor LED matrix panel, 64x32 pixels.
*
* Example 4: Having your own panel pixel mapping logic of use only to a specific panel that isn't supported.
* In this case we re-use this to map an individual pixel in a weird way.
*/ */
#include <Arduino.h> #include <Arduino.h>
@ -31,6 +34,7 @@
#define EXAMPLE_NUMBER 1 #define EXAMPLE_NUMBER 1
//#define EXAMPLE_NUMBER 2 //#define EXAMPLE_NUMBER 2
//#define EXAMPLE_NUMBER 3 //#define EXAMPLE_NUMBER 3
//#define EXAMPLE_NUMBER 4 // Custom Special Effects example!
/** /**
* Configuration of the LED matrix panels number and individual pixel resolution. * Configuration of the LED matrix panels number and individual pixel resolution.
@ -64,80 +68,124 @@
* Mandatory declaration of the dma_display. DO NOT CHANGE * Mandatory declaration of the dma_display. DO NOT CHANGE
**/ **/
MatrixPanel_I2S_DMA *dma_display = nullptr; MatrixPanel_I2S_DMA *dma_display = nullptr;
// ------------------------------------------------------------------------------------------------------------
/** /**
* Template instantiation for the VirtualMatrixPanel_T class, depending on use-case. * Template instantiation for the VirtualMatrixPanel_T class, depending on use-case.
**/ **/
#if EXAMPLE_NUMBER == 1 #if EXAMPLE_NUMBER == 1
// --- Example 1: STANDARD 1/2 Scan ---
// --- Example 1: STANDARD 1/2 Scan ---
// Declare a pointer to the specific instantiation:
VirtualMatrixPanel_T<PANEL_CHAIN_TYPE>* virtualDisp = nullptr; // Declare a pointer to the specific instantiation:
VirtualMatrixPanel_T<PANEL_CHAIN_TYPE>* virtualDisp = nullptr;
#endif #endif
#if EXAMPLE_NUMBER == 2 #if EXAMPLE_NUMBER == 2
// --- Example 2: Non-Standard 1/4 Scan (Four-Scan 1/8) ---
// --- 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;
// 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 #endif
#if EXAMPLE_NUMBER == 3 #if EXAMPLE_NUMBER == 3
// --- Example 3: Single non-standard 1/4 Scan (Four-Scan 1/8) --- // --- Example 3: Single non-standard 1/4 Scan (Four-Scan 1/8) ---
// Use an existing library user-contributed Scan Type pixel mapping // Use an existing library user-contributed Scan Type pixel mapping
using MyScanTypeMapping = ScanTypeMapping<PANEL_SCAN_TYPE>; using MyScanTypeMapping = ScanTypeMapping<PANEL_SCAN_TYPE>;
// Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class // Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class
VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>* virtualDisp = nullptr; VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>* virtualDisp = nullptr;
#endif #endif
// Bonus non-existnat example. Create your own per-panel custom pixel mapping! // Bonus non-existnat example. Create your own per-panel custom pixel mapping!
#if EXAMPLE_NUMBER == 4 #if EXAMPLE_NUMBER == 4
// --- Custom ScanType Pixel Mapping --- // --- Custom ScanType Pixel Mapping ---
// This policy adds a fixed offset to the coordinates. // This is not what you would use this for, but in any case it
struct CustomScanTypeMapping { // makes a flipped mirror image
static constexpr VirtualCoords apply(VirtualCoords coords, int virt_y, int panel_pixel_base) { struct CustomMirrorScanTypeMapping {
// For demonstration, add a fixed offset of +5 to x and +3 to y.
coords.x += 5; static VirtualCoords apply(VirtualCoords coords, int vy, int pb) {
coords.y += 3;
return coords; // coords are the input coords for adjusting
}
}; int width = PANEL_RES_X;
int height = PANEL_RES_Y;
// Flip / Mirror x
coords.x = PANEL_RES_X - coords.x - 1;
// coords.y = PANEL_RES_Y - coords.y - 1;
return coords;
}
};
// Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class
VirtualMatrixPanel_T<CHAIN_NONE, CustomMirrorScanTypeMapping>* virtualDisp = nullptr;
#endif #endif
// ------------------------------------------------------------------------------------------------------------
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(115200);
delay(2000); delay(2000);
#if EXAMPLE_NUMBER == 3 /*
/**
* HACK ALERT! #define RL1 18
* For 1/4 scan panels (namely outdoor panels), electrically the pixels are connected in a chain that is #define GL1 17
* twice the physical panel's pixel width, and half the pixel height. As such, we need to configure #define BL1 16
* the underlying DMA library to match the same. Then we use the VirtualMatrixPanel_T class to map the #define RL2 15
* physical pixels to the virtual pixels. #define GL2 7
*/ #define BL2 6
HUB75_I2S_CFG mxconfig( #define CH_A 4
PANEL_RES_X*2, // DO NOT CHANGE THIS #define CH_B 10
PANEL_RES_Y/2, // DO NOT CHANGE THIS #define CH_C 14
1 // A Single panel #define CH_D 21
); #define CH_E 5 // assign to any available pin if using two panels or 64x64 panels with 1/32 scan
#define CLK 47
#elif EXAMPLE_NUMBER == 2 #define LAT 48
#define OE 38
// HUB75_I2S_CFG::i2s_pins _pins={RL1, GL1, BL1, RL2, GL2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK};
*/
#if EXAMPLE_NUMBER == 1
// A grid of normal (i.e. supported out of the box) 1/16, 1/32 (two scan) panels
// Standard panel type natively supported by this library (Example 1, 4)
HUB75_I2S_CFG mxconfig(
PANEL_RES_X,
PANEL_RES_Y,
PANEL_CHAIN_LEN
//, _pins
);
#endif
#if EXAMPLE_NUMBER == 2
// A grid of 1/4 scan panels. This panel type is not supported 'out of the box' and require specific
// ScanTypeMapping (pixel mapping) within the panel itself.
/** /**
* HACK ALERT! * HACK ALERT!
* For 1/4 scan panels (namely outdoor panels), electrically the pixels are connected in a chain that is * For 1/4 scan panels (namely outdoor panels), electrically the pixels are connected in a chain that is
@ -149,15 +197,41 @@
PANEL_RES_X*2, // DO NOT CHANGE THIS PANEL_RES_X*2, // DO NOT CHANGE THIS
PANEL_RES_Y/2, // DO NOT CHANGE THIS PANEL_RES_Y/2, // DO NOT CHANGE THIS
PANEL_CHAIN_LEN PANEL_CHAIN_LEN
//, _pins
); );
#else #endif
// Standard panel type natively supported by this library (Example 1) #if EXAMPLE_NUMBER == 3
// A single 1/4 scan panel. This panel type is not supported 'out of the box' and require specific
// ScanTypeMapping (pixel mapping) within the panel itself.
/**
* 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
//, _pins
);
#endif
#if EXAMPLE_NUMBER == 4
// A single normal scan panel, but we're using a custom CustomScanTypeMapping in the 'wrong'
// way to demonstrate how it can be used to create custom physical LED Matrix panel mapping.
HUB75_I2S_CFG::i2s_pins _pins={RL1, GL1, BL1, RL2, GL2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK};
// Standard panel type natively supported by this library (Example 1, 4)
HUB75_I2S_CFG mxconfig( HUB75_I2S_CFG mxconfig(
PANEL_RES_X, PANEL_RES_X,
PANEL_RES_Y, PANEL_RES_Y,
PANEL_CHAIN_LEN 1
// , _pins
); );
#endif #endif
@ -185,11 +259,13 @@
virtualDisp = new VirtualMatrixPanel_T<PANEL_CHAIN_TYPE, MyScanTypeMapping>(VDISP_NUM_ROWS, VDISP_NUM_COLS, PANEL_RES_X, PANEL_RES_Y); virtualDisp = new VirtualMatrixPanel_T<PANEL_CHAIN_TYPE, MyScanTypeMapping>(VDISP_NUM_ROWS, VDISP_NUM_COLS, PANEL_RES_X, PANEL_RES_Y);
#elif EXAMPLE_NUMBER == 3 #elif EXAMPLE_NUMBER == 3
virtualDisp = new VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>(1, 1, PANEL_RES_X, PANEL_RES_Y); // Single 1/4 scan panel virtualDisp = new VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>(1, 1, PANEL_RES_X, PANEL_RES_Y); // Single 1/4 scan panel
#elif EXAMPLE_NUMBER == 4
virtualDisp = new VirtualMatrixPanel_T<CHAIN_NONE, CustomMirrorScanTypeMapping>(1, 1, PANEL_RES_X, PANEL_RES_Y); // Single 1/4 scan panel
#endif #endif
// Pass a reference to the DMA display to the VirtualMatrixPanel_T class // Pass a reference to the DMA display to the VirtualMatrixPanel_T class
virtualDisp->setDisplay(*dma_display); virtualDisp->setDisplay(*dma_display);
for (int y = 0; y < virtualDisp->height(); y++) { for (int y = 0; y < virtualDisp->height(); y++) {
for (int x = 0; x < virtualDisp->width(); x++) { for (int x = 0; x < virtualDisp->width(); x++) {
@ -199,20 +275,25 @@
if (x == (virtualDisp->width()-1)) color = virtualDisp->color565(0, 0, 255); // b if (x == (virtualDisp->width()-1)) color = virtualDisp->color565(0, 0, 255); // b
virtualDisp->drawPixel(x, y, color); virtualDisp->drawPixel(x, y, color);
delay(2); delay(1);
} }
} }
virtualDisp->drawLine(virtualDisp->width() - 1, virtualDisp->height() - 1, 0, 0, virtualDisp->color565(255, 255, 255));
virtualDisp->print("Virtual Matrix Panel");
delay(3000); delay(3000);
virtualDisp->clearScreen(); virtualDisp->clearScreen();
virtualDisp->drawDisplayTest(); // re draw text numbering on each screen to check connectivity virtualDisp->drawDisplayTest(); // re draw text numbering on each screen to check connectivity
} }
// ------------------------------------------------------------------------------------------------------------
void loop() { void loop() {
// Do nothing here. // Do nothing here.
delay (100);
} }

View file

@ -103,7 +103,7 @@ template <PANEL_SCAN_TYPE ScanType>
struct ScanTypeMapping { struct ScanTypeMapping {
static constexpr VirtualCoords apply(VirtualCoords coords, int virt_y, int panel_pixel_base) static constexpr VirtualCoords apply(VirtualCoords coords, int virt_y, int panel_pixel_base)
{ {
log_v("ScanTypeMapping: coords.x: %d, coords.y: %d, virt_y: %d, pixel_base: %d", coords.x, coords.y, virt_y, panel_pixel_base); //log_v("ScanTypeMapping: coords.x: %d, coords.y: %d, virt_y: %d, pixel_base: %d", coords.x, coords.y, virt_y, panel_pixel_base);
// FOUR_SCAN_16PX_HIGH // FOUR_SCAN_16PX_HIGH
if constexpr (ScanType == FOUR_SCAN_16PX_HIGH) if constexpr (ScanType == FOUR_SCAN_16PX_HIGH)
@ -301,7 +301,7 @@ public:
this->setCursor(start_x + panel_res_x/2 - 2, start_y + panel_res_y/2 - 4); this->setCursor(start_x + panel_res_x/2 - 2, start_y + panel_res_y/2 - 4);
this->print(panel_id); this->print(panel_id);
log_d("drawDisplayTest() Panel: %d, start_x: %d, start_y: %d", panel_id, start_x, start_y); //log_d("drawDisplayTest() Panel: %d, start_x: %d, start_y: %d", panel_id, start_x, start_y);
} }
} }