Integrate 1/8 Scan Panel logic into VirtualMatrixPanel class

This commit is contained in:
mrfaptastic 2021-12-20 21:35:16 +00:00
parent 239de3a5eb
commit 229b0d874c
3 changed files with 79 additions and 93 deletions

View file

@ -34,7 +34,8 @@ struct VirtualCoords {
}; };
enum PANEL_SCAN_RATE {NORMAL_ONE_SIXTEEN, ONE_EIGHT};
#ifdef USE_GFX_ROOT #ifdef USE_GFX_ROOT
class VirtualMatrixPanel : public GFX class VirtualMatrixPanel : public GFX
#elif !defined NO_GFX #elif !defined NO_GFX
@ -107,6 +108,8 @@ class VirtualMatrixPanel
void flipDMABuffer() { display->flipDMABuffer(); } void flipDMABuffer() { display->flipDMABuffer(); }
void drawDisplayTest(); void drawDisplayTest();
void setRotate(bool rotate); void setRotate(bool rotate);
void setPhysicalPanelScanRate(PANEL_SCAN_RATE rate);
protected: protected:
@ -116,6 +119,8 @@ class VirtualMatrixPanel
bool _s_chain_party = true; // Are we chained? Ain't no party like a... bool _s_chain_party = true; // Are we chained? Ain't no party like a...
bool _chain_top_down = false; // is the ESP at the top or bottom of the matrix of devices? bool _chain_top_down = false; // is the ESP at the top or bottom of the matrix of devices?
bool _rotate = false; bool _rotate = false;
PANEL_SCAN_RATE _panelScanRate = NORMAL_ONE_SIXTEEN;
}; // end Class header }; // end Class header
@ -179,6 +184,47 @@ inline VirtualCoords VirtualMatrixPanel::getCoords(int16_t &x, int16_t &y) {
coords.x = (dmaResX - 1) - coords.x; coords.x = (dmaResX - 1) - coords.x;
coords.y = (panelResY-1) - coords.y; coords.y = (panelResY-1) - coords.y;
} }
/* START: Pixel remapping AGAIN to convert 1/16 SCAN output that the
* the underlying hardware library is designed for (because
* there's only 2 x RGB pins... and convert this to 1/8 or something
*/
if ( _panelScanRate == ONE_EIGHT)
{
/* Convert Real World 'VirtualMatrixPanel' co-ordinates (i.e. Real World pixel you're looking at
on the panel or chain of panels, per the chaining configuration) to a 1/8 panels
double 'stretched' and 'squished' coordinates which is what needs to be sent from the
DMA buffer.
Note: Look at the One_Eight_1_8_ScanPanel code and you'll see that the DMA buffer is setup
as if the panel is 2 * W and 0.5 * H !
*/
/*
Serial.print("VirtualMatrixPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") ");
// to
Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") ");
*/
if ( (y & 8) == 0) {
coords.x += ((coords.x / panelResX)+1)*panelResX; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
}
else {
coords.x += (coords.x / panelResX)*panelResX; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
}
// http://cpp.sh/4ak5u
// Real number of DMA y rows is half reality
// coords.y = (y / 16)*8 + (y & 0b00000111);
coords.y = (y >> 4)*8 + (y & 0b00000111);
/*
Serial.print("OneEightScanPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") ");
// to
Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") ");
*/
}
//Serial.print("Mapping to x: "); Serial.print(coords.x, DEC); Serial.print(", y: "); Serial.println(coords.y, DEC); //Serial.print("Mapping to x: "); Serial.print(coords.x, DEC); Serial.print(", y: "); Serial.println(coords.y, DEC);
return coords; return coords;
@ -205,6 +251,11 @@ inline void VirtualMatrixPanel::setRotate(bool rotate) {
if (rotate) { setRotation(1); } else { setRotation(0); } if (rotate) { setRotation(1); } else { setRotation(0); }
} }
inline void VirtualMatrixPanel::setPhysicalPanelScanRate(PANEL_SCAN_RATE rate) {
_panelScanRate=rate;
}
#ifndef NO_GFX #ifndef NO_GFX
inline void VirtualMatrixPanel::drawDisplayTest() inline void VirtualMatrixPanel::drawDisplayTest()

View file

