commit
76a585e1f8
11 changed files with 185 additions and 115 deletions
|
@ -478,10 +478,11 @@ void IRAM_ATTR MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16
|
||||||
* i.e. It's almost impossible for color_depth_idx of 0 to be sent out to the MATRIX unless the 'value' of a color is exactly '1'
|
* i.e. It's almost impossible for color_depth_idx of 0 to be sent out to the MATRIX unless the 'value' of a color is exactly '1'
|
||||||
* https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
|
* https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
|
||||||
*/
|
*/
|
||||||
|
#ifndef NO_CIE1931
|
||||||
red = lumConvTab[red];
|
red = lumConvTab[red];
|
||||||
green = lumConvTab[green];
|
green = lumConvTab[green];
|
||||||
blue = lumConvTab[blue];
|
blue = lumConvTab[blue];
|
||||||
|
#endif
|
||||||
|
|
||||||
/* When using the drawPixel, we are obviously only changing the value of one x,y position,
|
/* When using the drawPixel, we are obviously only changing the value of one x,y position,
|
||||||
* however, the two-scan panels paint TWO lines at the same time
|
* however, the two-scan panels paint TWO lines at the same time
|
||||||
|
@ -543,9 +544,11 @@ void MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint
|
||||||
if ( !initialized ) return;
|
if ( !initialized ) return;
|
||||||
|
|
||||||
/* https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/ */
|
/* https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/ */
|
||||||
|
#ifndef NO_CIE1931
|
||||||
red = lumConvTab[red];
|
red = lumConvTab[red];
|
||||||
green = lumConvTab[green];
|
green = lumConvTab[green];
|
||||||
blue = lumConvTab[blue];
|
blue = lumConvTab[blue];
|
||||||
|
#endif
|
||||||
|
|
||||||
for(uint8_t color_depth_idx=0; color_depth_idx<PIXEL_COLOR_DEPTH_BITS; color_depth_idx++) // color depth - 8 iterations
|
for(uint8_t color_depth_idx=0; color_depth_idx<PIXEL_COLOR_DEPTH_BITS; color_depth_idx++) // color depth - 8 iterations
|
||||||
{
|
{
|
||||||
|
@ -862,9 +865,11 @@ void MatrixPanel_I2S_DMA::hlineDMA(int16_t x_coord, int16_t y_coord, int16_t l,
|
||||||
l = PIXELS_PER_ROW - x_coord + 1; // reset width to end of row
|
l = PIXELS_PER_ROW - x_coord + 1; // reset width to end of row
|
||||||
|
|
||||||
/* LED Brightness Compensation */
|
/* LED Brightness Compensation */
|
||||||
|
#ifndef NO_CIE1931
|
||||||
red = lumConvTab[red];
|
red = lumConvTab[red];
|
||||||
green = lumConvTab[green];
|
green = lumConvTab[green];
|
||||||
blue = lumConvTab[blue];
|
blue = lumConvTab[blue];
|
||||||
|
#endif
|
||||||
|
|
||||||
uint16_t _colorbitclear = BITMASK_RGB1_CLEAR, _colorbitoffset = 0;
|
uint16_t _colorbitclear = BITMASK_RGB1_CLEAR, _colorbitoffset = 0;
|
||||||
|
|
||||||
|
@ -929,9 +934,11 @@ void MatrixPanel_I2S_DMA::vlineDMA(int16_t x_coord, int16_t y_coord, int16_t l,
|
||||||
l = m_cfg.mx_height - y_coord + 1; // reset width to end of col
|
l = m_cfg.mx_height - y_coord + 1; // reset width to end of col
|
||||||
|
|
||||||
/* LED Brightness Compensation */
|
/* LED Brightness Compensation */
|
||||||
|
#ifndef NO_CIE1931
|
||||||
red = lumConvTab[red];
|
red = lumConvTab[red];
|
||||||
green = lumConvTab[green];
|
green = lumConvTab[green];
|
||||||
blue = lumConvTab[blue];
|
blue = lumConvTab[blue];
|
||||||
|
#endif
|
||||||
|
|
||||||
// Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
|
// Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
|
||||||
x_coord & 1U ? --x_coord : ++x_coord;
|
x_coord & 1U ? --x_coord : ++x_coord;
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 8bit per RGB color = 24 bit/per pixel,
|
// 8bit per RGB color = 24 bit/per pixel,
|
||||||
// might be reduced to save RAM but it corrupts colours badly (currently broken)
|
// might be reduced to save DMA RAM
|
||||||
#ifndef PIXEL_COLOR_DEPTH_BITS
|
#ifndef PIXEL_COLOR_DEPTH_BITS
|
||||||
#define PIXEL_COLOR_DEPTH_BITS 8
|
#define PIXEL_COLOR_DEPTH_BITS 8
|
||||||
#endif
|
#endif
|
||||||
|
@ -208,13 +208,13 @@ typedef struct RGB24 {
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************/
|
/***************************************************************************************/
|
||||||
// Used by val2PWM
|
|
||||||
//C/p'ed from https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
|
//C/p'ed from https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
|
||||||
// Example calculator: https://gist.github.com/mathiasvr/19ce1d7b6caeab230934080ae1f1380e
|
// Example calculator: https://gist.github.com/mathiasvr/19ce1d7b6caeab230934080ae1f1380e
|
||||||
// need to make sure this would end up in RAM for fastest access
|
// need to make sure this would end up in RAM for fastest access
|
||||||
|
#ifndef NO_CIE1931
|
||||||
static const uint8_t DRAM_ATTR lumConvTab[]={
|
static const uint8_t DRAM_ATTR lumConvTab[]={
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 30, 30, 31, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 38, 39, 40, 41, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 95, 96, 98, 99, 100, 102, 103, 105, 106, 107, 109, 110, 112, 113, 115, 116, 118, 120, 121, 123, 124, 126, 128, 129, 131, 133, 134, 136, 138, 139, 141, 143, 145, 146, 148, 150, 152, 154, 156, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 192, 194, 196, 198, 200, 203, 205, 207, 209, 212, 214, 216, 218, 221, 223, 226, 228, 230, 233, 235, 238, 240, 243, 245, 248, 250, 253, 255, 255};
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 30, 30, 31, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 38, 39, 40, 41, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 95, 96, 98, 99, 100, 102, 103, 105, 106, 107, 109, 110, 112, 113, 115, 116, 118, 120, 121, 123, 124, 126, 128, 129, 131, 133, 134, 136, 138, 139, 141, 143, 145, 146, 148, 150, 152, 154, 156, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 192, 194, 196, 198, 200, 203, 205, 207, 209, 212, 214, 216, 218, 221, 223, 226, 228, 230, 233, 235, 238, 240, 243, 245, 248, 250, 253, 255, 255};
|
||||||
|
#endif
|
||||||
|
|
||||||
/** @brief - configuration values for HUB75_I2S driver
|
/** @brief - configuration values for HUB75_I2S driver
|
||||||
* This structure holds configuration vars that are used as
|
* This structure holds configuration vars that are used as
|
||||||
|
|
126
README.md
126
README.md
|
@ -1,25 +1,55 @@
|
||||||
# HUB75 LED matrix library for the ESP32, utilising DMA
|
# HUB75 RGB LED matrix library utilizing ESP32 DMA Engine
|
||||||
|
|
||||||
## First time user? Please take the time to read the below
|
**Table of Content**
|
||||||
|
|
||||||
This ESP32 Arduino library for HUB75 / HUB75E connector type 64x32 RGB LED 1/16 Scan OR 64x64 RGB LED 1/32 Scan LED Matrix Panel, utilises the DMA functionality provided by the ESP32's I2S 'LCD Mode' which basically means that pixel data is sent straight from memory, via the DMA controller, to the relevant LED Matrix GPIO pins with little CPU overhead.
|
- [Introduction](#introduction)
|
||||||
|
* [Features](#features)
|
||||||
|
* [Panels Supported](#panels-supported)
|
||||||
|
* [Panel driver chips known to be working well](#panel-driver-chips-known-to-be-working-well)
|
||||||
|
* [Panels Not Supported](#panels-not-supported)
|
||||||
|
* [Update for 16x32 Panels](#update-for-16x32-panels)
|
||||||
|
- [Getting Started](#getting-started)
|
||||||
|
* [1. Library Installation](#1-library-installation)
|
||||||
|
* [2. Wiring ESP32 with the LED Matrix Panel](#2-wiring-esp32-with-the-led-matrix-panel)
|
||||||
|
* [3. Run a Test Sketch](#3-run-a-test-sketch)
|
||||||
|
- [More Information](#more-information)
|
||||||
|
* [Build-time options](#build-time-options)
|
||||||
|
* [Memory constraints](#memory-constraints)
|
||||||
|
* [Can I use with a larger panel (i.e. 64x64px square panel)?](#can-i-use-with-a-larger-panel--ie-64x64px-square-panel--)
|
||||||
|
* [Can I chain panels?](#can-i-chain-panels-)
|
||||||
|
* [Panel Brightness](#panel-brightness)
|
||||||
|
* [Latch blanking](#latch-blanking)
|
||||||
|
* [Power, Power and Power!](#power--power-and-power-)
|
||||||
|
* [Inspiration](#inspiration)
|
||||||
|
|
||||||
As a result, this library can theoretically provide ~16-24 bit colour, at various brightness levels without noticeable flicker.
|
## Introduction
|
||||||
|
This ESP32 Arduino/IDF library for HUB75 / HUB75E connector type 64x32 RGB LED 1/16 Scan OR 64x64 RGB LED 1/32 Scan LED Matrix Panel, utilities the DMA functionality provided by the ESP32's I2S 'LCD Mode'.
|
||||||
|
|
||||||
Ones interested in internals of such matrixes could find [this article](https://www.sparkfun.com/news/2650) useful.
|
### Features
|
||||||
|
- **Low CPU overhead** - once initialized pixel data is pumped to the matrix inputs via DMA engine directly from memory
|
||||||
|
- **Fast** - updating pixel data involves only bit-wise logic over DMA buffer memory, no pins manipulation or blocking IO
|
||||||
|
- **Full screen BCM** - library utilizes [binary-code modulation](http://www.batsocks.co.uk/readme/art_bcm_5.htm) to render pixel color depth / brightness over the entire matrix
|
||||||
|
- **Variable color depth** - up to TrueColor 24 bits output is possible depending on matrix size/refresh rate required
|
||||||
|
- **CIE 1931** luminance [correction](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) (aka natural LED dimming)
|
||||||
|
- **Adafruit GFX API** - library could be build with AdafruitGFX, simplified GFX or without GFX API at all
|
||||||
|
|
||||||
Due to the high-speed optimised nature of this library, only specific panels are supported. Please do not raised issues with respect to panels not supported on the list below.
|
If you wanna ask "*...OK, OK, than whats the price for those features?*" I'll tell you - "[memory](/doc/i2s_memcalc.md), you pay it all by precious MCU's memory for DMA buffer".
|
||||||
|
|
||||||
## Panels Supported
|
## Panels Supported
|
||||||
* 64x32 (width x height) pixel 1/16 Scan LED Matrix 'Indoor' Panel, such as this [typical RGB panel available for purchase](https://www.aliexpress.com/item/256-128mm-64-32-pixels-1-16-Scan-Indoor-3in1-SMD2121-RGB-full-color-P4-led/32810362851.html).
|
* 64x32 (width x height) pixel 1/16 Scan LED Matrix 'Indoor' Panel, such as this [typical RGB panel available for purchase](https://www.aliexpress.com/item/256-128mm-64-32-pixels-1-16-Scan-Indoor-3in1-SMD2121-RGB-full-color-P4-led/32810362851.html).
|
||||||
* 64x64 pixel 1/32 Scan LED Matrix 'Indoor' Panel.
|
* 64x64 pixel 1/32 Scan LED Matrix 'Indoor' Panel.
|
||||||
* 32x16 pixel 1/4 Scan LED Matrix 'Indoor' Panel using an ingenious workaround as demonstrated in the 32x16_1_4_ScanPanel example.
|
* 32x16 pixel 1/4 Scan LED Matrix 'Indoor' Panel using an ingenious workaround as demonstrated in the 32x16_1_4_ScanPanel example.
|
||||||
* Any of the above panel resolution / scan rates based on [FM6126](FM6126A.md) / ICN2038S chips. Refer to PatternPlasma example on how to use.
|
|
||||||
|
Ones interested in internals of such matrixes could find [this article](https://www.sparkfun.com/news/2650) useful.
|
||||||
|
|
||||||
|
Due to the high-speed optimized nature of this library, only specific panels are supported. Please do not raise issues with respect to panels not supported on the list below.
|
||||||
|
|
||||||
## Panel driver chips known to be working well
|
## Panel driver chips known to be working well
|
||||||
|
|
||||||
* ICND2012
|
* ICND2012
|
||||||
* RUC7258
|
* [RUC7258](http://www.ruichips.com/en/products.html?cateid=17496)
|
||||||
* FM6126A AKA ICN2038S, FM6124 (if specified properly)
|
* FM6126A AKA ICN2038S, [FM6124](https://datasheet4u.com/datasheet-pdf/FINEMADELECTRONICS/FM6124/pdf.php?id=1309677) (Refer to [PatternPlasma](/examples/2_PatternPlasma) example on how to use.)
|
||||||
|
|
||||||
## Panels Not Supported
|
## Panels Not Supported
|
||||||
* 1/8 Scan LED Matrix Panels are not supported.
|
* 1/8 Scan LED Matrix Panels are not supported.
|
||||||
* RUL5358 / SHIFTREG_ABC_BIN_DE based panels are not supported.
|
* RUL5358 / SHIFTREG_ABC_BIN_DE based panels are not supported.
|
||||||
|
@ -35,24 +65,23 @@ Please use an [alternative library](https://github.com/2dom/PxMatrix) if you bou
|
||||||
|
|
||||||
* Dependency: You will need to install Adafruit_GFX from the "Library > Manage Libraries" menu.
|
* Dependency: You will need to install Adafruit_GFX from the "Library > Manage Libraries" menu.
|
||||||
* Download and unzip this repository into your Arduino/libraries folder (or better still, use the Arduino 'add library from .zip' option.
|
* Download and unzip this repository into your Arduino/libraries folder (or better still, use the Arduino 'add library from .zip' option.
|
||||||
* Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate.
|
* Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate. Or just add it into [platformio.ini](/doc/BuildOptions.md) [lib_depth](https://docs.platformio.org/en/latest/projectconf/section_env_library.html#lib-deps) section.
|
||||||
|
|
||||||
## 2. Wiring ESP32 with the LED Matrix Panel
|
## 2. Wiring ESP32 with the LED Matrix Panel
|
||||||
|
|
||||||
By default the pin mapping is as follows (defaults defined in ESP32-HUB75-MatrixPanel-I2S-DMA.h).
|
By default the pin mapping is as follows (defaults defined in ESP32-HUB75-MatrixPanel-I2S-DMA.h).
|
||||||
|
|
||||||
```
|
```
|
||||||
HUB 75 PANEL ESP 32 PIN
|
HUB 75 PANEL ESP 32 PIN
|
||||||
+-----------+
|
+----------+
|
||||||
| R1 G1 | R1 -> IO25 G1 -> IO26
|
| R1 G1 | R1 -> IO25 G1 -> IO26
|
||||||
| B1 GND | B1 -> IO27
|
| B1 GND | B1 -> IO27
|
||||||
| R2 G2 | R2 -> IO14 G2 -> IO12
|
| R2 G2 | R2 -> IO14 G2 -> IO12
|
||||||
| B2 E | B2 -> IO13 E -> N/A (required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32 )
|
| B2 E | B2 -> IO13 E -> N/A (required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32 )
|
||||||
| A B | A -> IO23 B -> IO19
|
| A B | A -> IO23 B -> IO19
|
||||||
| C D | C -> IO 5 D -> IO17
|
| C D | C -> IO05 D -> IO17
|
||||||
| CLK LAT | CLK -> IO16 LAT -> IO 4
|
| CLK LAT | CLK -> IO16 LAT -> IO 4
|
||||||
| OE GND | OE -> IO15 GND -> ESP32 GND
|
| OE GND | OE -> IO15 GND -> ESP32 GND
|
||||||
+-----------+
|
+----------+
|
||||||
```
|
```
|
||||||
|
|
||||||
However, if you want to change this, simply provide the wanted pin mapping as part of the class initialization structure. For example, in your sketch have something like the following:
|
However, if you want to change this, simply provide the wanted pin mapping as part of the class initialization structure. For example, in your sketch have something like the following:
|
||||||
|
@ -65,16 +94,13 @@ However, if you want to change this, simply provide the wanted pin mapping as pa
|
||||||
#define R2_PIN 14
|
#define R2_PIN 14
|
||||||
#define G2_PIN 12
|
#define G2_PIN 12
|
||||||
#define B2_PIN 13
|
#define B2_PIN 13
|
||||||
|
|
||||||
#define A_PIN 23
|
#define A_PIN 23
|
||||||
#define B_PIN 22
|
#define B_PIN 22
|
||||||
#define C_PIN 5
|
#define C_PIN 5
|
||||||
#define D_PIN 17
|
#define D_PIN 17
|
||||||
#define E_PIN -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32
|
#define E_PIN -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32
|
||||||
|
|
||||||
#define LAT_PIN 4
|
#define LAT_PIN 4
|
||||||
#define OE_PIN 15
|
#define OE_PIN 15
|
||||||
|
|
||||||
#define CLK_PIN 16
|
#define CLK_PIN 16
|
||||||
|
|
||||||
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::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};
|
||||||
|
@ -87,80 +113,52 @@ HUB75_I2S_CFG mxconfig(
|
||||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||||
```
|
```
|
||||||
|
|
||||||
The panel must be powered by 5V AC adapter with enough current capacity. (Current varies due to how many LED are turned on at the same time. To drive all the LEDs, you need 5V4A adapter.)
|
|
||||||
|
|
||||||
## 3. Run a Test Sketch
|
## 3. Run a Test Sketch
|
||||||
|
|
||||||
Below is a bare minimum sketch to draw a single white dot in the top left. You must call .begin() before you call ANY pixel-drawing (fonts, lines, colours etc.) function of the MatrixPanel_I2S_DMA class.
|
Below is a bare minimum sketch to draw a single white dot in the top left. You must call .begin() before you call ANY pixel-drawing (fonts, lines, colours etc.) function of the MatrixPanel_I2S_DMA class.
|
||||||
|
|
||||||
No .begin() before other functions = Crash
|
No .begin() before other functions = Crash
|
||||||
```
|
```
|
||||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||||
MatrixPanel_I2S_DMA matrix;
|
MatrixPanel_I2S_DMA matrix;
|
||||||
|
void setup(){
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
// MUST DO THIS FIRST!
|
// MUST DO THIS FIRST!
|
||||||
matrix.begin(); // Use default values for matrix dimentions and pins supplied within ESP32-HUB75-MatrixPanel-I2S-DMA.h
|
matrix.begin(); // Use default values for matrix dimentions and pins supplied within ESP32-HUB75-MatrixPanel-I2S-DMA.h
|
||||||
|
|
||||||
// Draw a single white pixel
|
// Draw a single white pixel
|
||||||
matrix.drawPixel(0,0, matrix.color565(255,255,255)); // can do this after .begin() only
|
matrix.drawPixel(0,0, matrix.color565(255,255,255)); // can do this after .begin() only
|
||||||
|
|
||||||
}
|
}
|
||||||
|
void loop(){ }
|
||||||
void loop()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Once this is working, refer to the [PIO Test Patterns](/examples/PIO_TestPatterns) example. Note: Requires the use of PlatformIO, which you should probably use if you aren't already.
|
Once this is working, refer to the [PIO Test Patterns](/examples/PIO_TestPatterns) example. This sketch draws simple colors/lines/gradients over the entire matrix and it could help to troubleshoot various issues with ghosting, flickering, etc...
|
||||||
|
>Note: Requires the use of [PlatformIO](https://platformio.org/), which you should probably use if you aren't already.
|
||||||
# More Information
|
# More Information
|
||||||
## Build-time options
|
## Build-time options
|
||||||
|
Although Arduino IDE does not [seem](https://github.com/arduino/Arduino/issues/421) to offer any way of specifying compile-time options for external libs there are other IDE's (like [PlatformIO](https://platformio.org/)/[Eclipse](https://www.eclipse.org/ide/)) that could use that. Check [Buld Options](doc/BuildOptions.md) document for reference.
|
||||||
|
|
||||||
Although Arduino IDE does not seem to offer any way of specifying compile-time options for external libs there are other IDE's (like PlatformIO/Eclipse) that could use that. This lib supports the following compile-time defines
|
## Memory constraints
|
||||||
|
If you are going to use large/combined panels make sure to check for [memory constraints](/doc/i2s_memcalc.md).
|
||||||
**USE_GFX_ROOT** - Use lightweight version of AdafuitGFX, without Adafruit BusIO extensions
|
|
||||||
|
|
||||||
|
|
||||||
**NO_GFX** - Build without AdafuitGFX, only native methods supported based on manipulating DMA buffer. I.e. no methods of drawing circles/shapes, typing text or using fonts!!!
|
|
||||||
This might save some resources for applications using it's own internal graphics buffer or works solely with per-pixel manipulation. For example Aurora effects can work fine w/o AdafruitGFX.
|
|
||||||
|
|
||||||
|
|
||||||
**NO_FAST_FUNCTIONS** - do not build auxiliary speed-optimized functions. Those are used to speed-up operations like drawing straight lines or rectangles. Otherwise lines/shapes are drawn using drawPixel() method. The trade-off for speed is RAM/code-size, take it or leave it ;)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Can I use with a larger panel (i.e. 64x64px square panel)?
|
## Can I use with a larger panel (i.e. 64x64px square panel)?
|
||||||
If you want to use with a 64x64 pixel panel (typically a HUB75*E* panel) you MUST configure a valid *E_PIN* to your ESP32 and connect it to the E pin of the HUB75 panel! Hence the 'E' in 'HUB75E'
|
If you want to use with a 64x64 pixel panel (typically a HUB75*E* panel) you MUST configure a valid *E_PIN* to your ESP32 and connect it to the E pin of the HUB75 panel! Hence the 'E' in 'HUB75E'
|
||||||
|
|
||||||
## Can I chain panels?
|
## Can I chain panels?
|
||||||
|
|
||||||
Yes.
|
Yes.
|
||||||
|
For example: If you want to chain two of these horizontally to make a 128x32 panel you can do so by connecting the panels in series using the HUB75 ribbon cable. Than you must provide proper configuration structure to the class constructor letting it know that you use "one long virtual matrix chain". Refer to [Pattern Plasma](/examples/2_PatternPlasma/) example for all the details about configuration setup.
|
||||||
For example: If you want to chain two of these horizontally to make a 128x32 panel you can do so by setting the MATRIX_WIDTH to '128' and connecting the panels in series using the HUB75 ribbon cable.
|
|
||||||
|
|
||||||
Similarly, if you wanted to chain 4 panels to make a 256x32 px horizontal panel, you can easily by setting the MATRIX_WIDTH to '256' and connecting the panels in series using the HUB75 ribbon cable.
|
|
||||||
|
|
||||||
You MUST either change the MATRIX_WIDTH or MATRIX_HEIGHT values within the 'ESP32-HUB75-MatrixPanel-I2S-DMA.h' file OR pass a [compile time option](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/48#issuecomment-749402379) if using PlatformIO for your development (you should use this).
|
|
||||||
|
|
||||||
Finally, if you wanted to chain 4 x (64x32px) panels to make 128x64px display (essentially a 2x2 grid of 64x32 LED Matrix modules), a little more magic will be required. Refer to the [Chained Panels](examples/ChainedPanels/) example.
|
Finally, if you wanted to chain 4 x (64x32px) panels to make 128x64px display (essentially a 2x2 grid of 64x32 LED Matrix modules), a little more magic will be required. Refer to the [Chained Panels](examples/ChainedPanels/) example.
|
||||||
|
|
||||||
Resolutions beyond 128x128 are likely to result in crashes due to memory constraints etc. You're on your own at this point.
|
Resolutions beyond 128x128 are more likely to result in crashes due to [memory](/doc/i2s_memcalc.md) constraints etc. You're on your own at this point.
|
||||||
|
|
||||||
![ezgif com-video-to-gif](https://user-images.githubusercontent.com/12006953/89837358-b64c0480-db60-11ea-870d-4b6482068a3b.gif)
|
![ezgif com-video-to-gif](https://user-images.githubusercontent.com/12006953/89837358-b64c0480-db60-11ea-870d-4b6482068a3b.gif)
|
||||||
|
|
||||||
|
|
||||||
## Panel Brightness
|
## Panel Brightness
|
||||||
|
|
||||||
By default you should not need to change / set the brightness setting as the default value (16) is sufficient for most purposes. Brightness can be changed by calling `setPanelBrightness(int XX)` or `setBrightness8(uint8_t XX)`.
|
By default you should not need to change / set the brightness setting as the default value (16) is sufficient for most purposes. Brightness can be changed by calling `setPanelBrightness(int XX)` or `setBrightness8(uint8_t XX)`.
|
||||||
|
|
||||||
The value to pass 'setPanelBrightness' must be a value less than MATRIX_CHAIN_WIDTH in pixels. For example for a single 64x32 LED Matrix Module, a value must be less than 64. However, if you set the brightness too high, you may experience ghosting.
|
The value to pass `setPanelBrightness()` must be less than MATRIX_CHAIN_WIDTH in pixels. For example for a single 64x32 LED Matrix Module, a value must be less than 64. For 3 modules 64x32 it must be less than 192. However, if you set the brightness too high, you may experience ghosting.
|
||||||
|
|
||||||
Also you may use method `setPanelBrightness8(x)`, where x is a uint8_t value between 0-255. Library will recalculate required brightness level depending on matrix width (mostly useful with FastLED-based sketches).
|
Also you may use method `setPanelBrightness8(x)`, where x is a uint8_t value between 0-255. Library will recalculate required brightness level depending on matrix width (mostly useful with FastLED-based sketches).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
@ -170,18 +168,15 @@ void setup() {
|
||||||
// or another way
|
// or another way
|
||||||
matrix.setPanelBrightness8(192); // Set the brightness to about 3/4 or 75% (192/256) of maximum.
|
matrix.setPanelBrightness8(192); // Set the brightness to about 3/4 or 75% (192/256) of maximum.
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Summary: setPanelBrightness(xx) value can be any number from 0 (display off) to MATRIX_WIDTH-1. So if you are chaining multiple 64x32 panels, then this value may actually be > 64 (or you will have a dim display). Changing the brightness will have a huge impact on power usage.
|
Summary: setPanelBrightness(xx) value can be any number from 0 (display off) to MATRIX_WIDTH-1. So if you are chaining multiple 64x32 panels, then this value may actually be > 64 (or you will have a dim display). Changing the brightness will have a huge impact on power usage.
|
||||||
|
|
||||||
![It's better in real life](image.jpg)
|
![It's better in real life](image.jpg)
|
||||||
|
|
||||||
|
|
||||||
## Latch blanking
|
## Latch blanking
|
||||||
|
If you are facing issues with image ghosting when pixels has clones with horizontal offset, than you try to change Latch blanking value. Latch blanking controls for how many clock pulses matrix output is disabled via EO signal before/after toggling LAT signal. It hides row bits transitioning and different panels may require longer times for proper operation. Default value is 1 clock before/after LAT row transition. This could be controlled with `MatrixPanel_I2S_DMA::setLatBlanking(uint8_t v)`. v could be between 1 to 4, default is 1, larger values won't give any benefit other than reducing brightness.
|
||||||
If you face issues with image ghosting when pixels has clones with horizontal offset, than you try to change Latch blanking value. Latch blanking controls
|
|
||||||
for how many clock pulses matrix output is disabled via EO signal before/after toggling LAT signal. It hides row bits transitioning and different panels may
|
|
||||||
require longer times for proper operation. Default value is 1 clock before/after LAT row transition. This could be controlled with `MatrixPanel_I2S_DMA::setLatBlanking(uint8_t v)`. v could be between 1 to 4, default is 1, larger values won't give any benefit other than reducing brightness.
|
|
||||||
|
|
||||||
|
|
||||||
An example:
|
An example:
|
||||||
```
|
```
|
||||||
|
@ -189,17 +184,14 @@ matrix.setLatBlanking(2);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Power, Power and Power!
|
## Power, Power and Power!
|
||||||
|
|
||||||
Having a good power supply is CRITICAL, and it is highly recommended, for chains of LED Panels to have a 2000uf capacitor soldered to the back of each LED Panel across the [GND and VCC pins](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/39#issuecomment-720780463), otherwise you WILL run into issues with 'flashy' graphics whereby a large amount of LEDs are turned on and off in succession (due to current/power draw peaks and troughs).
|
Having a good power supply is CRITICAL, and it is highly recommended, for chains of LED Panels to have a 2000uf capacitor soldered to the back of each LED Panel across the [GND and VCC pins](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/39#issuecomment-720780463), otherwise you WILL run into issues with 'flashy' graphics whereby a large amount of LEDs are turned on and off in succession (due to current/power draw peaks and troughs).
|
||||||
|
|
||||||
Refer to this guide written for the [rpi-rgb-led-matrix library](https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/wiring.md#a-word-about-power) for an explanation.
|
- Refer to this guide written for the [rpi-rgb-led-matrix library](https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/wiring.md#a-word-about-power) for an explanation.
|
||||||
|
|
||||||
- Refer to this [example](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/39#issuecomment-722691127) issue of what can go wrong with a poor power supply.
|
- Refer to this [example](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/39#issuecomment-722691127) issue of what can go wrong with a poor power supply.
|
||||||
|
|
||||||
|
|
||||||
- Refer to [this comment](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/35#issuecomment-726419862) in regards to certain panels not playing nice with voltages, and a 3.3volt signal that the ESP32 GPIO can only provide.
|
- Refer to [this comment](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/35#issuecomment-726419862) in regards to certain panels not playing nice with voltages, and a 3.3volt signal that the ESP32 GPIO can only provide.
|
||||||
|
|
||||||
## Inspiration
|
## Inspiration
|
||||||
|
|
||||||
* 'SmartMatrix' project code: https://github.com/pixelmatix/SmartMatrix/tree/teensylc
|
* 'SmartMatrix' project code: https://github.com/pixelmatix/SmartMatrix/tree/teensylc
|
||||||
|
|
||||||
* Sprite_TM's demo implementation here: https://www.esp32.com/viewtopic.php?f=17&t=3188
|
* Sprite_TM's demo implementation here: https://www.esp32.com/viewtopic.php?f=17&t=3188
|
||||||
|
|
||||||
|
|
31
doc/BuildOptions.md
Normal file
31
doc/BuildOptions.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
### Build Options and flags
|
||||||
|
|
||||||
|
This lib supports build-time defines used to set some of the basic key features.
|
||||||
|
For example build flags could be set using PlatformIO's .ini file like this
|
||||||
|
|
||||||
|
```
|
||||||
|
[env]
|
||||||
|
framework = arduino
|
||||||
|
platform = espressif32
|
||||||
|
lib_deps =
|
||||||
|
ESP32 HUB75 LED MATRIX PANEL DMA Display
|
||||||
|
build_flags =
|
||||||
|
-DSERIAL_DEBUG
|
||||||
|
-DNO_GFX
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build flags
|
||||||
|
|
||||||
|
| Flag | Description | Note |
|
||||||
|
| :------------ |---------------|-----|
|
||||||
|
| **SERIAL_DEBUG** |Print out detailed information about memory allocations, DMA descriptors setup and color depth [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) |
|
||||||
|
| **USE_GFX_ROOT** | Use [lightweight](https://github.com/mrfaptastic/Adafruit_GFX_Lite) version of AdafuitGFX, without Adafruit BusIO extensions | You **must** install [Adafruit_GFX_Lite](https://github.com/mrfaptastic/Adafruit_GFX_Lite) library instead of original AdafruitGFX|
|
||||||
|
| **NO_GFX** | Build without AdafuitGFX API, only native methods supported based on manipulating DMA buffer. I.e. no methods of drawing circles/shapes, typing text or using fonts!!! This might save some resources for applications using it's own internal graphics buffer or working solely with per-pixel manipulation. | Use this if you rely on FastLED, Neomatrix or any other API. For example [Aurora](/examples/AuroraDemo/) effects can work fine w/o AdafruitGFX. |
|
||||||
|
| **NO_FAST_FUNCTIONS** | Do not build auxiliary speed-optimized functions. Those are used to speed-up operations like drawing straight lines or rectangles. Otherwise lines/shapes are drawn using drawPixel() method. The trade-off for speed is RAM/code-size, take it or leave it ;) | If you are not using AdafruitGFX than you probably do not need this eather|
|
||||||
|
|**NO_CIE1931**|Do not use LED brightness [compensation](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) described in [CIE 1931](https://en.wikipedia.org/wiki/CIE_1931_color_space). Normaly library would adjust every pixel's RGB888 so that liminance (or brighness control) for the corresponding LED's would apper 'linear' to the human's eye. I.e. a white dot with rgb(128,128,128) would seem to be at 50% brightness between rgb(0,0,0) and rgb(255,255,255). Normaly you would like to keep this enabled by default. Not only it makes brightness control "linear", it also makes colors more vivid, otherwise it looks brighter but 'bleached'.|You might want to turn it off in some special cases like: <ul><li>Using some other overlay lib for intermediate calculations that makes it's own compensation, like FastLED's [dimming functions](http://fastled.io/docs/3.1/group___dimming.html).<li>running at low color depth's - it **might** (or might not) look better in shadows, darker gradients w/o compensation, try it<li>you run for as bright output as possible, no matter what (make sure you have proper powering)<li>you run for speed/save resources at all costs</ul> |
|
||||||
|
|
||||||
|
## Build-time variables
|
||||||
|
|
||||||
|
| Flag | Description | Note |
|
||||||
|
| :------------ |---------------|-----|
|
||||||
|
| **PIXEL_COLOR_DEPTH_BITS=8** | Color depth per color per pixel in range 2-8. More bit's - more natural color. But on the other hand every additional bit:<ul><li>eats ~2.5 bits of DMA memoy per pixel<li>reduces matrix refresh rate in power of two due to nature of [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm)</ul> | Default is 8 bits per color per pixel, i.e. TrueColor 24 bit RGB. For higher resolutions, from 64x64 and above it is not possible to provide full 24 bits color without significant flickering OR reducing dynamic range in shadows. In that case using 5-6 bits at high res make very small difference to the humans eye actually. Refer to the [I2S memcalc](i2s_memcalc.md) for more details|
|
40
doc/i2s_memcalc.md
Normal file
40
doc/i2s_memcalc.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
### I2S HUB75 Calculator
|
||||||
|
|
||||||
|
I've made this [spreadsheet](i2s_memcalc.xlsm) to estimate all of the main parameters for ESP32-HUB75-MatrixPanel-I2S-DMA lib driving any combination of matrixes/chains so that I do not need to reflash it hundreds of times just to check for the debug info about memory.
|
||||||
|
Be sure to enable embeded macro's to allow refresh rate calculations.
|
||||||
|
|
||||||
|
![](i2scalc.png)
|
||||||
|
Just fill-in all of the INPUT fields and get the OUTPUTs.
|
||||||
|
|
||||||
|
So there are two main resources used to drive LED matrix
|
||||||
|
- Memory
|
||||||
|
- I2S clock speed (resulting in available bandwidth to pump pixel color data)
|
||||||
|
|
||||||
|
And there are lot's of hogs for those:
|
||||||
|
- matrix resolution (number of pixels)
|
||||||
|
- number of modules in chain
|
||||||
|
- pixel color depth
|
||||||
|
- [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) LSB to MSB transition
|
||||||
|
- double buffering
|
||||||
|
|
||||||
|
Equalising ones with the others results in **Refresh rate**,
|
||||||
|
|
||||||
|
or (rough approximation)
|
||||||
|
<img src="https://render.githubusercontent.com/render/math?math=RefreshRate=\frac{resolution%20\times%20chain%20\times%20(ColorDepth-LSB2MSB)}{%20I%20^2S%20_%20{clock}%20}">
|
||||||
|
|
||||||
|
[//]: # (github markdown does not like LaTex formulas)
|
||||||
|
[//]: # ($$RefreshRate=\frac{resolution \times chain \times (ColorDepth-LSB2MSB)}{ I ^2S _ {clock} }$$)
|
||||||
|
|
||||||
|
So, how to find optimum balance for all of these? Obviously you can't change *resolution* and *chain length*, it is physical characteristics and there is not much you can do about it except cutting of your chain or pushing it to the memory limits.
|
||||||
|
|
||||||
|
There are 3 parameters you can choose from (actually two:)
|
||||||
|
- **Color Depth** - predefined at [build-time]((/doc/BuildOptions.md)) option
|
||||||
|
|
||||||
|
- I2S clock speed - run-time tunable with a very limited options
|
||||||
|
|
||||||
|
- **LSB-to-MSB** transition - it can't be controlled in any way, library uses it internaly trying to balance all of the above
|
||||||
|
|
||||||
|
Using provided table it is possible to estimate all of the parameters before running the library. Besides calculating memory requirements it could help to find **optimum color depth** for your matrix configuration. For higher resolutions default 8 bits could be too much to sustain minimal refresh rate and avoid annoying flickering. So the library would increase MSB transition to keep the balance, thus reducing dynamic range in shadows and dark colors. As a result it is nearly almost the same as just reducing overal color depth. **But** reducing global color depth would also saves lot's of precious RAM!
|
||||||
|
Now it's all up to you to decide :)
|
||||||
|
|
||||||
|
/Vortigont/
|
BIN
doc/i2s_memcalc.xlsm
Normal file
BIN
doc/i2s_memcalc.xlsm
Normal file
Binary file not shown.
BIN
doc/i2scalc.png
Normal file
BIN
doc/i2scalc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
|
@ -138,7 +138,7 @@ void setup() {
|
||||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||||
|
|
||||||
// let's adjust default brightness to about 75%
|
// let's adjust default brightness to about 75%
|
||||||
dma_display->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100%
|
dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100%
|
||||||
|
|
||||||
// Allocate memory and start DMA display
|
// Allocate memory and start DMA display
|
||||||
if( not dma_display->begin() )
|
if( not dma_display->begin() )
|
||||||
|
|
|
@ -58,7 +58,7 @@ void setup(){
|
||||||
// In the setup() function do something like:
|
// In the setup() function do something like:
|
||||||
|
|
||||||
// let's adjust default brightness to about 75%
|
// let's adjust default brightness to about 75%
|
||||||
dma_display->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100%
|
dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100%
|
||||||
|
|
||||||
// Allocate memory and start DMA display
|
// Allocate memory and start DMA display
|
||||||
if( not dma_display->begin() )
|
if( not dma_display->begin() )
|
||||||
|
|
|
@ -192,7 +192,7 @@ void setup() {
|
||||||
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||||
|
|
||||||
// let's adjust default brightness to about 75%
|
// let's adjust default brightness to about 75%
|
||||||
dma_display->setBrightness8(96); // range is 0-255, 0 - 0%, 255 - 100%
|
dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100%
|
||||||
|
|
||||||
// Allocate memory and start DMA display
|
// Allocate memory and start DMA display
|
||||||
if( not dma_display->begin() )
|
if( not dma_display->begin() )
|
||||||
|
|
Loading…
Reference in a new issue