diff options
| author | mrfaptastic <12006953+mrfaptastic@users.noreply.github.com> | 2021-02-10 15:49:19 +0000 |
|---|---|---|
| committer | mrfaptastic <12006953+mrfaptastic@users.noreply.github.com> | 2021-02-10 15:49:19 +0000 |
| commit | 0749fa41932cc163a46801c1c1d6d2a309e8f273 (patch) | |
| tree | 396fd65acebf24c2335399039819485dc930ead1 /examples | |
| parent | 6ea2280ff3af21828974832402270ce54e52c5cc (diff) | |
Update to 2.0.0
Also known as the @vortigont release! Hooray!
Diffstat (limited to 'examples')
32 files changed, 1731 insertions, 333 deletions
diff --git a/examples/testshapes_32x64/testshapes_32x64.ino b/examples/1_SimpleTestShapes/1_SimpleTestShapes.ino index e3746fe..80f2236 100644 --- a/examples/testshapes_32x64/testshapes_32x64.ino +++ b/examples/1_SimpleTestShapes/1_SimpleTestShapes.ino @@ -1,9 +1,23 @@ +// Example sketch which shows how to display some patterns +// on a 64x32 LED matrix +// + #include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> -MatrixPanel_I2S_DMA dma_display; -// Or use an Alternative non-DMA library, i.e: -//#include <P3RGB64x32MatrixPanel.h> -//P3RGB64x32MatrixPanel display; +/* + * Below is an example of the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. Matrix Width and Height will need to be confirmed as compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths. + * + */ + MatrixPanel_I2S_DMA dma_display; + + // Or use an Alternative non-DMA library, i.e: + //#include <P3RGB64x32MatrixPanel.h> + //P3RGB64x32MatrixPanel display; void setup() { @@ -94,26 +108,6 @@ void setup() { dma_display.setTextColor(dma_display.color444(15,0,8)); dma_display.println("*"); - delay(2000); -/* - for (int i = 15; i > 0; i--) - { - // fade out - dma_display.fillScreen(dma_display.color565(0, 0, i*17)); - delay(250); - } - - for (int i = 15; i > 0; i--) - { - // draw a blue circle - dma_display.drawCircle(10, 10, 10, dma_display.color565(i*17, 0, 0)); - delay(250); - } -*/ - - - - // whew! } void loop() { diff --git a/examples/2_PatternPlasma/2_PatternPlasma.ino b/examples/2_PatternPlasma/2_PatternPlasma.ino new file mode 100644 index 0000000..b7bc791 --- /dev/null +++ b/examples/2_PatternPlasma/2_PatternPlasma.ino @@ -0,0 +1,207 @@ +/* + * Portions of this code are adapted from Aurora: https://github.com/pixelmatix/aurora + * Copyright (c) 2014 Jason Coon + * + * Portions of this code are adapted from LedEffects Plasma by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Plasma.cpp?at=default + * Copyright (c) 2013 Robert Atkins + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +// HUB75E pinout +// R1 | G1 +// B1 | GND +// R2 | G2 +// B2 | E +// A | B +// C | D +// CLK| LAT +// OE | GND + +/* Default library pin configuration for the reference + you can redefine only ones you need later on object creation + +#define R1 25 +#define G1 26 +#define BL1 27 +#define R2 14 +#define G2 12 +#define BL2 13 +#define CH_A 23 +#define CH_B 19 +#define CH_C 5 +#define CH_D 17 +#define CH_E -1 // assign to any available pin if using two panels or 64x64 panels with 1/32 scan +#define CLK 16 +#define LAT 4 +#define OE 15 + +*/ + + +#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> +#include <FastLED.h> + +// Configure for your panel(s) as appropriate! +#define PANEL_WIDTH 64 +#define PANEL_HEIGHT 64 // Panel height of 64 will required PIN_E to be defined. +#define PANELS_NUMBER 2 // Number of chained panels, if just a single panel, obviously set to 1 +#define PIN_E 32 + +#define PANE_WIDTH PANEL_WIDTH * PANELS_NUMBER +#define PANE_HEIGHT PANEL_HEIGHT + + +// placeholder for the matrix object +MatrixPanel_I2S_DMA *dma_display = nullptr; + + +uint16_t time_counter = 0, cycles = 0, fps = 0; +unsigned long fps_timer; + +CRGB currentColor; +CRGBPalette16 palettes[] = {HeatColors_p, LavaColors_p, RainbowColors_p, RainbowStripeColors_p, CloudColors_p}; +CRGBPalette16 currentPalette = palettes[0]; + + +CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { + return ColorFromPalette(currentPalette, index, brightness, blendType); +} + +void setup() { + + Serial.begin(115200); + + Serial.println(F("*****************************************************")); + Serial.println(F("* ESP32-HUB75-MatrixPanel-I2S-DMA DEMO *")); + Serial.println(F("*****************************************************")); + + /* + The configuration for MatrixPanel_I2S_DMA object is held in HUB75_I2S_CFG structure, + pls refer to the lib header file for full details. + All options has it's predefined default values. So we can create a new structure and redefine only the options we need + + // those are the defaults + mxconfig.mx_width = 64; // physical width of a single matrix panel module (in pixels, usually it is always 64 ;) ) + mxconfig.mx_height = 32; // physical height of a single matrix panel module (in pixels, usually amost always it is either 32 or 64) + mxconfig.chain_length = 1; // number of chained panels regardless of the topology, default 1 - a single matrix module + mxconfig.gpio.r1 = R1; // pin mappings + mxconfig.gpio.g1 = G1; + mxconfig.gpio.b1 = B1; // etc + mxconfig.driver = HUB75_I2S_CFG::SHIFT; // shift reg driver, default is plain shift register + mxconfig.double_buff = false; // use double buffer (twice amount of RAM required) + mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M;// I2S clock speed, better leave as-is unless you want to experiment + */ + + /* + For example we have two 64x64 panels chained, so we need to customize our setup like this + + */ + HUB75_I2S_CFG mxconfig; + mxconfig.mx_height = PANEL_HEIGHT; // we have 64 pix heigh panels + mxconfig.chain_length = PANELS_NUMBER; // we have 2 panels chained + mxconfig.gpio.e = PIN_E; // we MUST assign pin e to some free pin on a board to drive 64 pix height panels with 1/32 scan + //mxconfig.driver = HUB75_I2S_CFG::FM6126A; // in case that we use panels based on FM6126A chip, we can change that + + /* + //Another way of creating config structure + //Custom pin mapping for all pins + HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK}; + HUB75_I2S_CFG mxconfig( + 64, // width + 64, // height + 4, // chain length + _pins, // pin mapping + HUB75_I2S_CFG::FM6126A // driver chip + ); + + */ + + + // 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 ***********"); + + // well, hope we are OK, let's draw some colors first :) + Serial.println("Fill screen: RED"); + dma_display->fillScreenRGB888(255, 0, 0); + delay(1000); + + Serial.println("Fill screen: GREEN"); + dma_display->fillScreenRGB888(0, 255, 0); + delay(1000); + + Serial.println("Fill screen: BLUE"); + dma_display->fillScreenRGB888(0, 0, 255); + delay(1000); + + Serial.println("Fill screen: Neutral White"); + dma_display->fillScreenRGB888(64, 64, 64); + delay(1000); + + Serial.println("Fill screen: black"); + dma_display->fillScreenRGB888(0, 0, 0); + delay(1000); + + + // Set current FastLED palette + currentPalette = RainbowColors_p; + Serial.println("Starting plasma effect..."); + fps_timer = millis(); +} + +void loop() { + + for (int x = 0; x < PANE_WIDTH; x++) { + for (int y = 0; y < PANE_HEIGHT; y++) { + int16_t v = 0; + uint8_t wibble = sin8(time_counter); + v += sin16(x * wibble * 3 + time_counter); + v += cos16(y * (128 - wibble) + time_counter); + v += sin16(y * x * cos8(-time_counter) / 8); + + currentColor = ColorFromPalette(currentPalette, (v >> 8) + 127); //, brightness, currentBlendType); + dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); + } + } + + ++time_counter; + ++cycles; + ++fps; + + if (cycles >= 1024) { + time_counter = 0; + cycles = 0; + currentPalette = palettes[random(0,sizeof(palettes)/sizeof(palettes[0]))]; + } + + // print FPS rate every 5 seconds + // Note: this is NOT a matrix refresh rate, it's the number of data frames being drawn to the DMA buffer per second + if (fps_timer + 5000 < millis()){ + Serial.printf_P(PSTR("Effect fps: %d\n"), fps/5); + fps_timer = millis(); + fps = 0; + } +} // end loop
\ No newline at end of file diff --git a/examples/PatternPlasma/PatternWave.jpg b/examples/2_PatternPlasma/PatternWave.jpg Binary files differindex e6ce3c3..e6ce3c3 100644 --- a/examples/PatternPlasma/PatternWave.jpg +++ b/examples/2_PatternPlasma/PatternWave.jpg diff --git a/examples/PatternPlasma/README.md b/examples/2_PatternPlasma/README.md index 172a99f..172a99f 100644 --- a/examples/PatternPlasma/README.md +++ b/examples/2_PatternPlasma/README.md diff --git a/examples/FM6126Panel/FM6126Panel.ino b/examples/3_FM6126Panel/3_FM6126Panel.ino index 45eae70..114247c 100644 --- a/examples/FM6126Panel/FM6126Panel.ino +++ b/examples/3_FM6126Panel/3_FM6126Panel.ino @@ -3,47 +3,23 @@ #include <Arduino.h> #include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> - -MatrixPanel_I2S_DMA dma_display; - #include <FastLED.h> //////////////////////////////////////////////////////////////////// -// Reset Panel // FM6126 support is still experimental -// -// pinout for ESP38 38pin module -// http://arduinoinfo.mywikis.net/wiki/Esp32#KS0413_keyestudio_ESP32_Core_Board -// -// HUB75E pinout -// R1 | G1 -// B1 | GND -// R2 | G2 -// B2 | E -// A | B -// C | D -// CLK| LAT -// OE | GND +// Output resolution and panel chain length 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 PANEL_CHAIN 1 // Total number of panels chained one to another + -#define R1 25 -#define G1 26 -#define BL1 27 -#define R2 14 // 21 SDA -#define G2 12 // 22 SDL -#define BL2 13 -#define CH_A 23 -#define CH_B 19 -#define CH_C 5 -#define CH_D 17 -#define CH_E -1 // assign to any available pin if using two panels or 64x64 panels with 1/32 scan (i.e. 32 works fine) -#define CLK 16 -#define LAT 4 -#define OE 15 +// placeholder for the matrix object +MatrixPanel_I2S_DMA *dma_display = nullptr; -// End of default setup for RGB Matrix 64x32 panel /////////////////////////////////////////////////////////////// +// FastLED variables for pattern output uint16_t time_counter = 0, cycles = 0, fps = 0; unsigned long fps_timer; @@ -57,38 +33,44 @@ CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlend } void setup(){ + + /* + The configuration for MatrixPanel_I2S_DMA object is held in HUB75_I2S_CFG structure, + All options has it's predefined default values. So we can create a new structure and redefine only the options we need - // If you experience ghosting, you will need to reduce the brightness level, not all RGB Matrix - // Panels are the same - some seem to display ghosting artefacts at lower brightness levels. - // In the setup() function do something like: - - // SETS THE BRIGHTNESS HERE. MAX value is MATRIX_WIDTH, 2/3 OR LOWER IDEAL, default is about 50% - // dma_display.setPanelBrightness(30); + Please refer to the '2_PatternPlasma.ino' example for detailed example of how to use the MatrixPanel_I2S_DMA configuration + if you need to change the pin mappings etc. + */ - /* another way to change brightness is to use - * dma_display.setPanelBrightness8(uint8_t brt); // were brt is within range 0-255 - * it will recalculate to consider matrix width automatically - */ - //dma_display.setPanelBrightness8(180); + HUB75_I2S_CFG mxconfig( + PANEL_RES_X, // module width + PANEL_RES_Y, // module height + PANEL_CHAIN // Chain length + ); - /** - * this demo runs pretty fine in fast-mode which gives much better fps on large matrixes (>128x64) - * see comments in the lib header on what does that means - */ - dma_display.setFastMode(true); + 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 - /** - * Run display on our matrix, be sure to specify 'FM6126A' as last parametr to the begin(), - * it would reset 6126 registers and enables the matrix - */ - dma_display.begin(R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK, FM6126A); + // OK, now we can create our matrix object + dma_display = new MatrixPanel_I2S_DMA(mxconfig); + + // If you experience ghosting, you will need to reduce the brightness level, not all RGB Matrix + // Panels are the same - some seem to display ghosting artefacts at lower brightness levels. + // In the setup() function do something like: + // 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! Insufficient memory - allocation failed ***********"); + fps_timer = millis(); + } void loop(){ - for (int x = 0; x < dma_display.width(); x++) { - for (int y = 0; y < dma_display.height(); y++) { + for (int x = 0; x < dma_display->width(); x++) { + for (int y = 0; y < dma_display->height(); y++) { int16_t v = 0; uint8_t wibble = sin8(time_counter); v += sin16(x * wibble * 3 + time_counter); @@ -96,7 +78,7 @@ void loop(){ v += sin16(y * x * cos8(-time_counter) / 8); currentColor = ColorFromPalette(currentPalette, (v >> 8) + 127); //, brightness, currentBlendType); - dma_display.drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); + dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); } } diff --git a/examples/3_FM6126Panel/FM6126A.md b/examples/3_FM6126Panel/FM6126A.md new file mode 100644 index 0000000..bfab4a5 --- /dev/null +++ b/examples/3_FM6126Panel/FM6126A.md @@ -0,0 +1,51 @@ +## The mystery of control registers for FM6126A chips + + +The only available Datasheet for this chips is in Chinese and does not shed a light on what those two control regs are. + +An excellent insight could be found here https://github.com/hzeller/rpi-rgb-led-matrix/issues/746#issuecomment-453860510 + + + +So there are two regs in this chip - **REG1** and **REG2**, +one could be written with 12 clock pusles (and usually called reg12, dunno why :)) +the other one could be written with 13 clock pulses (and usually called reg13, dunno why :)) + + +I've done some measurmens on power consumption while toggling bits of **REG1** and it looks that it could provide a fine grained brighness control over the entire matrix with no need for bitbanging over RGB or EO pins. +There are 6 bits (6 to 11) giving an increased brighness (compared to all-zeroes) and 4 bits (2-5) giving decreased brighness!!! +Still unclear if FM6112A brightness control is internally PWMed or current limited, might require some poking with oscilloscope. + +So it seems that the most bright (and hungry for power) value is bool REG1[16] = {0,0,0,0,0, 1,1,1,1,1,1, 0,0,0,0,0}; and not {0,1,1,1,1, 1,1,1,1,1,1, 1,1,1,1,1} as it is usually used. +I'm not sure about bit 1 - it is either not used or I was unable to measure it's influence to brightness/power. + +Giving at least 10 bits of hardware brightness control opens pretty nice options for offloading and simplifiyng matrix output. Should dig into this more deeper. + +Here are some of the measurments I've took for 2 64x64 panels filled with white color - reg value and corresponding current drain in amps. + + +|REG1 |bit value|Current, amps | +|--|--|--| +|REG1| 0111111 00000| >5 amps| +|REG1| 0100010 00000| 3.890 amp| +|REG1| 0100000 00000| 3.885 amp| +|REG1| 0011110 00000| 3.640 amp| +|REG1| 0011100 00000| 3.620 amp| +|REG1| 0011000 00000| 3.240 amp| +|REG1| 0010010 00000| 2.520 amp| +|REG1| 0010001 00000| 2.518 amp| +|REG1| 0010001 10000| 2.493 amp| +|REG1| 0010000 00000| 2.490 amp| +|REG1| 0010000 11110| 2.214 amp| +|REG1| 0001100 00000| 2.120 amp| +|REG1| 0001000 00000| 1.750 amp| +|REG1| 0000100 00000| 1.375 amp| +|REG1| 0000010 00000| 1.000 amp| +|REG1| **0000000 00000**| 0.995 amp| +|REG1| 0000001 11111| 0.700 amp| +|REG1| 0000000 01111| 0.690 amp| +|REG1| 0000000 10000| 0.690 amp| +|REG1| 0000000 11110| 0.686 amp| + + +/Vortigont/
\ No newline at end of file diff --git a/examples/FM6126Panel/README.md b/examples/3_FM6126Panel/README.md index 4683446..4683446 100644 --- a/examples/FM6126Panel/README.md +++ b/examples/3_FM6126Panel/README.md diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel.ino b/examples/AnimatedGIFPanel/AnimatedGIFPanel.ino index 75e0d4f..d3c9916 100644 --- a/examples/AnimatedGIFPanel/AnimatedGIFPanel.ino +++ b/examples/AnimatedGIFPanel/AnimatedGIFPanel.ino @@ -25,7 +25,18 @@ // ---------------------------- +/* + * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths within the sketch 'setup()'. + * + */ MatrixPanel_I2S_DMA dma_display; + + AnimatedGIF gif; File f; int x_offset, y_offset; diff --git a/examples/AuroraDemo/AuroraDemo.ino b/examples/AuroraDemo/AuroraDemo.ino index 817780e..7ed10fa 100644 --- a/examples/AuroraDemo/AuroraDemo.ino +++ b/examples/AuroraDemo/AuroraDemo.ino @@ -22,6 +22,16 @@ /* -------------------------- Class Initialisation -------------------------- */ #include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> + +/* + * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths within the sketch 'setup()'. + * + */ MatrixPanel_I2S_DMA matrix; #include <FastLED.h> diff --git a/examples/BitmapIcons/BitmapIcons.ino b/examples/BitmapIcons/BitmapIcons.ino index 09c6815..8f86135 100644 --- a/examples/BitmapIcons/BitmapIcons.ino +++ b/examples/BitmapIcons/BitmapIcons.ino @@ -27,7 +27,15 @@ #define CLK_PIN 16 -// Display +/* + * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths within the sketch 'setup()'. + * + */ MatrixPanel_I2S_DMA display; // RGB Panel // Wifi Logo, generated using LCD Image Converter: http://www.riuson.com/lcd-image-converter diff --git a/examples/ChainedPanels/ChainedPanels.ino b/examples/ChainedPanels/ChainedPanels.ino index a45f9c1..57fa15b 100644 --- a/examples/ChainedPanels/ChainedPanels.ino +++ b/examples/ChainedPanels/ChainedPanels.ino @@ -3,19 +3,9 @@ Steps to use ----------- - 1) In ESP32-HUB75-MatrixPanel-I2S-DMA.h: - - - Set the MATRIX_HEIGHT to be the y resolution of a physical chained - panels in the line (as panels each must be of the same dimensions). - i.e. If you are chaining 32px 'high' panels, then set MATRIX_HEIGHT to 32. - - - Set the MATRIX_WIDTH to be the sum of the x resolution of all the physical - chained panels (i.e. If you have 4 (four) x (64px w x 32px h) panels, then 64x4 = 256) - i.e. The total pixel 'width' of all the chained panels. - - 2) In the sketch (i.e. this example): + 1) In the sketch (i.e. this example): - - Set values for NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y. + - Set values for NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, PANEL_CHAIN. There are comments beside them explaining what they are in more detail. - Other than where the matrix is defined and matrix.begin in the setup, you should now be using the virtual display for everything (drawing pixels, writing text etc). @@ -39,25 +29,6 @@ *****************************************************************************/ -//#define USE_CUSTOM_PINS // uncomment to use custom pins, then provide below - -#define A_PIN 26 -#define B_PIN 4 -#define C_PIN 27 -#define D_PIN 2 -#define E_PIN 21 - -#define R1_PIN 5 -#define R2_PIN 19 -#define G1_PIN 17 -#define G2_PIN 16 -#define B1_PIN 18 -#define B2_PIN 25 - -#define CLK_PIN 14 -#define LAT_PIN 15 -#define OE_PIN 13 - /****************************************************************************** * VIRTUAL DISPLAY / MATRIX PANEL CHAINING CONFIGURATION @@ -168,14 +139,16 @@ #define NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS #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 - -/****************************************************************************** - * Create physical DMA panel class AND virtual (chained) display class. - ******************************************************************************/ +// library includes #include <ESP32-VirtualMatrixPanel-I2S-DMA.h> -MatrixPanel_I2S_DMA dma_display; -VirtualMatrixPanel virtualDisp(dma_display, NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, true); + +// placeholder for the matrix object +MatrixPanel_I2S_DMA *dma_display = nullptr; + +// placeholder for the virtual display object +VirtualMatrixPanel *virtualDisp = nullptr; /****************************************************************************** @@ -190,29 +163,47 @@ void setup() { Serial.println(" HELLO !"); Serial.println("*****************************************************"); -#ifdef USE_CUSTOM_PINS - dma_display.begin(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 ); // setup the LED matrix -#else - dma_display.begin(); -#endif + /****************************************************************************** + * Create physical DMA panel class AND virtual (chained) display class. + ******************************************************************************/ + + /* + The configuration for MatrixPanel_I2S_DMA object is held in HUB75_I2S_CFG structure, + All options has it's predefined default values. So we can create a new structure and redefine only the options we need + Please refer to the '2_PatternPlasma.ino' example for detailed example of how to use the MatrixPanel_I2S_DMA configuration + */ + + HUB75_I2S_CFG mxconfig( + PANEL_RES_X, // module width + PANEL_RES_Y, // module height + PANEL_CHAIN // chain length + ); + + //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 // Sanity checks if (NUM_ROWS <= 1) { Serial.println(F("There is no reason to use the VirtualDisplay class for a single horizontal chain and row!")); } - if (dma_display.width() != NUM_ROWS*NUM_COLS*PANEL_RES_X ) - { - Serial.println(F("\r\nERROR: MATRIX_WIDTH and/or MATRIX_HEIGHT in 'ESP32-HUB75-MatrixPanel-I2S-DMA.h'\r\nis not configured correctly for the requested VirtualMatrixPanel dimensions!\r\n")); - Serial.printf("WIDTH according dma_display is %d, but should be %d. Is your NUM_ROWS and NUM_COLS correct?\r\n", dma_display.width(), NUM_ROWS*NUM_COLS*PANEL_RES_X); - return; - } - + // 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 ***********"); + + // create VirtualDisplay object based on our newly created dma_display object + virtualDisp = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, true); + // So far so good, so continue - virtualDisp.fillScreen(virtualDisp.color444(0, 0, 0)); - virtualDisp.drawDisplayTest(); // draw text numbering on each screen to check connectivity + virtualDisp->fillScreen(virtualDisp->color444(0, 0, 0)); + virtualDisp->drawDisplayTest(); // draw text numbering on each screen to check connectivity delay(3000); @@ -225,20 +216,17 @@ void setup() { Serial.println("| (ESP) | |"); Serial.println("+--------+---------+"); - virtualDisp.setFont(&FreeSansBold12pt7b); - virtualDisp.setTextColor(virtualDisp.color565(0, 0, 255)); - virtualDisp.setTextSize(2); - virtualDisp.setCursor(10, virtualDisp.height()-20); + virtualDisp->setFont(&FreeSansBold12pt7b); + virtualDisp->setTextColor(virtualDisp->color565(0, 0, 255)); + virtualDisp->setTextSize(2); + virtualDisp->setCursor(10, virtualDisp->height()-20); // Red text inside red rect (2 pix in from edge) - virtualDisp.print("1234") ; - virtualDisp.drawRect(1,1, virtualDisp.width()-2, virtualDisp.height()-2, virtualDisp.color565(255,0,0)); + virtualDisp->print("1234"); + virtualDisp->drawRect(1,1, virtualDisp->width()-2, virtualDisp->height()-2, virtualDisp->color565(255,0,0)); // White line from top left to bottom right - virtualDisp.drawLine(0,0, virtualDisp.width()-1, virtualDisp.height()-1, virtualDisp.color565(255,255,255)); - - - + virtualDisp->drawLine(0,0, virtualDisp->width()-1, virtualDisp->height()-1, virtualDisp->color565(255,255,255)); } void loop() { diff --git a/examples/ChainedPanels/README.md b/examples/ChainedPanels/README.md index f9b8f18..ca55860 100644 --- a/examples/ChainedPanels/README.md +++ b/examples/ChainedPanels/README.md @@ -1,35 +1,33 @@ ## Chained Panels example - Chaining individual LED matrix panels to make a larger panel ## -This is the PatternPlasma Demo adopted for use with multiple -displays arranged in a non standard order +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. -### What is a non standard order? ### +### What do we mean by 'non standard order'? ### -When you connect multiple panels together, the library treats the -multiple panels as one big panel arranged horizontally. Arranging -the displays like this would be a standard order. +When you link / chain multiple panels together, the ESP32-HUB75-MatrixPanel-I2S-DMA library treats as one wide horizontal panel. This would be a 'standard' (default) order. -Non-standard order is essentially the creation of a non-horizontal only 'virtual' display that you can draw to in the same way you would -the matrix, but with VirtualDisplay library looking after the pixel mapping to the physical chained panels. +Non-standard order is essentially the creation of a non-horizontal-only display that you can draw to in the same way you would any other display, with VirtualDisplay library looking after the pixel mapping to the physical chained panels. + +For example: You bought four (4) 64x32px panels, and wanted to use them to create a 128x64pixel display. You would use the VirtualMatrixPanel class. + +[Refer to this document](VirtualMatrixPanel.pdf) for an explanation and refer to this example on how to use. -[Refer to this document](VirtualDisplay.pdf) for the guide on how to use. ### Steps to Use ### -1) In ESP32-HUB75-MatrixPanel-I2S-DMA.h: +1. [Refer to this document](VirtualMatrixPanel.pdf) for an explanation and refer to this example on how to use. + +2. In your Arduino sketch, configure these defines accordingly: +``` +#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. -- Set the MATRIX_HEIGHT to be the y resolution of the physical chained panels in a line (if the panels are 32 x 16, set it to be 16) -- Set the MATRIX_WIDTH to be the sum of the x resolution of all the physical chained panels (i.e. If you have 4 x (32px w x 16px h) panels, 32x4 = 128) +#define NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS +#define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW +``` -2) In the sketch: +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). -- Set values for NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y. There are comments beside them -explaining what they are in more detail. -- Other than where the matrix is defined and matrix.begin in the setup, you should now be using the virtual display -for everything (drawing pixels, writing text etc). You can do a find and replace of all calls if it's an existing sketch -(just make sure you don't replace the definition and the matrix.begin) -- If the sketch makes use of MATRIX_HEIGHT or MATRIX_WIDTH, these will need to be replaced with the width and height -of your virtual screen. Either make new defines and use that, or you can use virtualDisp.width() or .height() #### Thanks to #### * Brian Lough for the Virtual to Real pixel co-ordinate code. diff --git a/examples/ChainedPanels/VirtualDisplay.pdf b/examples/ChainedPanels/VirtualDisplay.pdf Binary files differdeleted file mode 100644 index 97eda05..0000000 --- a/examples/ChainedPanels/VirtualDisplay.pdf +++ /dev/null diff --git a/examples/ChainedPanels/VirtualMatrixPanel.odp b/examples/ChainedPanels/VirtualMatrixPanel.odp Binary files differnew file mode 100644 index 0000000..8245a1a --- /dev/null +++ b/examples/ChainedPanels/VirtualMatrixPanel.odp diff --git a/examples/ChainedPanels/VirtualMatrixPanel.pdf b/examples/ChainedPanels/VirtualMatrixPanel.pdf Binary files differnew file mode 100644 index 0000000..c0220a7 --- /dev/null +++ b/examples/ChainedPanels/VirtualMatrixPanel.pdf diff --git a/examples/ChainedPanelsAuroraDemo/ChainedPanelsAuroraDemo.ino b/examples/ChainedPanelsAuroraDemo/ChainedPanelsAuroraDemo.ino index 2800835..4d89944 100644 --- a/examples/ChainedPanelsAuroraDemo/ChainedPanelsAuroraDemo.ino +++ b/examples/ChainedPanelsAuroraDemo/ChainedPanelsAuroraDemo.ino @@ -1,38 +1,42 @@ -/* ------------------------- CUSTOM GPIO PIN MAPPING ------------------------- */ -// Kosso's ESP32 Matrix PCB pins -#define R1_PIN 2 -#define G1_PIN 15 -#define B1_PIN 4 -#define R2_PIN 16 -#define G2_PIN 13 -#define B2_PIN 17 -#define A_PIN 5 -#define B_PIN 18 -#define C_PIN 19 -#define D_PIN 27 -#define E_PIN -1 -#define LAT_PIN 21 -#define OE_PIN 23 -#define CLK_PIN 22 +#include <Arduino.h> +/* Default library pin configuration for the reference + you can redefine only ones you need later on object creation -/* -------------------------- Display Config Initialisation -------------------- */ -// MATRIX_WIDTH and MATRIX_HEIGHT *must* be changed in ESP32-HUB75-MatrixPanel-I2S-DMA.h -// If you are using Platform IO (you should), pass MATRIX_WIDTH and MATRIX_HEIGHT as a compile time option. -// Refer to: https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/48#issuecomment-749402379 +#define R1 25 +#define G1 26 +#define BL1 27 +#define R2 14 +#define G2 12 +#define BL2 13 +#define CH_A 23 +#define CH_B 19 +#define CH_C 5 +#define CH_D 17 +#define CH_E -1 // assign to any available pin if using two panels or 64x64 panels with 1/32 scan +#define CLK 16 +#define LAT 4 +#define OE 15 + +*/ -//This will not work here -> #define MATRIX_WIDTH 128 // Overall matrix dimensions if laid out end-to-end. -//This will not work here -> #define MATRIX_HEIGHT 32 +/* -------------------------- Display Config Initialisation -------------------- */ +// Assume we have four 64x32 panels daizy-chained and ESP32 attached to the bottom right corner #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 -#define NUM_COLS 1 // Number of INDIVIDUAL PANELS per ROW +#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 -// Virtual Panl dimensions -#define VPANEL_W 64 // Kosso: All Pattern files have had the MATRIX_WIDTH and MATRIX_HEIGHT replaced by these. -#define VPANEL_H 64 // +// Change this to your needs, for details on VirtualPanel pls see ChainedPanels example +#define SERPENT false +#define TOPDOWN false + +// Virtual Panl dimensions - our combined panel would be a square 4x4 modules with a combined resolution of 128x128 pixels +#define VPANEL_W PANEL_RES_X*NUM_COLS // Kosso: All Pattern files have had the MATRIX_WIDTH and MATRIX_HEIGHT replaced by these. +#define VPANEL_H PANEL_RES_Y*NUM_ROWS // // Kosso added: Button with debounce #define BTN_PIN 0 // Pattern advance. Using EPS32 Boot button. @@ -50,32 +54,33 @@ int lastPattern = 0; /* -------------------------- Class Initialisation -------------------------- */ -//#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> -//MatrixPanel_I2S_DMA matrix; - #include <ESP32-VirtualMatrixPanel-I2S-DMA.h> -MatrixPanel_I2S_DMA matrix; -// Added support for 'Chained' virtual panel configurations. -VirtualMatrixPanel virtualDisp(matrix, NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, true); - #include <FastLED.h> // Used for some mathematics calculations and effects. +// placeholder for the matrix object +MatrixPanel_I2S_DMA *matrix = nullptr; + +// placeholder for the virtual display object +VirtualMatrixPanel *virtualDisp = nullptr; + +// Aurora related #include "Effects.h" Effects effects; #include "Drawable.h" #include "Playlist.h" //#include "Geometry.h" - #include "Patterns.h" Patterns patterns; /* -------------------------- Some variables -------------------------- */ unsigned long ms_current = 0; unsigned long ms_previous = 0; -unsigned long ms_animation_max_duration = 60000; // 10 seconds +unsigned long ms_animation_max_duration = 20000; // 10 seconds unsigned long next_frame = 0; +void listPatterns(); + void setup() { // Setup serial interface @@ -87,19 +92,37 @@ void setup() // For saving last pattern index. TO reboot with same. preferences.begin("RGBMATRIX", false); lastPattern = preferences.getInt("lastPattern", 0); - - matrix.setPanelBrightness(30); - matrix.setMinRefreshRate(200); - - - matrix.begin(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 ); // setup the LED matrix - - virtualDisp.fillScreen(virtualDisp.color444(0, 0, 0)); - + + // Configure your matrix setup here + HUB75_I2S_CFG mxconfig(PANEL_RES_X, PANEL_RES_Y, PANEL_CHAIN); + + // custom pin mapping (if required) + //HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK}; + //mxconfig.gpio = _pins; + + // in case that we use panels based on FM6126A chip, we can change that + //mxconfig.driver = HUB75_I2S_CFG::FM6126A; + + // FM6126A panels could be cloked at 20MHz with no visual artefacts + // mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_20M; + + // OK, now we can create our matrix object + matrix = new MatrixPanel_I2S_DMA(mxconfig); + + // let's adjust default brightness to about 75% + matrix->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100% + + // Allocate memory and start DMA display + if( not matrix->begin() ) + Serial.println("****** !KABOOM! I2S memory allocation failed ***********"); + + // create VirtualDisplay object based on our newly created dma_display object + virtualDisp = new VirtualMatrixPanel((*matrix), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN); + Serial.println("**************** Starting Aurora Effects Demo ****************"); - Serial.println("MATRIX_WIDTH " + String(MATRIX_WIDTH)); - Serial.println("MATRIX_HEIGHT " + String(MATRIX_HEIGHT)); + Serial.print("MATRIX_WIDTH: "); Serial.println(PANEL_RES_X*PANEL_CHAIN); + Serial.print("MATRIX_HEIGHT: "); Serial.println(PANEL_RES_Y); #ifdef VPANEL_W Serial.println("VIRTUAL PANEL WIDTH " + String(VPANEL_W)); @@ -169,7 +192,7 @@ void loop() if ( (ms_current - ms_previous) > ms_animation_max_duration ) { - // patternAdvance(); + patternAdvance(); // just auto-change the palette effects.RandomPalette(); ms_previous = ms_current; diff --git a/examples/ChainedPanelsAuroraDemo/Drawable.h b/examples/ChainedPanelsAuroraDemo/Drawable.h index 40356f4..b2169fe 100644 --- a/examples/ChainedPanelsAuroraDemo/Drawable.h +++ b/examples/ChainedPanelsAuroraDemo/Drawable.h @@ -38,7 +38,7 @@ public: // a single frame should be drawn as fast as possible, without any delay or blocking // return how many millisecond delay is requested before the next call to drawFrame() virtual unsigned int drawFrame() { - matrix.fillScreen(0); + matrix->fillScreen(0); //backgroundLayer.fillScreen({ 0, 0, 0 }); return 0; }; diff --git a/examples/ChainedPanelsAuroraDemo/Effects.h b/examples/ChainedPanelsAuroraDemo/Effects.h index fa0ca45..9c1f623 100644 --- a/examples/ChainedPanelsAuroraDemo/Effects.h +++ b/examples/ChainedPanelsAuroraDemo/Effects.h @@ -112,8 +112,6 @@ uint8_t noisesmoothing; class Effects { public: CRGB *leds; - //CRGB leds[NUM_LEDS]; - //CRGB leds2[NUM_LEDS]; // Faptastic: getting rid of this and any dependant effects or algos. to save memory 24*64*32 bytes of ram (50k). Effects(){ // we do dynamic allocation for leds buffer, otherwise esp32 toolchain can't link static arrays of such a big size for 256+ matrixes @@ -127,7 +125,6 @@ public: } ClearFrame(); - matrix.clearScreen(); } ~Effects(){ free(leds); @@ -175,7 +172,7 @@ public: for (int x=0; x<VPANEL_W; ++x){ //Serial.printf("Flushing x, y coord %d, %d\n", x, y); uint16_t _pixel = XY16(x,y); - virtualDisp.drawPixelRGB888( x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b); + virtualDisp->drawPixelRGB888( x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b); } // end loop to copy fast led to the dma matrix } } diff --git a/examples/ChainedPanelsAuroraDemo/PatternInvaders.h b/examples/ChainedPanelsAuroraDemo/PatternInvaders.h index cad004c..98f3200 100644 --- a/examples/ChainedPanelsAuroraDemo/PatternInvaders.h +++ b/examples/ChainedPanelsAuroraDemo/PatternInvaders.h @@ -36,7 +36,7 @@ class PatternInvadersSmall : public Drawable { } void start() { - matrix.fillScreen(0); + matrix->fillScreen(0); } unsigned int drawFrame() { @@ -80,7 +80,7 @@ class PatternInvadersMedium : public Drawable { } void start() { - matrix.fillScreen(0); + matrix->fillScreen(0); } unsigned int drawFrame() { @@ -92,10 +92,10 @@ class PatternInvadersMedium : public Drawable { if (random(0, 2) == 1) color = color1; - matrix.fillRect(x + (i * 2), y + (j * 2), x + (i * 2 + 1), y + (j * 2 + 1), color); + matrix->fillRect(x + (i * 2), y + (j * 2), x + (i * 2 + 1), y + (j * 2 + 1), color); if (i < 2) - matrix.fillRect(x + (8 - i * 2), y + (j * 2), x + (9 - i * 2), y + (j * 2 + 1), color); + matrix->fillRect(x + (8 - i * 2), y + (j * 2), x + (9 - i * 2), y + (j * 2 + 1), color); } } @@ -122,11 +122,11 @@ class PatternInvadersLarge : public Drawable { } void start() { - matrix.fillScreen(0); + matrix->fillScreen(0); } unsigned int drawFrame() { - matrix.fillScreen(0); + matrix->fillScreen(0); CRGB color1 = effects.ColorFromCurrentPalette(random(0, 255)); @@ -138,10 +138,10 @@ class PatternInvadersLarge : public Drawable { color = color1; } - matrix.fillRect(1 + x * 6, 1 + y * 6, 5 + x * 6, 5 + y * 6, color); + matrix->fillRect(1 + x * 6, 1 + y * 6, 5 + x * 6, 5 + y * 6, color); if (x < 2) - matrix.fillRect(1 + (4 - x) * 6, 1 + y * 6, 5 + (4 - x) * 6, 5 + y * 6, color); + matrix->fillRect(1 + (4 - x) * 6, 1 + y * 6, 5 + (4 - x) * 6, 5 + y * 6, color); } } diff --git a/examples/ChainedPanelsAuroraDemo/PatternTest.h b/examples/ChainedPanelsAuroraDemo/PatternTest.h index 6f0544f..7a4a07d 100644 --- a/examples/ChainedPanelsAuroraDemo/PatternTest.h +++ b/examples/ChainedPanelsAuroraDemo/PatternTest.h @@ -12,7 +12,7 @@ class PatternTest : public Drawable { unsigned int drawFrame() { - matrix.fillScreen(matrix.color565(128, 0, 0)); + matrix->fillScreen(matrix->color565(128, 0, 0)); return 1000; } }; diff --git a/examples/DoubleBufferSwap/DoubleBufferSwap.ino b/examples/DoubleBufferSwap/DoubleBufferSwap.ino index 6d71f75..81e116d 100644 --- a/examples/DoubleBufferSwap/DoubleBufferSwap.ino +++ b/examples/DoubleBufferSwap/DoubleBufferSwap.ino @@ -1,5 +1,15 @@ #include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> + +/* + * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths within the sketch 'setup()'. + * + */ MatrixPanel_I2S_DMA display(true); // Note the TRUE -> Turns of secondary buffer - "double buffering"! // Double buffering is not enabled by default with the library. diff --git a/examples/GraphicsLayer/GraphicsLayer.ino b/examples/GraphicsLayer/GraphicsLayer.ino index 2c15d18..61f51bf 100644 --- a/examples/GraphicsLayer/GraphicsLayer.ino +++ b/examples/GraphicsLayer/GraphicsLayer.ino @@ -33,8 +33,18 @@ #include "Layer.h" // Layer Library #include "Fonts/FreeSansBold9pt7b.h" // include adafruit font -// Object creation +/* + * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths within the sketch 'setup()'. + * + */ MatrixPanel_I2S_DMA dma_display; // Create HUB75 DMA object + +// Create FastLED based graphic 'layers' Layer bgLayer(dma_display); // Create background Layer Layer textLayer(dma_display); // Create foreground Layer diff --git a/examples/P6_32x16_1_4_ScanPanel/P6_32x16_1_4_ScanPanel.ino b/examples/P6_32x16_1_4_ScanPanel/P6_32x16_1_4_ScanPanel.ino new file mode 100644 index 0000000..8efd79f --- /dev/null +++ b/examples/P6_32x16_1_4_ScanPanel/P6_32x16_1_4_ScanPanel.ino @@ -0,0 +1,223 @@ +/************************************************************************* + * Contributor: https://github.com/mrRobot62 + * + * Description: + * + * The underlying implementation of the ESP32-HUB75-MatrixPanel-I2S-DMA only + * supports output to 1/16 or 1/32 scan panels (two scan parallel scan lines) + * this is fixed and cannot be changed. + * + * However, it is possible to connect 1/4 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 (in this example, it is the 'dmaOutput' class). + * + * This is done by way of the 'QuarterScanMatrixPanel.h' class that sends + * adjusted x,y co-ordinates to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA + * library's drawPixel routine. + * + * Refer to the 'getCoords' function within 'QuarterScanMatrixPanel.h' + * + **************************************************************************/ + +// uncomment to use custom pins, then provide below +#define USE_CUSTOM_PINS + +/* Pin 1,3,5,7,9,11,13,15 */ +#define R1_PIN 25 +#define B1_PIN 27 +#define R2_PIN 14 +#define B2_PIN 13 +#define A_PIN 23 +#define C_PIN 5 +#define CLK_PIN 16 +#define OE_PIN 15 + +/* Pin 2,6,10,12,14 */ +#define G1_PIN 26 +#define G2_PIN 12 +#define B_PIN 19 +#define D_PIN 17 +#define LAT_PIN 4 +#define E_PIN -1 // required for 1/32 scan panels + +#include "QuarterScanMatrixPanel.h" // Virtual Display to re-map co-ordinates such that they draw correctly on a32x16 1/4 Scan panel +#include <Wire.h> + +/* + * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths within the sketch 'setup()'. + * + */ +MatrixPanel_I2S_DMA dmaOutput; + +// Create virtual 1/2 to 1/4 scan pixel co-ordinate mapping class. +QuarterScanMatrixPanel display(dmaOutput); + +#include <FastLED.h> + +int time_counter = 0; +int cycles = 0; + +CRGBPalette16 currentPalette; +CRGB currentColor; + + +CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { + return ColorFromPalette(currentPalette, index, brightness, blendType); +} + +typedef struct Matrix { + uint8_t x; + uint8_t y; +} Matrix; + +Matrix matrix; + + +void testSimpleChars(uint16_t timeout) { + + /** drawChar() **/ + Serial.println("draw chars with drawChar()"); + display.fillScreen(display.color444(0,0,0)); + + uint16_t myFGColor = display.color565(180,0,0); + uint16_t myBGColor = display.color565(0,50,0); + display.fillScreen(display.color444(0,0,0)); + display.drawChar(0,0,'X',myFGColor, myFGColor,1); + display.drawChar(16,1,'Y',myFGColor, myBGColor,1); + display.drawChar(3,9,'Z',myFGColor, myFGColor,1); + display.drawChar(16,9,'4',display.color565(0,220,0), myBGColor,1); + delay(timeout); + +} + +void testSimpleCharString(uint16_t timeout) { + uint8_t x,y,w,h; + w = 6; h=8; + x = 0; y=0; + display.fillScreen(display.color444(0,0,0)); + display.setTextFGColor(display.color565(0,60,180)); + display.setCursor(x,y); display.write('L'); + display.setCursor(x+w,y); display.write('u'); + display.setCursor(x+(2*w),y); display.write('n'); + display.setCursor(x+(3*w),y); display.write('a'); + display.setTextFGColor(display.color565(180,60,140)); + display.setCursor(x+(4*w),y); display.write('X'); + + delay(timeout); + +} + +void testTextString(uint16_t timeout) { + display.fillScreen(display.color444(0,0,0)); + display.setTextFGColor(display.color565(0,60,255)); + + display.setCursor(0,5); + display.write("HURRA"); + delay(timeout); +} + +void testWrapChar(const char c, uint16_t speed, uint16_t timeout) { + display.setTextWrap(true); + for (uint8_t i = 32; i > 0; i--) { + display.fillScreen(display.color444(0,0,0)); + display.setCursor(i, 5); + display.write(c); + delay(speed); + } + delay(timeout); +} + +void testScrollingChar(const char c, uint16_t speed, uint16_t timeout) { + Serial.println("Scrolling Char"); + uint16_t myFGColor = display.color565(180,0,0); + uint16_t myBGColor = display.color565(60,120,0); + display.fillScreen(display.color444(0,0,0)); + display.setTextWrap(true); + // from right to left with wrap + display.scrollChar(31,5,c, myFGColor, myFGColor, 1, speed); + // left out with wrap + delay(500); + display.scrollChar(0,5,c, myBGColor, myBGColor, 1, speed); + + delay(timeout); +} + +void testScrollingText(const char *str, uint16_t speed, uint16_t timeout) { + Serial.println("Scrolling Text as loop"); + // pre config + uint16_t red = display.color565(255,0,100); + uint16_t blue100 = display.color565(0,0,100); + uint16_t black = display.color565(0,0,0); + uint16_t green = display.color565(0,255,0); + uint16_t green150 = display.color565(0,150,0); + + display.fillScreen(display.color565(0,0,0)); + display.setCursor(31,5); + display.setScrollDir(1); + + /** black background **/ + display.setTextFGColor(green150); + display.scrollText("** Welcome **", speed); + display.fillScreen(black); + delay(timeout / 2) ; + + /** scrolling with colored background */ + display.fillRect(0,4,VP_WIDTH,8,blue100); + // scrolling, using default pixels size = length of string (not used parameter pixels) + display.setTextFGColor(red); + display.setTextBGColor(blue100); + display.scrollText(str, speed); + delay(timeout / 2) ; + + // same as above but now from left to right + display.setScrollDir(0); + display.setTextFGColor(blue100); + display.setTextBGColor(red); + display.fillRect(0,4,VP_WIDTH,8,red); + display.scrollText(str, speed, 0); + + delay(timeout); + display.fillScreen(black); + display.setTextFGColor(red); + + +} + +void setup() { + + Serial.begin(115200); + delay(500); + Serial.println("*****************************************************"); + Serial.println(" dmaOutput 32x16 !"); + Serial.println("*****************************************************"); + +#ifdef USE_CUSTOM_PINS + dmaOutput.begin(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 ); // setup the LED matrix +#else + display.begin(true); // init buffers +#endif + + // fill the screen with 'black' + display.fillScreen(display.color444(0, 0, 0)); + + // Set current FastLED palette + currentPalette = RainbowColors_p; + // display.fillScreen(display.color565(0, 0, 0)); +} + +void loop() { + display.fillScreen(display.color444(0, 0, 0)); + //testSimpleChars(1500); + //testSimpleCharString (1500); + testTextString(2000); + // length = 16 bytes without \0 + //testWrapChar('A', 250, 1500); + //testScrollingChar('X', 250, 2000); + testScrollingText("Scrolling 16x32", 100, 2000); +} // end loop
\ No newline at end of file diff --git a/examples/P6_32x16_1_4_ScanPanel/QuarterScanMatrixPanel.h b/examples/P6_32x16_1_4_ScanPanel/QuarterScanMatrixPanel.h new file mode 100644 index 0000000..b7955f5 --- /dev/null +++ b/examples/P6_32x16_1_4_ScanPanel/QuarterScanMatrixPanel.h @@ -0,0 +1,449 @@ + +/* + Patch class for 32x16 RGB Matrix panels + + reimplement all functions which use x,y coordinates + +*/ + +#ifndef ESP_HUB75_32x16MatrixPanel +#define ESP_HUB75_32x16MatrixPanel + +#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" +#include <Fonts/FreeSansBold12pt7b.h> +#include "glcdfont.c" + +struct VirtualCoords { + int16_t x; + int16_t y; +}; + +#define VP_WIDTH 32 +#define VP_HEIGHT 16 +#define DEFAULT_FONT_W 5 +#define DEFAULT_FONT_H 7 +#define PIXEL_SPACE 1 // space between chars in a string + + +/* --- PRINTF_BYTE_TO_BINARY macro's --- */ +#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c" +#define PRINTF_BYTE_TO_BINARY_INT8(i) \ + (((i) & 0x80ll) ? '1' : '0'), \ + (((i) & 0x40ll) ? '1' : '0'), \ + (((i) & 0x20ll) ? '1' : '0'), \ + (((i) & 0x10ll) ? '1' : '0'), \ + (((i) & 0x08ll) ? '1' : '0'), \ + (((i) & 0x04ll) ? '1' : '0'), \ + (((i) & 0x02ll) ? '1' : '0'), \ + (((i) & 0x01ll) ? '1' : '0') + +#define PRINTF_BINARY_PATTERN_INT16 \ + PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_PATTERN_INT8 +#define PRINTF_BYTE_TO_BINARY_INT16(i) \ + PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i) + + +/* --- end macros --- */ + + +class QuarterScanMatrixPanel : public Adafruit_GFX +{ + + public: + + MatrixPanel_I2S_DMA *display; + + QuarterScanMatrixPanel(MatrixPanel_I2S_DMA &disp) : Adafruit_GFX(64, 32) + { + this->display = &disp; + size_x = size_y = 1 ; + wrap = false; + cursor_x = cursor_y = 0; + dir = 1; + loop = true; + + } + + VirtualCoords getCoords(int16_t x, int16_t y); + int16_t getVirtualX(int16_t x) { + VirtualCoords coords = getCoords(x, 0); + return coords.x; + } + int16_t getVirtualY(int16_t y) { + VirtualCoords coords = getCoords(0,y); + return coords.y; + } +// int16_t getVirtualY(int16_t y) {return getCoords(0,y).y;} + /** extende function to draw lines/rects/... **/ + virtual uint8_t width() {return VP_WIDTH;}; + virtual uint8_t height() {return VP_HEIGHT;}; + + virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + virtual void drawHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color); + virtual void drawVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color); + virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + + virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size); + virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y); + virtual void scrollChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint16_t dir, uint16_t speed); + virtual void drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg); + virtual size_t write(unsigned char c); // write a character on current cursor postion + virtual size_t write(const char *str); // write a character array (string) on curreont cursor postion + + virtual void setTextWrap(bool w); + virtual void setCursor (int16_t x, int16_t y); + void setTextFGColor(uint16_t color) {textFGColor = color;}; + void setTextBGColor(uint16_t color) {textBGColor = color;}; + void setTextSize(uint8_t x, uint8_t y) {size_x = x; size_y = y;}; // magnification, default = 1 + + void setScrollDir(uint8_t d = 1) { dir = (d != 1) ? 0 : 1;}; // set scroll dir default = 1 + void setScroolLoop (bool b = true) { loop = b;} ; // scroll text in a loop, default true + void scrollText(const char *str, uint16_t speed, uint16_t pixels); + /**------------------------------------------**/ + + // equivalent methods of the matrix library so it can be just swapped out. + virtual void drawPixel(int16_t x, int16_t y, uint16_t color); + virtual void fillScreen(uint16_t color); // overwrite adafruit implementation + void clearScreen() { fillScreen(0); } + void drawPixelRGB565(int16_t x, int16_t y, uint16_t color); + void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b); + void drawPixelRGB24(int16_t x, int16_t y, RGB24 color); + void drawIcon (int *ico, int16_t x, int16_t y, int16_t module_cols, int16_t module_rows); + + uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { + return display->color444(r, g, b); + } + uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { + return display->color565(r, g, b); + } + uint16_t color333(uint8_t r, uint8_t g, uint8_t b) { + return display->color333(r, g, b); + } + + void flipDMABuffer() { display->flipDMABuffer(); } + void showDMABuffer() { display->showDMABuffer(); } + + void drawDisplayTest(); + + protected: + int16_t cursor_x, cursor_y; // Cursor position + uint8_t size_x, size_y; // Font size Multiplikator default = 1 => 5x7 Font (5widht,7Height) + uint16_t textFGColor, textBGColor; + bool wrap ; // < If set, 'wrap' text at right edge of display + uint8_t dir ; // used for scrolling text direction + bool loop ; // used for scrolling text in a loop + + private: + VirtualCoords coords; + +}; // end Class header + + +/*************************************************************************************** + + @brief scroll text from right to left or vice versa on current cursor position + please note, this function is not interruptable. + + @param *c pointer to \0 terminated string + @param pixels number of pixels to scroll, if 0, than scroll complete text + @param speed velocity of scrolling in ms +***************************************************************************************/ +void QuarterScanMatrixPanel::scrollText(const char *str,uint16_t speed, uint16_t pixels = 0) { + // first we put all columns of every char inside str into a big array of lines + // than we move through this arry and draw line per line and move this line + // one position to dir + const uint8_t xSize = 6; + uint16_t len = strlen(str); + uint8_t array[len * xSize]; // size of array number of chars * width of char + //uint16_t lenArray = sizeof(array)/sizeof(array[0]); + uint16_t aPtr = 0; + // + // generate array + char c = *str; + // Serial.printf("size *str (%d), size array: (%d) \n", len, lenArray); + + while (c) { + // Serial.printf("** %c ** \n", c); + // read font line per line. A line is a column inside a char + for (int8_t i = 0; i < 5; i++) { + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + array[aPtr++] = line; + // Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", i, PRINTF_BYTE_TO_BINARY_INT8(line) ); + } + str++; + c = *str; + array[aPtr++] = 0x00; // line with 0 (space between chars) + + } + array[aPtr++] = 0x00; // line with 0 (space between chars) +/* + Serial.printf("---------------------------- \n"); + for (aPtr=0; aPtr < (len*xSize); aPtr++) { + Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", aPtr, PRINTF_BYTE_TO_BINARY_INT8(array[aPtr]) ); + } +*/ + + int16_t x,y,lastX, p; + lastX = (dir) ? VP_WIDTH : 0; + x = cursor_x; + y = cursor_y; + Serial.printf("X: %d, Y: %d \n", x,y); + p=0; + pixels = (pixels) ? pixels : len * xSize; + + while (p <= pixels) { + // remove last pixel positions + fillRect(x,y,5,7,textBGColor); + // set new pixel position + x = (dir) ? lastX - p : lastX + p - pixels; + // iterator through our array + for (uint8_t i=0; i < (len*xSize); i++) { + uint8_t line = array[i]; + //Serial.printf("%d:%d : " PRINTF_BINARY_PATTERN_INT8 "\n", x, i, PRINTF_BYTE_TO_BINARY_INT8(line) ); + // read line and shift from right to left + // start with bit 0 (top of char) to 7(bottom) + for (uint8_t j=0; j < 8; j++, line>>=1) { + if (line & 1) { + // got 1, if x + i outside panel ignore pixel + if (x + i >= 0 && x + i < VP_WIDTH) { + drawPixel(x + i, y + j, textFGColor); + } + } + else { + // got 0 + if (x + i >= 0 && x + i < VP_WIDTH) { + drawPixel(x + i, y + j, textBGColor); + } + } // if + } // for j + } // for i + p++; + delay(speed); + + } // while +} + +inline size_t QuarterScanMatrixPanel::write(const char *str) { + uint8_t x, y; + x=cursor_x; + y=cursor_y; + char c = *str; + while (c) { + //Serial.printf("%c ", c); + write(c); + str++; + c = *str; + x = x + ((DEFAULT_FONT_W + PIXEL_SPACE) * size_x); + setCursor(x,y); + } + Serial.printf("\n"); + return 1; +} + +inline size_t QuarterScanMatrixPanel::write(unsigned char c) { + Serial.printf("\twrite(%d, %d, %c)\n", cursor_x, cursor_y, c); + drawChar(cursor_x, cursor_y, c, textFGColor, textBGColor, size_x, size_y); + return 1; +} + +void QuarterScanMatrixPanel::setTextWrap(bool w) {this->display->setTextWrap(w);} +void QuarterScanMatrixPanel::setCursor(int16_t x, int16_t y) { + cursor_x = x; + cursor_y = y; +} + + +/* - new for 16x32 panels - */ +inline void QuarterScanMatrixPanel::drawLine(int16_t x, int16_t y, int16_t x1, int16_t y1, uint16_t color) +{ + int16_t a,b; + for (a=x; a <= x1; a++) { + for (b=y; b <= y1; b++) { + drawPixel(a,b,color); + } + } +} + +inline void QuarterScanMatrixPanel::drawHLine(int16_t x, int16_t y, int16_t w, uint16_t color) +{ + drawLine(x,y,x+w,y, color); +} + +inline void QuarterScanMatrixPanel::drawVLine(int16_t x, int16_t y, int16_t h, uint16_t color) +{ + drawLine(x,y,x,y+h, color); +} + +inline void QuarterScanMatrixPanel::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) +{ + for (int16_t i = x; i < x + w; i++) { + drawVLine(i, y, h, color); + } +} + +void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) +{ + drawChar(x,y,c,color, bg, size, size); +} + +inline void QuarterScanMatrixPanel::scrollChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint16_t dir, uint16_t speed){ + + if ((x >= VP_WIDTH) || + (y >= VP_HEIGHT) || + ((x + 6 * size_x-1) < 0) || + ((y + 8 * size_y-1) <0)) + return; + setTextWrap(true); + // text wrap is only for the right end of the panel, to scroll soft out of the left of panel + // algorithm should wrap the character from left to right + + + // loop s = scroll-loop, scrolls char 5 pixels into dir + uint8_t lastX = x; + for (int8_t s = 0; s < 6; s++) { + // loop i : width of a character + Serial.printf("X:%d ", x); + + // clear current position + fillRect(x,y,5,7,0); + x = lastX - s; + for (int8_t i = 0; i < 5; i++) { + // first line is the firste vertical part of a character and 8bits long + // last bit is everytime 0 + // we read 5 lines with 8 bit (5x7 char + 8bit with zeros) + // Example : char A (90deg cw) + // 01111100 + // 00010010 + // 00010001 + // 00010010 + // 01111100 + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + // shift from right to left bit per bit + // loop j = height of a character + // loop through a colunm of currenc character + Serial.printf("i:%d ", i); + // ignore all pixels outside panel + if (x+i >= VP_WIDTH) continue; + + for (int8_t j=0; j < 8; j++, line >>= 1) { + if (line & 1) { + Serial.printf + (" ON %d", x+i); + // we read 1 + if (x >= 0) { + drawPixel(x+i, y+j, color); + } + else if (x+i >= 0) { + drawPixel(x+i, y+j, color); + } + } + else if (bg != color) { + // we read 0 + Serial.printf(" OFF %d", x+i); + + if (x >= 0) { + drawPixel(x+i, y+j, bg); + } + else if (x+i >= 0) { + drawPixel(x+i, y+j, bg); + } + } + } + } + Serial.printf("\n"); + delay(speed); + } +} + + +inline void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y) +{ + //Serial.printf("unmapped : drawChar(%d, %d, %c) \n",x, y, c); + + // note: remapping to 16x32 coordinats is done inside drawPixel() or fillRect + + if ((x >= VP_WIDTH) || + (y >= VP_HEIGHT) || + ((x + 6 * size_x-1) < 0) || + ((y + 8 * size_y-1) <0)) + return; + //Serial.printf("Font-Array : %d \n", sizeof(font)); + for (int8_t i = 0; i < 5; i++) { + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + //Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", i, PRINTF_BYTE_TO_BINARY_INT8(line) ); + for (int8_t j = 0; j < 8; j++, line >>= 1) { + if (line & 1) { + if (size_x == 1 && size_y == 1) + //Serial.printf(""); + drawPixel(x + i, y + j, color); + else + // remark: it's important to call function with orgininal coordinates for x/y + fillRect(x + i * size_x, y + j * size_y, size_x, size_y, + color); + } else if (bg != color) { + if (size_x == 1 && size_y == 1) + drawPixel(x + i, y + j, bg); + else + // remark: it's important to call function with orgininal coordinates for x/y + fillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg); + } + } + } + +} + +inline void QuarterScanMatrixPanel::drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg) { + +} + +inline VirtualCoords QuarterScanMatrixPanel::getCoords(int16_t x, int16_t y) +{ + const int y_remap[] = { 0,1,8,9,4,5,12,13,16,17,24,25,22,23,30,31 }; + if (y > VP_HEIGHT) + y = VP_HEIGHT; + if (x > VP_WIDTH) + x = VP_WIDTH; + coords.x = x + VP_WIDTH; + coords.y = y_remap[y]; + return coords; +} + + +/* -------------------------*/ + +inline void QuarterScanMatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t color) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixel(coords.x, coords.y, color); +} + +inline void QuarterScanMatrixPanel::fillScreen(uint16_t color) // adafruit virtual void override +{ + // No need to map this. + this->display->fillScreen(color); +} + +inline void QuarterScanMatrixPanel::drawPixelRGB565(int16_t x, int16_t y, uint16_t color) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixelRGB565( coords.x, coords.y, color); +} + + +inline void QuarterScanMatrixPanel::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixelRGB888( coords.x, coords.y, r, g, b); +} + +inline void QuarterScanMatrixPanel::drawPixelRGB24(int16_t x, int16_t y, RGB24 color) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixelRGB24(coords.x, coords.y, color); +} + + +// need to recreate this one, as it wouldnt work to just map where it starts. +inline void QuarterScanMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t module_cols, int16_t module_rows) { } + +#endif
\ No newline at end of file diff --git a/examples/P6_32x16_1_4_ScanPanel/README.md b/examples/P6_32x16_1_4_ScanPanel/README.md new file mode 100644 index 0000000..6af1fa6 --- /dev/null +++ b/examples/P6_32x16_1_4_ScanPanel/README.md @@ -0,0 +1,78 @@ +# Using this library with 32x16 1/4 Scan Panels + +## Problem +ESP32-HUB75-MatrixPanel-I2S-DMA library will not display output correctly with 1/4 scan panels such [as this](https://de.aliexpress.com/item/33017477904.html?spm=a2g0o.detail.1000023.16.1fedd556Yw52Zi&algo_pvid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40&algo_expid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40-52&btsid=9a8bf2b5-334b-45ea-a849-063d7461362e&ws_ab_test=searchweb0_0,searchweb201602_10,searchweb201603_60%5BAliExpress%2016x32%5D). + +## Solution +It is possible to connect 1/4 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 ESP32-HUB75-MatrixPanel-I2S-DMA library (in this example, it is the 'dmaOutput' class). + +Creation of a 'QuarterScanMatrixPanel.h' class which sends an adjusted x,y co-ordinates to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA library's drawPixel routine, to trick the output to look pixel perfect. Refer to the 'getCoords' function within 'QuarterScanMatrixPanel.h' + +## Limitations + +* Only one font (glcd - standard font) is implemented. This font can't be resized. + +## New functions (and adapted function) in this QuarterScanMatrixPanel class +### drawLine +`void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)` + +Parameters should be self explained. x0/y0 upper left corner, x1/y1 lower right corner + +### drawHLine +`void drawHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color)` + +Draw a fast horizontal line with length `w`. Starting at `x0/y0` + +### drawVLine +`void drawVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color)` + +Draw a fast vertical line with length `h` Starting at `x0/y0` + +### fillRect +`void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)` + +Draw a rectangle starting at `x/y` with width `w` and height `h`in `color` + +### drawChar (5x7) Standard font +`drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)` + +Draw a char at position x/y in `color` with a background color `bg` +`size` is ignored. + +### writeChar (5x7) +`size_t write(unsigned char c)` + +Write a char at current cursor position with current foreground and background color. + +### writeString (5x7) +`size_t write(const char *c)` + +Write a string at current cursor position with current foreground and background color. +You have to use `setCursor(x,y)` and `setTextFGColor() / setTextBGColor()` + +### drawString (5x7) +`void drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg)` + +Draw String at postion x/y wit foreground `color` and background `bg` +Example: `display.drawString(0,5,"**Welcome**",display.color565(0,60,255));` + +### void setScrollDir(uint8_t d = 1) +Set scrolling direction 0=left to right, 1= right to left (default) + +### scrollText +`void scrollText(const char *str, uint16_t speed, uint16_t pixels)` + +Scroll text `str` into `setScrollDir`. Speed indicates how fast in ms per pixel, pixels are the number pixes which should be scrolled, if not set or 0, than pixels is calculates by size of `*str` + +### drawPixel(int16_t x, int16_t y, uint16_t color) +Draw a pixel at x/y in `color`. This function is the atomic function for all above drawing functions + +### clearScreen() (all pixels off (black)) +Same as `fillScreen(0)` + + +## Example videos: +https://user-images.githubusercontent.com/949032/104838449-4aae5600-58bb-11eb-802f-a358b49a9315.mp4 + +https://user-images.githubusercontent.com/949032/104366906-5647f880-551a-11eb-9792-a6f8276629e6.mp4 + diff --git a/examples/PIO_TestPatterns/README.md b/examples/PIO_TestPatterns/README.md new file mode 100644 index 0000000..291bee2 --- /dev/null +++ b/examples/PIO_TestPatterns/README.md @@ -0,0 +1,16 @@ +# Test Patterns + +Simple solid colors, gradients and test line patterns, could be used to test matrixes for proper operation, flickering and estimate fillrate timings. + +Should be build and uploaded as a [platformio](https://platformio.org/) project + + +To build with Arduino's framework use +``` +pio run -t upload +``` + +To build using ESP32 IDF with arduino's component use +``` +pio run -t upload -e idfarduino +``` diff --git a/examples/PIO_TestPatterns/platformio.ini b/examples/PIO_TestPatterns/platformio.ini new file mode 100644 index 0000000..0edd28a --- /dev/null +++ b/examples/PIO_TestPatterns/platformio.ini @@ -0,0 +1,42 @@ +[platformio] +default_envs = esp32 + +[env] +framework = arduino +platform = espressif32 +board_build.filesystem = littlefs +board = wemos_d1_mini32 +lib_deps = + FastLED +build_flags = +; -DSERIAL_DEBUG=1 +upload_speed = 921600 +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder + +[env:esp32] +build_flags = + ${env.build_flags} + -DUSE_FASTLINES + -DNO_GFX +lib_deps = + ${env.lib_deps} +; use dev version of the lib + https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA.git#dev + + +[env:idfarduino] +platform = espressif32 +platform_packages = + ; use a special branch + framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0 +framework = arduino, espidf +build_flags = + ${env.build_flags} + -DARDUINO=200 + -DESP32 + -DUSE_FASTLINES + -DNO_GFX +lib_deps = + ${env.lib_deps} + https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA.git#dev diff --git a/examples/PIO_TestPatterns/src/CMakeLists.txt b/examples/PIO_TestPatterns/src/CMakeLists.txt new file mode 100644 index 0000000..483bc0c --- /dev/null +++ b/examples/PIO_TestPatterns/src/CMakeLists.txt @@ -0,0 +1,6 @@ +# This file was automatically generated for projects +# without default 'CMakeLists.txt' file. + +FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*) + +idf_component_register(SRCS ${app_sources}) diff --git a/examples/PIO_TestPatterns/src/main.cpp b/examples/PIO_TestPatterns/src/main.cpp new file mode 100644 index 0000000..7ba159c --- /dev/null +++ b/examples/PIO_TestPatterns/src/main.cpp @@ -0,0 +1,382 @@ +// How to use this library with a FM6126 panel, thanks goes to: +// https://github.com/hzeller/rpi-rgb-led-matrix/issues/746 + +// IDF +#if defined(IDF_VER) + #include <stdio.h> + #include <freertos/FreeRTOS.h> + #include <freertos/task.h> + #include <driver/gpio.h> + #include "sdkconfig.h" +#endif + +#include <Arduino.h> +#include "xtensa/core-macros.h" +#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> + +#include "main.h" + +// HUB75E pinout +// R1 | G1 +// B1 | GND +// R2 | G2 +// B2 | E +// A | B +// C | D +// CLK| LAT +// OE | GND + +#define R1 25 +#define G1 26 +#define BL1 27 +#define R2 14 // 21 SDA +#define G2 12 // 22 SDL +#define BL2 13 +#define CH_A 23 +#define CH_B 19 +#define CH_C 5 +#define CH_D 17 +#define CH_E 32 // assign to any available pin if using two panels or 64x64 panels with 1/32 scan +#define CLK 16 +#define LAT 4 +#define OE 15 + + +#define M_WIDTH 256 +#define M_HEIGHT 64 +#define PATTERN_DELAY 2000 + +#define NUM_LEDS M_WIDTH*M_HEIGHT + +//#define USE_FASTLINES + +MatrixPanel_I2S_DMA *matrix = nullptr; + +uint16_t time_counter = 0, cycles = 0, fps = 0; +unsigned long fps_timer; + +// +CRGB *ledbuff; +// + +unsigned long t1, t2, s1=0, s2=0, s3=0; +uint32_t ccount1, ccount2; + +uint8_t color1 = 0, color2 = 0, color3 = 0; +uint16_t x,y; + +void setup(){ + + Serial.begin(BAUD_RATE); + Serial.println("Starting pattern test..."); + + HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK}; + HUB75_I2S_CFG mxconfig(64, 64, 4, _pins, HUB75_I2S_CFG::FM6126A); + mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_20M; + + matrix = new MatrixPanel_I2S_DMA(mxconfig); + + matrix->begin(); + matrix->setBrightness8(255); + //matrix->setLatBlanking(2); + + ledbuff = (CRGB *)malloc(NUM_LEDS * sizeof(CRGB)); // allocate buffer for some tests + buffclear(ledbuff); + +} + + +void loop(){ + + Serial.printf("Cycle: %d\n", ++cycles); + + Serial.print("Estimating clearScreen() - "); + ccount1 = XTHAL_GET_CCOUNT(); + matrix->clearScreen(); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + Serial.printf("%d ticks\n", ccount1); + delay(PATTERN_DELAY); + +/* +// Power supply tester +// slowly fills matrix with white, stressing PSU + for (int y=0; y!=M_HEIGHT; ++y){ + for (int x=0; x!=M_WIDTH; ++x){ + matrix->drawPixelRGB888(x, y, 255,255,255); + //matrix->drawPixelRGB888(x, y-1, 255,0,0); // pls, be gentle :) + delay(10); + } + } + delay(5000); +*/ + + + // simple solid colors + Serial.println("Fill screen: RED"); + matrix->fillScreenRGB888(255, 0, 0); + delay(PATTERN_DELAY); + Serial.println("Fill screen: GREEN"); + matrix->fillScreenRGB888(0, 255, 0); + delay(PATTERN_DELAY); + Serial.println("Fill screen: BLUE"); + matrix->fillScreenRGB888(0, 0, 255); + delay(PATTERN_DELAY); + + + for (uint8_t i=5; i; --i){ + Serial.print("Estimating single drawPixelRGB888(r, g, b) ticks: "); + color1 = random8(); + ccount1 = XTHAL_GET_CCOUNT(); + matrix->drawPixelRGB888(i,i, color1, color1, color1); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + Serial.printf("%d ticks\n", ccount1); + } + +// Clearing CRGB ledbuff + Serial.print("Estimating ledbuff clear time: "); + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + buffclear(ledbuff); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n\n", t2, ccount1); + + // Bare fillscreen(r, g, b) + Serial.print("Estimating fillscreenRGB888(r, g, b) time: "); + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + matrix->fillScreenRGB888(64, 64, 64); // white + ccount2 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + s1+=t2; + Serial.printf("%lu us, avg: %lu, ccnt: %d\n", t2, s1/cycles, ccount2); + delay(PATTERN_DELAY); + + + Serial.print("Estimating full-screen fillrate with looped drawPixelRGB888(): "); + y = M_HEIGHT; + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + do { + --y; + uint16_t x = M_WIDTH; + do { + --x; + matrix->drawPixelRGB888( x, y, 0, 0, 0); + } while(x); + } while(y); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n", t2, ccount1); + + + +// created random color gradient in ledbuff + uint8_t color1 = 0; + uint8_t color2 = random8(); + uint8_t color3 = 0; + + for (uint16_t i = 0; i<NUM_LEDS; ++i){ + ledbuff[i].r=color1++; + ledbuff[i].g=color2; + if (i%M_WIDTH==0) + color3+=255/M_HEIGHT; + + ledbuff[i].b=color3; + } +// + +// + Serial.print("Estimating ledbuff-to-matrix fillrate with drawPixelRGB888(), time: "); + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + mxfill(ledbuff); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + s2+=t2; + Serial.printf("%lu us, avg: %lu, %d ticks:\n", t2, s2/cycles, ccount1); + delay(PATTERN_DELAY); +// + +#ifdef USE_FASTLINES + // Fillrate for fillRect() function + Serial.print("Estimating fullscreen fillrate with fillRect() time: "); + t1 = micros(); + matrix->fillRect(0, 0, M_WIDTH, M_HEIGHT, 0, 224, 0); + t2 = micros()-t1; + Serial.printf("%lu us\n", t2); + delay(PATTERN_DELAY); + + + Serial.print("Chessboard with fillRect(): "); // шахматка + matrix->fillScreen(0); + x =0, y = 0; + color1 = random8(); + color2 = random8(); + color3 = random8(); + bool toggle=0; + t1 = micros(); + do { + do{ + matrix->fillRect(x, y, 8, 8, color1, color2, color3); + x+=16; + }while(x < M_WIDTH); + y+=8; + toggle = !toggle; + x = toggle ? 8 : 0; + }while(y < M_HEIGHT); + t2 = micros()-t1; + Serial.printf("%lu us\n", t2); + delay(PATTERN_DELAY); +#endif + +// ======== V-Lines ========== + Serial.println("Estimating V-lines with drawPixelRGB888(): "); // + matrix->fillScreen(0); + color1 = random8(); + color2 = random8(); + x = y = 0; + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + do { + y=0; + do{ + matrix->drawPixelRGB888(x, y, color1, color2, color3); + } while(++y != M_HEIGHT); + x+=2; + } while(x != M_WIDTH); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n", t2, ccount1); + delay(PATTERN_DELAY); + +#ifdef USE_FASTLINES + Serial.println("Estimating V-lines with vlineDMA(): "); // + matrix->fillScreen(0); + color2 = random8(); + x = y = 0; + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + do { + matrix->drawFastVLine(x, y, M_HEIGHT, color1, color2, color3); + x+=2; + } while(x != M_WIDTH); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n", t2, ccount1); + delay(PATTERN_DELAY); + + Serial.println("Estimating V-lines with fillRect(): "); // + matrix->fillScreen(0); + color1 = random8(); + color2 = random8(); + x = y = 0; + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + do { + matrix->fillRect(x, y, 1, M_HEIGHT, color1, color2, color3); + x+=2; + } while(x != M_WIDTH); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n", t2, ccount1); + delay(PATTERN_DELAY); +#endif + + + +// ======== H-Lines ========== + Serial.println("Estimating H-lines with drawPixelRGB888(): "); // + matrix->fillScreen(0); + color2 = random8(); + x = y = 0; + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + do { + x=0; + do{ + matrix->drawPixelRGB888(x, y, color1, color2, color3); + } while(++x != M_WIDTH); + y+=2; + } while(y != M_HEIGHT); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n", t2, ccount1); + delay(PATTERN_DELAY); + +#ifdef USE_FASTLINES + Serial.println("Estimating H-lines with hlineDMA(): "); + matrix->fillScreen(0); + color2 = random8(); + color3 = random8(); + x = y = 0; + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + do { + matrix->drawFastHLine(x, y, M_WIDTH, color1, color2, color3); + y+=2; + } while(y != M_HEIGHT); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n", t2, ccount1); + delay(PATTERN_DELAY); + + Serial.println("Estimating H-lines with fillRect(): "); // + matrix->fillScreen(0); + color2 = random8(); + color3 = random8(); + x = y = 0; + t1 = micros(); + ccount1 = XTHAL_GET_CCOUNT(); + do { + matrix->fillRect(x, y, M_WIDTH, 1, color1, color2, color3); + y+=2; + } while(y != M_HEIGHT); + ccount1 = XTHAL_GET_CCOUNT() - ccount1; + t2 = micros()-t1; + Serial.printf("%lu us, %u ticks\n", t2, ccount1); + delay(PATTERN_DELAY); +#endif + + + + + Serial.println("\n====\n"); + + // take a rest for a while + delay(10000); +} + + +void buffclear(CRGB *buf){ + memset(buf, 0x00, NUM_LEDS * sizeof(CRGB)); // flush buffer to black +} + +void IRAM_ATTR mxfill(CRGB *leds){ + uint16_t y = M_HEIGHT; + do { + --y; + uint16_t x = M_WIDTH; + do { + --x; + uint16_t _pixel = y * M_WIDTH + x; + matrix->drawPixelRGB888( x, y, leds[_pixel].r, leds[_pixel].g, leds[_pixel].b); + } while(x); + } while(y); +} +// + +/** + * The one for 256+ matrixes + * otherwise this: + * for (uint8_t i = 0; i < MATRIX_WIDTH; i++) {} + * turns into an infinite loop + */ +uint16_t XY16( uint16_t x, uint16_t y) +{ + if (x<M_WIDTH && y < M_HEIGHT){ + return (y * M_WIDTH) + x; // everything offset by one to capute out of bounds stuff - never displayed by ShowFrame() + } else { + return 0; + } +} diff --git a/examples/PIO_TestPatterns/src/main.h b/examples/PIO_TestPatterns/src/main.h new file mode 100644 index 0000000..d947d8e --- /dev/null +++ b/examples/PIO_TestPatterns/src/main.h @@ -0,0 +1,8 @@ + +#include <FastLED.h> + +#define BAUD_RATE 115200 // serial debug port baud rate + +void buffclear(CRGB *buf); +uint16_t XY16( uint16_t x, uint16_t y); +void mxfill(CRGB *leds);
\ No newline at end of file diff --git a/examples/PatternPlasma/PatternPlasma.ino b/examples/PatternPlasma/PatternPlasma.ino deleted file mode 100644 index e8a16d9..0000000 --- a/examples/PatternPlasma/PatternPlasma.ino +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Portions of this code are adapted from Aurora: https://github.com/pixelmatix/aurora - * Copyright (c) 2014 Jason Coon - * - * Portions of this code are adapted from LedEffects Plasma by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Plasma.cpp?at=default - * Copyright (c) 2013 Robert Atkins - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -//#define USE_CUSTOM_PINS // uncomment to use custom pins, then provide below - -#define A_PIN 26 -#define B_PIN 4 -#define C_PIN 27 -#define D_PIN 2 -#define E_PIN 21 - -#define R1_PIN 5 -#define R2_PIN 19 -#define G1_PIN 17 -#define G2_PIN 16 -#define B1_PIN 18 -#define B2_PIN 25 - -#define CLK_PIN 14 -#define LAT_PIN 15 -#define OE_PIN 13 - - -#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h> -MatrixPanel_I2S_DMA dma_display; - -#include <FastLED.h> - -int time_counter = 0; -int cycles = 0; - - -CRGBPalette16 currentPalette; -CRGB currentColor; - - -CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { - return ColorFromPalette(currentPalette, index, brightness, blendType); -} - -void setup() { - - Serial.begin(115200); - - Serial.println("*****************************************************"); - Serial.println(" HELLO !"); - Serial.println("*****************************************************"); - -#ifdef USE_CUSTOM_PINS - dma_display.begin(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 ); // setup the LED matrix -#else - dma_display.begin(); -#endif - - // fill the screen with 'black' - dma_display.fillScreen(dma_display.color444(0, 0, 0)); - - // Set current FastLED palette - currentPalette = RainbowColors_p; - -} - -void loop() { - - for (int x = 0; x < dma_display.width(); x++) { - for (int y = 0; y < dma_display.height(); y++) { - int16_t v = 0; - uint8_t wibble = sin8(time_counter); - v += sin16(x * wibble * 3 + time_counter); - v += cos16(y * (128 - wibble) + time_counter); - v += sin16(y * x * cos8(-time_counter) / 8); - - currentColor = ColorFromPalette(currentPalette, (v >> 8) + 127); //, brightness, currentBlendType); - dma_display.drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); - - } - } - - time_counter += 1; - cycles++; - - if (cycles >= 2048) { - time_counter = 0; - cycles = 0; - } - -} // end loop
\ No newline at end of file diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..6b55f37 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,14 @@ +| Example Name |Description | +|--|--| +|1_SimpleTestShapes |Example for new starters - how to display basic shapes. | +|2_PatternPlasma |Example for new starters - how to display a cool plasma pattern. | +|3_FM6126Panel |Example for new starters - how to initialise FM6126/FM6126A panels with this library. +|AnimatedGIFPanel |Using Larry Bank's GIF Decoder to display animated GIFs. | +|AuroraDemo |Simple example demonstrating various animated effects. | +|BitmapIcons |Simple example of how to display a bitmap image to the display. | +|ChainedPanels |Popular example on how to use the 'VirtualDisplay' class to chain multiple LED Matrix Panels to form a much bigger display! Refer to the README within this example's folder! | +|ChainedPanelsAuroraDemo |As above, but showing a large trippy plasma animation. | +|DoubleBufferSwap |Advanced example of using a back-buffer (double buffering). Not useful for 99% of use cases. | +|GraphicsLayer |Advanced example of using an off-screen 'layer' library before writing to the LED Matrix Panels. | +|P6_32x16_1_4_ScanPanel |An advanced example ('hack') on how to use this library on 32w x 16h 1/4 Scan LED Matrix Panel. | +|PIO_TestPatterns |Non-Arduino example of how to display basic shapes. | |
