ESP32-HUB75-MatrixPanel-DMA/examples/VirtualMatrixPanel/VirtualMatrixPanel.ino
2025-03-19 22:20:23 +00:00

299 lines
No EOL
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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 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.
*
* 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.
*
* 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 <ESP32-HUB75-VirtualMatrixPanel_T.hpp>
// Select example to compile!
#define EXAMPLE_NUMBER 1
//#define EXAMPLE_NUMBER 2
//#define EXAMPLE_NUMBER 3
//#define EXAMPLE_NUMBER 4 // Custom Special Effects example!
/**
* 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 ScanType Pixel Mapping ---
// This is not what you would use this for, but in any case it
// makes a flipped mirror image
struct CustomMirrorScanTypeMapping {
static VirtualCoords apply(VirtualCoords coords, int vy, int pb) {
// 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
// ------------------------------------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
delay(2000);
/*
#define RL1 18
#define GL1 17
#define BL1 16
#define RL2 15
#define GL2 7
#define BL2 6
#define CH_A 4
#define CH_B 10
#define CH_C 14
#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
#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!
* 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
//, _pins
);
#endif
#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(
PANEL_RES_X,
PANEL_RES_Y,
1
// , _pins
);
#endif
mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M;
mxconfig.clkphase = false;
//mxconfig.driver = HUB75_I2S_CFG::FM6126A;
/**
* Setup physical DMA LED display output.
*/
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
#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
// 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(1);
}
}
virtualDisp->drawLine(virtualDisp->width() - 1, virtualDisp->height() - 1, 0, 0, virtualDisp->color565(255, 255, 255));
virtualDisp->print("Virtual Matrix Panel");
delay(3000);
virtualDisp->clearScreen();
virtualDisp->drawDisplayTest(); // re draw text numbering on each screen to check connectivity
}
// ------------------------------------------------------------------------------------------------------------
void loop() {
// Do nothing here.
}