diff --git a/ESP32-VirtualMatrixPanel-I2S-DMA.h b/ESP32-VirtualMatrixPanel-I2S-DMA.h index b6027a9..f4f1834 100644 --- a/ESP32-VirtualMatrixPanel-I2S-DMA.h +++ b/ESP32-VirtualMatrixPanel-I2S-DMA.h @@ -34,7 +34,8 @@ struct VirtualCoords { }; - +enum PANEL_SCAN_RATE {NORMAL_ONE_SIXTEEN, ONE_EIGHT}; + #ifdef USE_GFX_ROOT class VirtualMatrixPanel : public GFX #elif !defined NO_GFX @@ -107,6 +108,8 @@ class VirtualMatrixPanel void flipDMABuffer() { display->flipDMABuffer(); } void drawDisplayTest(); void setRotate(bool rotate); + + void setPhysicalPanelScanRate(PANEL_SCAN_RATE rate); protected: @@ -116,6 +119,8 @@ class VirtualMatrixPanel 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 _rotate = false; + + PANEL_SCAN_RATE _panelScanRate = NORMAL_ONE_SIXTEEN; }; // end Class header @@ -179,6 +184,47 @@ inline VirtualCoords VirtualMatrixPanel::getCoords(int16_t &x, int16_t &y) { coords.x = (dmaResX - 1) - coords.x; 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); return coords; @@ -205,6 +251,11 @@ inline void VirtualMatrixPanel::setRotate(bool rotate) { if (rotate) { setRotation(1); } else { setRotation(0); } } +inline void VirtualMatrixPanel::setPhysicalPanelScanRate(PANEL_SCAN_RATE rate) { + _panelScanRate=rate; +} + + #ifndef NO_GFX inline void VirtualMatrixPanel::drawDisplayTest() diff --git a/examples/One_Eight_1_8_ScanPanel/1_8_ScanPanel.h b/examples/One_Eight_1_8_ScanPanel/1_8_ScanPanel.h deleted file mode 100644 index 238b5a6..0000000 --- a/examples/One_Eight_1_8_ScanPanel/1_8_ScanPanel.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _ESP32_ONE_EIGHT_SCAN_PANEL -#define _ESP32_ONE_EIGHT_SCAN_PANEL - -#include - -/* 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 diff --git a/examples/One_Eight_1_8_ScanPanel/One_Eight_1_8_ScanPanel.ino b/examples/One_Eight_1_8_ScanPanel/One_Eight_1_8_ScanPanel.ino index 65050aa..a15367e 100644 --- a/examples/One_Eight_1_8_ScanPanel/One_Eight_1_8_ScanPanel.ino +++ b/examples/One_Eight_1_8_ScanPanel/One_Eight_1_8_ScanPanel.ino @@ -15,8 +15,10 @@ **************************************************************************/ #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 -#include "1_8_ScanPanel.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 @@ -37,7 +39,7 @@ MatrixPanel_I2S_DMA *dma_display = nullptr; // placeholder for the virtual display object - OneEightScanPanel *OneEightMatrixDisplay = nullptr; + VirtualMatrixPanel *OneEightMatrixDisplay = nullptr; /****************************************************************************** * Setup! @@ -54,41 +56,43 @@ /* // 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, 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 - ); + 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 + //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); + // 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% + // 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 ***********"); + // Allocate memory and start DMA display + if( not dma_display->begin() ) + Serial.println("****** !KABOOM! I2S memory allocation failed ***********"); dma_display->clearScreen(); delay(500); - // 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); - + // create OneEightMatrixDisplaylay object based on our newly created dma_display object + 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); }