@ -1,69 +0,0 @@
#ifndef _ESP32_ONE_EIGHT_SCAN_PANEL
#define _ESP32_ONE_EIGHT_SCAN_PANEL
#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>
/* This class inherits all the goodness of the VirtualMatrixPanel class used to created
large displays of chained panels, but does trickery to convert from 1/16 to 1/8
DMA output.
Some guidance given by looking at hzeller's code, in relation to the 'stretch factor'
concept where these panels are really double width and half the height, from the perspective
of the digital input required to get the 'real world' resolution and output.
https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/lib/multiplex-mappers.cc
*/
class OneEightScanPanel : public VirtualMatrixPanel
{
public:
using VirtualMatrixPanel::VirtualMatrixPanel; // inherit VirtualMatrixPanel's constructor(s)
protected:
/* Convert Real World 'VirtualMatrixPanel' co-ordinates (i.e. Real World pixel you're looking at
on the panel or chain of panels, per the chaining configuration) to a 1/8 panels
double 'stretched' and 'squished' coordinates which is what needs to be sent from the
DMA buffer.
Note: Look at the One_Eight_1_8_ScanPanel code and you'll see that the DMA buffer is setup
as if the panel is 2 * W and 0.5 * H !
*/
VirtualCoords getCoords(int16_t &x, int16_t &y);
}; // end class header note the ;
inline VirtualCoords OneEightScanPanel::getCoords(int16_t &x, int16_t &y) {
VirtualMatrixPanel::getCoords(x, y); // call to base to update coords for chaining approach
if ( coords.x == -1 || coords.y == -1 ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range!
return coords;
}
/*
Serial.print("VirtualMatrixPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") ");
// to
Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") ");
*/
if ( (y & 8) == 0) {
coords.x += ((coords.x / panelResX)+1)*panelResX; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer
}
else {
coords.x += (coords.x / panelResX)*panelResX; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer
}
// http://cpp.sh/4ak5u
// Real number of DMA y rows is half reality
// coords.y = (y / 16)*8 + (y & 0b00000111);
coords.y = (y >> 4)*8 + (y & 0b00000111);
/*
Serial.print("OneEightScanPanel Mapping ("); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(") ");
// to
Serial.print("to ("); Serial.print(coords.x, DEC); Serial.print(","); Serial.print(coords.y, DEC); Serial.println(") ");
*/
return coords;
}
#endif

View file

@ -15,8 +15,10 @@
**************************************************************************/ **************************************************************************/
#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" #include "ESP32-HUB75-MatrixPanel-I2S-DMA.h"
// Virtual Display to re-map co-ordinates such that they draw correctly on a 32x16 1/4 Scan panel /* Use the Virtual Display class to re-map co-ordinates such that they draw
#include "1_8_ScanPanel.h" * correctly on a 32x16 1/8 Scan panel (or chain of such panels).
*/
#include "ESP32-VirtualMatrixPanel-I2S-DMA.h"
// Panel configuration // Panel configuration
@ -37,7 +39,7 @@
MatrixPanel_I2S_DMA *dma_display = nullptr; MatrixPanel_I2S_DMA *dma_display = nullptr;
// placeholder for the virtual display object // placeholder for the virtual display object
OneEightScanPanel *OneEightMatrixDisplay = nullptr; VirtualMatrixPanel *OneEightMatrixDisplay = nullptr;
/****************************************************************************** /******************************************************************************
* Setup! * Setup!
@ -54,41 +56,43 @@
/* /*
// 62x32 1/8 Scan Panels don't have a D and E pin! // 62x32 1/8 Scan Panels don't have a D and E pin!
HUB75_I2S_CFG::i2s_pins _pins = { HUB75_I2S_CFG::i2s_pins _pins = {
R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN,
A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN,
LAT_PIN, OE_PIN, CLK_PIN LAT_PIN, OE_PIN, CLK_PIN
}; };
*/ */
HUB75_I2S_CFG mxconfig( HUB75_I2S_CFG mxconfig(
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
NUM_ROWS*NUM_COLS // DO NOT CHANGE THIS NUM_ROWS*NUM_COLS // DO NOT CHANGE THIS
//,_pins // Uncomment to enable custom pins //,_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.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 //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 // OK, now we can create our matrix object
dma_display = new MatrixPanel_I2S_DMA(mxconfig); dma_display = new MatrixPanel_I2S_DMA(mxconfig);
// let's adjust default brightness to about 75% // let's adjust default brightness to about 75%
dma_display->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100% dma_display->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100%
// Allocate memory and start DMA display // Allocate memory and start DMA display
if( not dma_display->begin() ) if( not dma_display->begin() )
Serial.println("****** !KABOOM! I2S memory allocation failed ***********"); Serial.println("****** !KABOOM! I2S memory allocation failed ***********");
dma_display->clearScreen(); dma_display->clearScreen();
delay(500); delay(500);
// create OneEightMatrixDisplaylay object based on our newly created dma_display object // create OneEightMatrixDisplaylay object based on our newly created dma_display object
OneEightMatrixDisplay = new OneEightScanPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN); OneEightMatrixDisplay = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN);
// THE IMPORTANT BIT BELOW!
OneEightMatrixDisplay->setPhysicalPanelScanRate(ONE_EIGHT);
} }