This commit is contained in:
mrfaptastic 2021-10-24 22:04:02 +01:00
commit 3f511c9f6e
33 changed files with 135 additions and 128 deletions

View file

@ -60,7 +60,7 @@
Then we ask the I2S-parallel driver to set up a DMA chain so the subframes are sent out in a sequence that satisfies the requirement that
subframe x has to be sent out for (2^x) ticks. Finally, we fill the subframes with image data.
We use a front buffer/back buffer technique here to make sure the display is refreshed in one go and drawing artifacts do not reach the display.
We use a front buffer/back buffer technique here to make sure the display is refreshed in one go and drawing artefacts do not reach the display.
In practice, for small displays this is not really necessarily.
*/
@ -327,7 +327,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
#endif
// first set of data is LSB through MSB, single pass (IF TOTAL SIZE < DMA_MAX) - all color bits are displayed once, which takes care of everything below and inlcluding LSBMSB_TRANSITION_BIT
// first set of data is LSB through MSB, single pass (IF TOTAL SIZE < DMA_MAX) - all color bits are displayed once, which takes care of everything below and including LSBMSB_TRANSITION_BIT
// NOTE: size must be less than DMA_MAX - worst case for library: 16-bpp with 256 pixels per row would exceed this, need to break into two
link_dma_desc(&dmadesc_a[current_dmadescriptor_offset], previous_dmadesc_a, dma_buff.rowBits[row]->getDataPtr(), dma_buff.rowBits[row]->size(num_dma_payload_color_depths));
previous_dmadesc_a = &dmadesc_a[current_dmadescriptor_offset];
@ -342,12 +342,12 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
if ( rowBitStructBuffSize > DMA_MAX )
{
#if SERIAL_DEBUG
Serial.printf_P(PSTR("Spliting DMA payload for %d color depths into %d byte payloads.\r\n"), PIXEL_COLOR_DEPTH_BITS-1, rowBitStructBuffSize/PIXEL_COLOR_DEPTH_BITS );
Serial.printf_P(PSTR("Splitting DMA payload for %d color depths into %d byte payloads.\r\n"), PIXEL_COLOR_DEPTH_BITS-1, rowBitStructBuffSize/PIXEL_COLOR_DEPTH_BITS );
#endif
for (int cd = 1; cd < PIXEL_COLOR_DEPTH_BITS; cd++)
{
// first set of data is LSB through MSB, single pass - all color bits are displayed once, which takes care of everything below and inlcluding LSBMSB_TRANSITION_BIT
// first set of data is LSB through MSB, single pass - all color bits are displayed once, which takes care of everything below and including LSBMSB_TRANSITION_BIT
// TODO: size must be less than DMA_MAX - worst case for library: 16-bpp with 256 pixels per row would exceed this, need to break into two
link_dma_desc(&dmadesc_a[current_dmadescriptor_offset], previous_dmadesc_a, dma_buff.rowBits[row]->getDataPtr(cd, 0), dma_buff.rowBits[row]->size(num_dma_payload_color_depths) );
previous_dmadesc_a = &dmadesc_a[current_dmadescriptor_offset];
@ -441,7 +441,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
/* There are 'bits' set in the frameStruct that we simply don't need to set every single time we change a pixel / DMA buffer co-ordinate.
* For example, the bits that determine the address lines, we don't need to set these every time. Once they're in place, and assuming we
* don't accidently clear them, then we don't need to set them again.
* don't accidentally clear them, then we don't need to set them again.
* So to save processing, we strip this logic out to the absolute bare minimum, which is toggling only the R,G,B pixels (bits) per co-ord.
*
* Critical dependency: That 'updateMatrixDMABuffer(uint8_t red, uint8_t green, uint8_t blue)' has been run at least once over the
@ -538,7 +538,7 @@ void IRAM_ATTR MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16
ESP32_I2S_DMA_STORAGE_TYPE *p = getRowDataPtr(y_coord, color_depth_idx, back_buffer_id);
// We need to update the correct uint16_t word in the rowBitStruct array poiting to a specific pixel at X - coordinate
// We need to update the correct uint16_t word in the rowBitStruct array pointing to a specific pixel at X - coordinate
p[x_coord] &= _colorbitclear; // reset RGB bits
p[x_coord] |= RGB_output_bits; // set new RGB bits
@ -604,7 +604,7 @@ void MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint
/**
* @brief - clears and reinitializes color/control data in DMA buffs
* When allocated, DMA buffs might be dirtry, so we need to blank it and initialize ABCDE,LAT,OE control bits.
* When allocated, DMA buffs might be dirty, so we need to blank it and initialize ABCDE,LAT,OE control bits.
* Those control bits are constants during the entire DMA sweep and never changed when updating just pixel color data
* so we could set it once on DMA buffs initialization and forget.
* This effectively clears buffers to blank BLACK and makes it ready to display output.
@ -834,7 +834,7 @@ uint8_t MatrixPanel_I2S_DMA::setLatBlanking(uint8_t pulses){
pulses = DEFAULT_LAT_BLANKING;
m_cfg.latch_blanking = pulses;
setPanelBrightness(brightness); // set brighness to reset OE bits to the values matching new LAT blanking setting
setPanelBrightness(brightness); // set brightness to reset OE bits to the values matching new LAT blanking setting
return m_cfg.latch_blanking;
}
@ -979,7 +979,7 @@ void MatrixPanel_I2S_DMA::vlineDMA(int16_t x_coord, int16_t y_coord, int16_t l,
uint16_t _colorbitclear = BITMASK_RGB1_CLEAR;
do { // iterate pixels in a column
if (_y >= ROWS_PER_FRAME){ // if y-coord overlaped bottom-half panel
if (_y >= ROWS_PER_FRAME){ // if y-coord overlapped bottom-half panel
_y -= ROWS_PER_FRAME;
_colorbitclear = BITMASK_RGB2_CLEAR;
RGB_output_bits <<= BITS_RGB2_OFFSET;
@ -999,7 +999,7 @@ void MatrixPanel_I2S_DMA::vlineDMA(int16_t x_coord, int16_t y_coord, int16_t l,
/**
* @brief - update DMA buff drawing a rectangular at specified coordinates
* this works much faster than mulltiple consecutive per-pixel calls to updateMatrixDMABuffer()
* this works much faster than multiple consecutive per-pixel calls to updateMatrixDMABuffer()
* @param int16_t x, int16_t y - coordinates of a top-left corner
* @param int16_t w, int16_t h - width and height of a rectangular, min is 1 px
* @param uint8_t r - RGB888 color

View file

@ -176,7 +176,7 @@
#error "Pixel color depth bits cannot be less than 2."
#endif
/* This library is designed to take an 8 bit / 1 byt value (0-255) for each R G B colour sub-pixel.
/* This library is designed to take an 8 bit / 1 byte value (0-255) for each R G B colour sub-pixel.
* The PIXEL_COLOR_DEPTH_BITS should always be '8' as a result.
* However, if the library is to be used with lower colour depth (i.e. 6 bit colour), then we need to ensure the 8-bit value passed to the colour masking
* is adjusted accordingly to ensure the LSB's are shifted left to MSB, by the difference. Otherwise the colours will be all screwed up.
@ -187,7 +187,7 @@ static constexpr uint8_t const MASK_OFFSET = 8-PIXEL_COLOR_DEPTH_BITS;
/***************************************************************************************/
/** @brief - Structure holds raw DMA data to drive TWO full rows of pixels spaning through all chained modules
/** @brief - Structure holds raw DMA data to drive TWO full rows of pixels spanning through all chained modules
* Note: sizeof(data) must be multiple of 32 bits, as ESP32 DMA linked list buffer address pointer must be word-aligned
*/
struct rowBitStruct {
@ -206,7 +206,7 @@ struct rowBitStruct {
*/
size_t size(uint8_t _dpth=0 ) { if (!_dpth) _dpth = color_depth; return width * _dpth * sizeof(ESP32_I2S_DMA_STORAGE_TYPE); };
/** @brief - returns pointer to the row's data vector begining at pixel[0] for _dpth color bit
/** @brief - returns pointer to the row's data vector beginning at pixel[0] for _dpth color bit
* default - returns pointer to the data vector's head
* NOTE: this call might be very slow in loops. Due to poor instruction caching in esp32 it might be required a reread from flash
* every loop cycle, better use inlined #define instead in such cases
@ -264,7 +264,7 @@ struct HUB75_I2S_CFG {
// physical width of a single matrix panel module (in pixels, usually it is 64 ;) )
uint16_t mx_width;
// physical height of a single matrix panel module (in pixels, usually amost always it is either 32 or 64)
// physical height of a single matrix panel module (in pixels, usually almost always it is either 32 or 64)
uint16_t mx_height;
// number of chained panels regardless of the topology, default 1 - a single matrix module
uint16_t chain_length;
@ -316,7 +316,7 @@ struct HUB75_I2S_CFG {
shift_driver _drv = SHIFTREG,
bool _dbuff = false,
clk_speed _i2sspeed = HZ_10M,
uint8_t _latblk = 1, // Anything > 1 seems to cause artifacts on ICS panels
uint8_t _latblk = 1, // Anything > 1 seems to cause artefacts on ICS panels
bool _clockphase = true,
uint8_t _min_refresh_rate = 85
) : mx_width(_w),
@ -347,7 +347,7 @@ class MatrixPanel_I2S_DMA {
/**
* MatrixPanel_I2S_DMA
*
* default predefined values are used for matrix configuraton
* default predefined values are used for matrix configuration
*
*/
MatrixPanel_I2S_DMA()
@ -372,7 +372,7 @@ class MatrixPanel_I2S_DMA {
#endif
m_cfg(opts) {}
/* Propagate the DMA pin configuration, allocate DMA buffs and start data ouput, initialy blank */
/* Propagate the DMA pin configuration, allocate DMA buffs and start data output, initially blank */
bool begin(){
if (initialized) return true; // we don't do this twice or more!
@ -477,7 +477,7 @@ class MatrixPanel_I2S_DMA {
/**
* @brief - override Adafruit's fillRect
* this works much faster than mulltiple consecutive per-pixel drawPixel() calls
* this works much faster than multiple consecutive per-pixel drawPixel() calls
*/
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
uint8_t r, g, b;
@ -595,7 +595,7 @@ class MatrixPanel_I2S_DMA {
/**
* @brief - clears and reinitializes color/control data in DMA buffs
* When allocated, DMA buffs might be dirtry, so we need to blank it and initialize ABCDE,LAT,OE control bits.
* When allocated, DMA buffs might be dirty, so we need to blank it and initialize ABCDE,LAT,OE control bits.
* Those control bits are constants during the entire DMA sweep and never changed when updating just pixel color data
* so we could set it once on DMA buffs initialization and forget.
* This effectively clears buffers to blank BLACK and makes it ready to display output.
@ -643,7 +643,7 @@ class MatrixPanel_I2S_DMA {
/**
* @brief - update DMA buff drawing a rectangular at specified coordinates
* uses Fast H/V line draw internally, works faster than mulltiple consecutive pixel by pixel calls to updateMatrixDMABuffer()
* uses Fast H/V line draw internally, works faster than multiple consecutive pixel by pixel calls to updateMatrixDMABuffer()
* @param int16_t x, int16_t y - coordinates of a top-left corner
* @param int16_t w, int16_t h - width and height of a rectangular, min is 1 px
* @param uint8_t r - RGB888 color
@ -683,7 +683,7 @@ class MatrixPanel_I2S_DMA {
* (two rows of pixels are refreshed in parallel)
* Memory is allocated (malloc'd) by the row, and not in one massive chunk, for flexibility.
* The whole DMA framebuffer is just a vector of pointers to structs with ESP32_I2S_DMA_STORAGE_TYPE arrays
* Since it's dimensions is unknown prior to class initialization, we just decrale it here as empty struct and will do all allocations later.
* Since it's dimensions is unknown prior to class initialization, we just declare it here as empty struct and will do all allocations later.
* Refer to rowBitStruct to get the idea of it's internal structure
*/
frameStruct dma_buff;

View file

@ -214,7 +214,7 @@ inline void VirtualMatrixPanel::drawDisplayTest()
}
#endif
// need to recreate this one, as it wouldnt work to just map where it starts.
// need to recreate this one, as it wouldn't work to just map where it starts.
inline void VirtualMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t icon_cols, int16_t icon_rows) {
int i, j;
for (i = 0; i < icon_rows; i++) {

View file

@ -35,7 +35,7 @@ This ESP32 Arduino/IDF library for HUB75 / HUB75E connector type 64x32 RGB LED 1
- **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
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".
If you wanna ask "*...OK, OK, than what's 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".
## ESP32 Supported
Espressif have kept the 'ESP32' name for all their chips for brand recognition, but their new variant MCU's are different to the ESP32 this library was built for.
@ -52,7 +52,7 @@ RISC-V ESP32's (like the C3) are not, and will never be supported as they do no
* 32x16 pixel 1/4 Scan LED Matrix 'Indoor' Panel using an ingenious workaround as demonstrated in the 32x16_1_4_ScanPanel example.
* 126x64 [SM5266P](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164) 1/32 Scan Panel
Ones interested in internals of such matrixes could find [this article](https://www.sparkfun.com/news/2650) useful.
Ones interested in internals of such matrices 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.
@ -71,7 +71,7 @@ Due to the high-speed optimized nature of this library, only specific panels are
Please use an [alternative library](https://github.com/2dom/PxMatrix) if you bought one of these.
## Update for 16x32 Panels
* There is a virtual panel class available to work with 16x32 panels (see: [examples/16x32 Panel](/examples/P6_32x16_1_4_ScanPanel). This Panel includes drawing lines and rectanges, text and scrolling text
* There is a virtual panel class available to work with 16x32 panels (see: [examples/16x32 Panel](/examples/P6_32x16_1_4_ScanPanel). This Panel includes drawing lines and rectangles, text and scrolling text
## Cool uses of this library
There are a number of great looking LED graphical display projects which leverage this library, these include:
@ -149,7 +149,7 @@ Once this is working, refer to the [PIO Test Patterns](/examples/PIO_TestPattern
>Note: Requires the use of [PlatformIO](https://platformio.org/), which you should probably use if you aren't already.
# More Information
## 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](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 [Build Options](doc/BuildOptions.md) document for reference.
## Memory constraints
If you are going to use large/combined panels make sure to check for [memory constraints](/doc/i2s_memcalc.md).

View file

@ -21,11 +21,11 @@ build_flags =
| **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> |
| **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 either|
|**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). Normally library would adjust every pixel's RGB888 so that luminance (or brightness control) for the corresponding LED's would appear '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). Normally 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|
| **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 memory 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|

View file

@ -1,13 +1,13 @@
## Estimating fillrate
Here are some results of simple tests on filling DMA buffer with data.
Filling DMA buffer requres lot's of memory operations on a bit level rather than doing simple byte/word wide store and copy. And it looks like it's quite a task both for esp32 core and compiler.
Filling DMA buffer requires lots of memory operations on a bit level rather than doing simple byte/word wide store and copy. And it looks like it's quite a task both for esp32 core and compiler.
I've done this while optimizing loops and bit logic along with testing compiler results.
So the testbed is:
- Matrix modules: 4 x FM6126A based 64x64 modules chained in 256x64
A testpatters sketch:
A testpatterns sketch:
- allocating single DMA buffs for 256x64
- allocating (NUM_LEDS*3) bytes for CRGB buffer
- measuring microseconds for the following calls:
@ -19,7 +19,7 @@ A testpatters sketch:
- drawing lines
||clearScreen()|drawPixelRGB888(), ticks|fillScreen()|fillScreen with a drawPixel()|fillRect() over Maxrix|V-line with drawPixel|fast-V-line|H-line with drawPixel|fast-H-line|
||clearScreen()|drawPixelRGB888(), ticks|fillScreen()|fillScreen with a drawPixel()|fillRect() over Matrix|V-line with drawPixel|fast-V-line|H-line with drawPixel|fast-H-line|
|--|--|--|--|--|--|--|--|--|--|
|v1.2.4|1503113 ticks|9244 non-cached, 675 cached|1719 us, 412272 t|47149 us, 11315418 ticks|-|24505 us, 5880209 ticks|-|24200 us|-|
|FastLines|1503113 ticks|1350 non-cached, 405 cached|1677 us, 401198 t|28511 us, 6841440 ticks|10395 us|14462 us, 3469605 ticks|10391 us, 2492743 ticks|14575 us|5180 us, 1242041 ticks|

View file

@ -1,7 +1,7 @@
### 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.
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 matrices/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 embedded macro's to allow refresh rate calculations.
![](i2scalc.png)
Just fill-in all of the INPUT fields and get the OUTPUTs.
@ -32,9 +32,9 @@ There are 3 parameters you can choose from (actually two:)
- 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
- **LSB-to-MSB** transition - it can't be controlled in any way, library uses it internally 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 save lot's of precious RAM!
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 overall color depth. **But** reducing global color depth would also save lot's of precious RAM!
Now it's all up to you to decide :)
/Vortigont/

View file

@ -295,7 +295,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* co
dev->fifo_conf.tx_fifo_mod = 3;
} else {
// Mode 1, single 16-bit channel, load 16 bit sample(*) into fifo and pad to 32 bit with zeros
// *Actually a 32 bit read where two samples are read at once. Length of fifo must thus still be word-alligned
// *Actually a 32 bit read where two samples are read at once. Length of fifo must thus still be word-aligned
dev->fifo_conf.tx_fifo_mod = 1;
}

View file

@ -17,7 +17,7 @@
#include <esp_err.h>
// Turn on and off a periphal
// Turn on and off a peripheral
#include <driver/periph_ctrl.h>
// GPIO
@ -227,7 +227,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* cf
// setup I2S Interrupt
// SET_PERI_REG_BITS(I2S_INT_ENA_REG(1), I2S_OUT_EOF_INT_ENA_V, 1, I2S_OUT_EOF_INT_ENA_S);
// allocate a level 1 intterupt: lowest priority, as ISR isn't urgent and may take a long time to complete
// allocate a level 1 interrupt: lowest priority, as ISR isn't urgent and may take a long time to complete
esp_intr_alloc(ETS_I2S1_INTR_SOURCE, (int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1), gdma_irq_handler, NULL, NULL);
GDMA.intr[0].ena.out_eof = 1; //?
@ -243,7 +243,7 @@ esp_err_t i2s_parallel_driver_install(i2s_port_t port, i2s_parallel_config_t* cf
// Setup interrupt
// Setup outlink
GDMA.channel[0].out.out_link.addr = ((uint32_t)(&st->dmadesc_a[0]));// Set a vlaue here
GDMA.channel[0].out.out_link.addr = ((uint32_t)(&st->dmadesc_a[0]));// Set a value here
GDMA.channel[0].out.out_peri_sel.sel = SOC_GDMA_TRIG_PERIPH_I2S0; // 3 = I2S0
GDMA.channel[0].out.out_conf0.out_data_burst_en = 1;
GDMA.channel[0].out.out_conf0.outdscr_burst_en = 1;

View file

@ -99,7 +99,7 @@ void setup() {
// 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.mx_height = 32; // physical height of a single matrix panel module (in pixels, usually almost 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;

View file

@ -8,20 +8,20 @@ An excellent insight could be found here https://github.com/hzeller/rpi-rgb-led-
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 :))
one could be written with 12 clock pulses (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!!!
I've done some measurements on power consumption while toggling bits of **REG1** and it looks that it could provide a fine grained brightness 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 brightness (compared to all-zeroes) and 4 bits (2-5) giving decreased brightness!!!
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.
Giving at least 10 bits of hardware brightness control opens pretty nice options for offloading and simplifying 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.
Here are some of the measurements I've took for 2 64x64 panels filled with white color - reg value and corresponding current drain in amps.
|REG1 |bit value|Current, amps |

View file

@ -1,3 +1,3 @@
## FM6126 based LED Matrix Panel Reset ##
FM6216 panels require a special reset sequence before they can be used, check your panel chipset if you have issuees. Refer to this example.
FM6216 panels require a special reset sequence before they can be used, check your panel chipset if you have issues. Refer to this example.

View file

@ -43,7 +43,7 @@ public:
float d = force.mag(); // Distance between objects
d = constrain(d, 5.0, 32.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects
force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction)
float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude
float strength = (G * mass * m.mass) / (d * d); // Calculate gravitational force magnitude
force *= strength; // Get force vector --> magnitude * direction
return force;
}

View file

@ -64,8 +64,8 @@ Effects effects;
Patterns patterns;
/* -------------------------- Some variables -------------------------- */
unsigned long fps = 0, fps_timer; // fps (this is NOT a matix refresh rate!)
unsigned int default_fps = 30, pattern_fps = 30; // default fps limit (this is not a matix refresh conuter!)
unsigned long fps = 0, fps_timer; // fps (this is NOT a matrix refresh rate!)
unsigned int default_fps = 30, pattern_fps = 30; // default fps limit (this is not a matrix refresh counter!)
unsigned long ms_animation_max_duration = 20000; // 20 seconds
unsigned long last_frame=0, ms_previous=0;

View file

@ -48,7 +48,7 @@ uint16_t XY16( uint16_t x, uint16_t y);
/* Convert x,y co-ordinate to flat array index.
* x and y positions start from 0, so must not be >= 'real' panel width or height
* (i.e. 64 pixels or 32 pixels.). Max value: MATRIX_WIDTH-1 etc.
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrixes :(
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrices :(
*/
uint16_t XY( uint8_t x, uint8_t y)
{
@ -56,7 +56,7 @@ uint16_t XY( uint8_t x, uint8_t y)
}
/**
* The one for 256+ matrixes
* The one for 256+ matrices
* otherwise this:
* for (uint8_t i = 0; i < MATRIX_WIDTH; i++) {}
* turns into an infinite loop
@ -66,7 +66,7 @@ uint16_t XY16( uint16_t x, uint16_t y)
if( x >= MATRIX_WIDTH) return 0;
if( y >= MATRIX_HEIGHT) return 0;
return (y * MATRIX_WIDTH) + x + 1; // everything offset by one to capute out of bounds stuff - never displayed by ShowFrame()
return (y * MATRIX_WIDTH) + x + 1; // everything offset by one to compute out of bounds stuff - never displayed by ShowFrame()
}
@ -116,7 +116,7 @@ public:
//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
// we do dynamic allocation for leds buffer, otherwise esp32 toolchain can't link static arrays of such a big size for 256+ matrices
leds = (CRGB *)malloc(NUM_LEDS * sizeof(CRGB));
// allocate mem for noise effect
@ -494,7 +494,7 @@ public:
leds[XY16(i, y - d)].nscale8(dimm);
}
for (int i = y - d; i <= y + d; i++) {
leds[XY16(x + d, i)] += leds[XY16(x + d, i + 1)]; // right colum up
leds[XY16(x + d, i)] += leds[XY16(x + d, i + 1)]; // right column up
leds[XY16(x + d, i)].nscale8(dimm);
}
for (int i = x + d; i >= x - d; i--) {
@ -502,7 +502,7 @@ public:
leds[XY16(i, y + d)].nscale8(dimm);
}
for (int i = y + d; i >= y - d; i--) {
leds[XY16(x - d, i)] += leds[XY16(x - d, i - 1)]; // left colum down
leds[XY16(x - d, i)] += leds[XY16(x - d, i - 1)]; // left column down
leds[XY16(x - d, i)].nscale8(dimm);
}
}

View file

@ -28,7 +28,7 @@
class PatternSpiral : public Drawable {
private:
// Timer stuff (Oszillators)
// Timer stuff (Oscillators)
struct timer {
unsigned long takt;
unsigned long lastMillis;
@ -68,7 +68,7 @@ public:
// set all counting directions positive for the beginning
for (int i = 0; i < timers; i++) multiTimer[i].delta = 1;
// set range (up/down), speed (takt=ms between steps) and starting point of all oszillators
// set range (up/down), speed (takt=ms between steps) and starting point of all oscillators
unsigned long now = millis();
@ -104,10 +104,10 @@ public:
}
unsigned int drawFrame() {
// manage the Oszillators
// manage the Oscillators
UpdateTimers();
// draw just a line defined by 5 oszillators
// draw just a line defined by 5 oscillators
effects.BresenhamLine(
multiTimer[3].count, // x1
multiTimer[4].count, // y1
@ -116,7 +116,7 @@ public:
multiTimer[2].count); // color
// manipulate the screen buffer
// with fixed parameters (could be oszillators too)
// with fixed parameters (could be oscillators too)
// Params: center x, y, radius, scale color down
// --> NOTE: Affects always a SQUARE with an odd length
// effects.SpiralStream(15, 15, 10, 128);

View file

@ -63,9 +63,9 @@ class PatternSwirl : public Drawable {
// The color of each point shifts over time, each at a different speed.
uint16_t ms = millis();
effects.leds[XY(i, j)] += effects.ColorFromCurrentPalette(ms / 11);
//effects.leds[XY(j, i)] += effects.ColorFromCurrentPalette(ms / 13); // this doesn't work for non-square matrixes
//effects.leds[XY(j, i)] += effects.ColorFromCurrentPalette(ms / 13); // this doesn't work for non-square matrices
effects.leds[XY(ni, nj)] += effects.ColorFromCurrentPalette(ms / 17);
//effects.leds[XY(nj, ni)] += effects.ColorFromCurrentPalette(ms / 29); // this doesn't work for non-square matrixes
//effects.leds[XY(nj, ni)] += effects.ColorFromCurrentPalette(ms / 29); // this doesn't work for non-square matrices
effects.leds[XY(i, nj)] += effects.ColorFromCurrentPalette(ms / 37);
effects.leds[XY(ni, j)] += effects.ColorFromCurrentPalette(ms / 41);

View file

@ -137,13 +137,13 @@ class Patterns : public Playlist {
// &incrementalDrift2, // 13 fail
&munch, // 14 ok
&electricMandala, // 15 ok
// &spin, // 16 ok but repeditivev
// &spin, // 16 ok but repetitive
&simplexNoise, // 17 - cool!
// &wave, // 18 ok (can't work with 256+ matrix due to uint8_t vars)
// &rainbowFlag, //20 // fail
&attract, // 21 ok
&swirl, // 22
// &bounce, // boncing line crap
// &bounce, // bouncing line crap
&flock, // works
&infinity, // works
&plasma, // works

View file

@ -146,7 +146,7 @@ def bmp2hex(infile, tablewidth, sizebytes, invert, raw, named, double, xbm):
# Convert tablewidth to characters from hex bytes
tablewidth = int(tablewidth) * 6
# Initilize output buffer
# Initialize output buffer
outstring = ''
# Open File
@ -165,7 +165,7 @@ def bmp2hex(infile, tablewidth, sizebytes, invert, raw, named, double, xbm):
if ((values[0] != 0x42) or (values[1] != 0x4D)):
sys.exit ("Error: Unsupported BMP format. Make sure your file is a Windows BMP.")
# Calculate width, heigth
# Calculate width, height
dataOffset = getLONG(values, 10) # Offset to image data
pixelWidth = getLONG(values, 18) # Width of image
pixelHeight = getLONG(values, 22) # Height of image

View file

@ -42,18 +42,17 @@ void setup()
// Create some Squares
for (int i = 0; i < numSquares; i++)
{
Squares[i].xpos = random(0, display->width());
Squares[i].ypos = random(0, display->height());
Squares[i].square_size = random(2,10);
Squares[i].xpos = random(0, display->width() - Squares[i].square_size);
Squares[i].ypos = random(0, display->height() - Squares[i].square_size);
Squares[i].velocityx = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
Squares[i].velocityy = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
//Squares[i].xdir = (random(2) == 1) ? true:false;
//Squares[i].ydir = (random(2) == 1) ? true:false;
Squares[i].square_size = random(2,10);
int random_num = random(6);
Squares[i].colour = colours[random_num];
}
}
void loop()
@ -64,14 +63,22 @@ void loop()
for (int i = 0; i < numSquares; i++)
{
// Draw rect and then calculatae
// Draw rect and then calculate
display->fillRect(Squares[i].xpos, Squares[i].ypos, Squares[i].square_size, Squares[i].square_size, Squares[i].colour);
if (Squares[i].xpos >= display->width()) { Squares[i].velocityx *= -1; } else if (Squares[i].xpos <= 0) { Squares[i].velocityx = abs (Squares[i].velocityx); }
if (Squares[i].ypos >= display->height()) { Squares[i].velocityy *= -1; } else if (Squares[i].ypos <= 0) { Squares[i].velocityy = abs (Squares[i].velocityy); }
if (Squares[i].square_size + Squares[i].xpos >= display->width()) {
Squares[i].velocityx *= -1;
} else if (Squares[i].xpos <= 0) {
Squares[i].velocityx = abs (Squares[i].velocityx);
}
if (Squares[i].square_size + Squares[i].ypos >= display->height()) {
Squares[i].velocityy *= -1;
} else if (Squares[i].ypos <= 0) {
Squares[i].velocityy = abs (Squares[i].velocityy);
}
Squares[i].xpos += Squares[i].velocityx;
Squares[i].ypos += Squares[i].velocityy;
}
}

View file

@ -43,7 +43,7 @@ public:
float d = force.mag(); // Distance between objects
d = constrain(d, 5.0, 32.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects
force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction)
float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude
float strength = (G * mass * m.mass) / (d * d); // Calculate gravitational force magnitude
force *= strength; // Get force vector --> magnitude * direction
return force;
}

View file

@ -22,7 +22,7 @@
/* -------------------------- Display Config Initialisation -------------------- */
// Assume we have four 64x32 panels daizy-chained and ESP32 attached to the bottom right corner
// Assume we have four 64x32 panels daisy-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.
@ -34,7 +34,7 @@
#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
// Virtual Panel 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 //

View file

@ -48,7 +48,7 @@ uint16_t XY16( uint16_t x, uint16_t y);
/* Convert x,y co-ordinate to flat array index.
* x and y positions start from 0, so must not be >= 'real' panel width or height
* (i.e. 64 pixels or 32 pixels.). Max value: VPANEL_W-1 etc.
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrixes :(
* Ugh... uint8_t - really??? this weak method can't cope with 256+ pixel matrices :(
*/
uint16_t XY( uint8_t x, uint8_t y)
{
@ -56,7 +56,7 @@ uint16_t XY( uint8_t x, uint8_t y)
}
/**
* The one for 256+ matrixes
* The one for 256+ matrices
* otherwise this:
* for (uint8_t i = 0; i < VPANEL_W; i++) {}
* turns into an infinite loop
@ -66,7 +66,7 @@ uint16_t XY16( uint16_t x, uint16_t y)
if( x >= VPANEL_W) return 0;
if( y >= VPANEL_H) return 0;
return (y * VPANEL_W) + x + 1; // everything offset by one to capute out of bounds stuff - never displayed by ShowFrame()
return (y * VPANEL_W) + x + 1; // everything offset by one to compute out of bounds stuff - never displayed by ShowFrame()
}
@ -114,7 +114,7 @@ public:
CRGB *leds;
Effects(){
// we do dynamic allocation for leds buffer, otherwise esp32 toolchain can't link static arrays of such a big size for 256+ matrixes
// we do dynamic allocation for leds buffer, otherwise esp32 toolchain can't link static arrays of such a big size for 256+ matrices
leds = (CRGB *)malloc(NUM_LEDS * sizeof(CRGB));
// allocate mem for noise effect
@ -491,7 +491,7 @@ public:
leds[XY16(i, y - d)].nscale8(dimm);
}
for (int i = y - d; i <= y + d; i++) {
leds[XY16(x + d, i)] += leds[XY16(x + d, i + 1)]; // right colum up
leds[XY16(x + d, i)] += leds[XY16(x + d, i + 1)]; // right column up
leds[XY16(x + d, i)].nscale8(dimm);
}
for (int i = x + d; i >= x - d; i--) {
@ -499,7 +499,7 @@ public:
leds[XY16(i, y + d)].nscale8(dimm);
}
for (int i = y + d; i >= y - d; i--) {
leds[XY16(x - d, i)] += leds[XY16(x - d, i - 1)]; // left colum down
leds[XY16(x - d, i)] += leds[XY16(x - d, i - 1)]; // left column down
leds[XY16(x - d, i)].nscale8(dimm);
}
}

View file

@ -28,7 +28,7 @@
class PatternSpiral : public Drawable {
private:
// Timer stuff (Oszillators)
// Timer stuff (Oscillators)
struct timer {
unsigned long takt;
unsigned long lastMillis;
@ -68,7 +68,7 @@ public:
// set all counting directions positive for the beginning
for (int i = 0; i < timers; i++) multiTimer[i].delta = 1;
// set range (up/down), speed (takt=ms between steps) and starting point of all oszillators
// set range (up/down), speed (takt=ms between steps) and starting point of all oscillators
unsigned long now = millis();
@ -104,10 +104,10 @@ public:
}
unsigned int drawFrame() {
// manage the Oszillators
// manage the Oscillators
UpdateTimers();
// draw just a line defined by 5 oszillators
// draw just a line defined by 5 oscillators
effects.BresenhamLine(
multiTimer[3].count, // x1
multiTimer[4].count, // y1
@ -116,7 +116,7 @@ public:
multiTimer[2].count); // color
// manipulate the screen buffer
// with fixed parameters (could be oszillators too)
// with fixed parameters (could be oscillators too)
// Params: center x, y, radius, scale color down
// --> NOTE: Affects always a SQUARE with an odd length
// effects.SpiralStream(15, 15, 10, 128);

View file

@ -63,9 +63,9 @@ class PatternSwirl : public Drawable {
// The color of each point shifts over time, each at a different speed.
uint16_t ms = millis();
effects.leds[XY(i, j)] += effects.ColorFromCurrentPalette(ms / 11);
//effects.leds[XY(j, i)] += effects.ColorFromCurrentPalette(ms / 13); // this doesn't work for non-square matrixes
//effects.leds[XY(j, i)] += effects.ColorFromCurrentPalette(ms / 13); // this doesn't work for non-square matrices
effects.leds[XY(ni, nj)] += effects.ColorFromCurrentPalette(ms / 17);
//effects.leds[XY(nj, ni)] += effects.ColorFromCurrentPalette(ms / 29); // this doesn't work for non-square matrixes
//effects.leds[XY(nj, ni)] += effects.ColorFromCurrentPalette(ms / 29); // this doesn't work for non-square matrices
effects.leds[XY(i, nj)] += effects.ColorFromCurrentPalette(ms / 37);
effects.leds[XY(ni, j)] += effects.ColorFromCurrentPalette(ms / 41);

View file

@ -135,13 +135,13 @@ class Patterns : public Playlist {
&incrementalDrift2, // 13 fail
&munch, // 14 ok
// &electricMandala, // 15 ok, but ugly (vortigont)
// &spin, // 16 ok but repeditivev
// &spin, // 16 ok but repetitive
// &simplexNoise, // 17 - cool!
// &wave, // 18 ok (can't work with 256+ matrix due to uint8_t vars)
// &rainbowFlag, //20 // fail
&attract, // 21 ok
// &swirl, // 22 ok, but ugly (vortigont)
// &bounce, // boncing line crap
// &bounce, // bouncing line crap
&flock, // works
&infinity, // works
&plasma, // works

View file

@ -103,7 +103,7 @@ class OneEighthMatrixPanel
*/
inline VirtualCoords OneEighthMatrixPanel::getCoords(int16_t x, int16_t y) {
coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
coords.x = coords.y = -1; // By default use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer
// Check if virtual work co-ordinates are outside the virtual display resolution space. This does NOT check
// against the physical real-world DMA matrix resolution / setup configured, that is used to actually output
@ -221,7 +221,7 @@ inline void OneEighthMatrixPanel::setRotate(bool rotate) {
if (rotate) { setRotation(1); } else { setRotation(0); }
}
// need to recreate this one, as it wouldnt work to just map where it starts.
// need to recreate this one, as it wouldn't work to just map where it starts.
inline void OneEighthMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t icon_cols, int16_t icon_rows) {
}

View file

@ -74,7 +74,7 @@ class QuarterScanMatrixPanel : public Adafruit_GFX
return coords.y;
}
// int16_t getVirtualY(int16_t y) {return getCoords(0,y).y;}
/** extende function to draw lines/rects/... **/
/** extended function to draw lines/rects/... **/
virtual uint8_t width() {return VP_WIDTH;};
virtual uint8_t height() {return VP_HEIGHT;};
@ -87,8 +87,8 @@ class QuarterScanMatrixPanel : public Adafruit_GFX
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 size_t write(unsigned char c); // write a character on current cursor position
virtual size_t write(const char *str); // write a character array (string) on current cursor position
virtual void setTextWrap(bool w);
virtual void setCursor (int16_t x, int16_t y);
@ -127,7 +127,7 @@ class QuarterScanMatrixPanel : public Adafruit_GFX
protected:
int16_t cursor_x, cursor_y; // Cursor position
uint8_t size_x, size_y; // Font size Multiplikator default = 1 => 5x7 Font (5widht,7Height)
uint8_t size_x, size_y; // Font size Multiplier default = 1 => 5x7 Font (5width,7Height)
uint16_t textFGColor, textBGColor;
bool wrap ; // < If set, 'wrap' text at right edge of display
uint8_t dir ; // used for scrolling text direction
@ -150,7 +150,7 @@ class QuarterScanMatrixPanel : public Adafruit_GFX
***************************************************************************************/
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
// than we move through this array and draw line per line and move this line
// one position to dir
const uint8_t xSize = 6;
uint16_t len = strlen(str);
@ -308,7 +308,7 @@ inline void QuarterScanMatrixPanel::scrollChar(int16_t x, int16_t y, unsigned ch
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
// first line is the first 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)
@ -320,7 +320,7 @@ inline void QuarterScanMatrixPanel::scrollChar(int16_t x, int16_t y, unsigned ch
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
// loop through a column of current character
Serial.printf("i:%d ", i);
// ignore all pixels outside panel
if (x+i >= VP_WIDTH) continue;
@ -360,7 +360,7 @@ inline void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char
{
//Serial.printf("unmapped : drawChar(%d, %d, %c) \n",x, y, c);
// note: remapping to 16x32 coordinats is done inside drawPixel() or fillRect
// note: remapping to 16x32 coordinates is done inside drawPixel() or fillRect
if ((x >= VP_WIDTH) ||
(y >= VP_HEIGHT) ||
@ -377,14 +377,14 @@ inline void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char
//Serial.printf("");
drawPixel(x + i, y + j, color);
else
// remark: it's important to call function with orgininal coordinates for x/y
// remark: it's important to call function with original 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
// remark: it's important to call function with original coordinates for x/y
fillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg);
}
}
@ -445,7 +445,7 @@ inline void QuarterScanMatrixPanel::drawPixelRGB24(int16_t x, int16_t y, RGB24 c
*/
// need to recreate this one, as it wouldnt work to just map where it starts.
// need to recreate this one, as it wouldn't 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

View file

@ -53,7 +53,7 @@ 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`
Draw String at position 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)

View file

@ -1,6 +1,6 @@
# Test Patterns
Simple solid colors, gradients and test line patterns, could be used to test matrixes for proper operation, flickering and estimate fillrate timings.
Simple solid colors, gradients and test line patterns, could be used to test matrices for proper operation, flickering and estimate fillrate timings.
Should be build and uploaded as a [platformio](https://platformio.org/) project

View file

@ -94,7 +94,7 @@ void setup(){
matrix->begin();
matrix->setBrightness8(255);
// longer latch blanking could help to elliminate ghosting in some cases
// longer latch blanking could help to eliminate ghosting in some cases
//matrix->setLatBlanking(2);
ledbuff = (CRGB *)malloc(NUM_LEDS * sizeof(CRGB)); // allocate buffer for some tests
@ -383,7 +383,7 @@ void IRAM_ATTR mxfill(CRGB *leds){
//
/**
* The one for 256+ matrixes
* The one for 256+ matrices
* otherwise this:
* for (uint8_t i = 0; i < MATRIX_WIDTH; i++) {}
* turns into an infinite loop