Fix bug with fillScreen and re-implement colour correction
Forgot to implement this two years ago... nobody noticed.
This commit is contained in:
parent
4fd25c4a4e
commit
9b2caddbed
6 changed files with 87 additions and 19 deletions
|
@ -52,6 +52,18 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// For development testing only
|
||||||
|
//#define IGNORE_REFRESH_RATE 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t val2PWM(int val) {
|
||||||
|
if (val<0) val=0;
|
||||||
|
if (val>255) val=255;
|
||||||
|
return lumConvTab[val];
|
||||||
|
}
|
||||||
|
|
||||||
bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
|
bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -142,15 +154,18 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
* Step 2: Calculate the amount of memory required for the DMA engine's linked list descriptors.
|
* Step 2: Calculate the amount of memory required for the DMA engine's linked list descriptors.
|
||||||
* Credit to SmartMatrix for this stuff.
|
* Credit to SmartMatrix for this stuff.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Calculate what color depth is actually possible based on memory avaialble vs. required dma linked-list descriptors.
|
// Calculate what color depth is actually possible based on memory avaialble vs. required dma linked-list descriptors.
|
||||||
// aka. Calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory
|
// aka. Calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory
|
||||||
int numDMAdescriptorsPerRow = 0;
|
int numDMAdescriptorsPerRow = 0;
|
||||||
lsbMsbTransitionBit = 0;
|
lsbMsbTransitionBit = 0;
|
||||||
|
|
||||||
|
#ifndef IGNORE_REFRESH_RATE
|
||||||
while(1) {
|
while(1) {
|
||||||
numDMAdescriptorsPerRow = 1;
|
numDMAdescriptorsPerRow = 1;
|
||||||
for(int i=lsbMsbTransitionBit + 1; i<PIXEL_COLOR_DEPTH_BITS; i++) {
|
for(int i=lsbMsbTransitionBit + 1; i<PIXEL_COLOR_DEPTH_BITS; i++) {
|
||||||
numDMAdescriptorsPerRow += 1<<(i - lsbMsbTransitionBit - 1);
|
numDMAdescriptorsPerRow += (1<<(i - lsbMsbTransitionBit - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int ramrequired = numDMAdescriptorsPerRow * ROWS_PER_FRAME * _num_frame_buffers * sizeof(lldesc_t);
|
int ramrequired = numDMAdescriptorsPerRow * ROWS_PER_FRAME * _num_frame_buffers * sizeof(lldesc_t);
|
||||||
|
@ -169,9 +184,10 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("Raised lsbMsbTransitionBit to %d/%d to fit in remaining RAM\r\n", lsbMsbTransitionBit, PIXEL_COLOR_DEPTH_BITS - 1);
|
Serial.printf("Raised lsbMsbTransitionBit to %d/%d to fit in remaining RAM\r\n", lsbMsbTransitionBit, PIXEL_COLOR_DEPTH_BITS - 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
// calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory that will meet or exceed the configured refresh rate
|
// calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory that will meet or exceed the configured refresh rate
|
||||||
while(1) {
|
while(1) {
|
||||||
int psPerClock = 1000000000000UL/ESP32_I2S_CLOCK_SPEED;
|
int psPerClock = 1000000000000UL/ESP32_I2S_CLOCK_SPEED;
|
||||||
int nsPerLatch = ((PIXELS_PER_ROW + CLKS_DURING_LATCH) * psPerClock) / 1000;
|
int nsPerLatch = ((PIXELS_PER_ROW + CLKS_DURING_LATCH) * psPerClock) / 1000;
|
||||||
|
|
||||||
|
@ -200,6 +216,7 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("Raised lsbMsbTransitionBit to %d/%d to meet minimum refresh rate\r\n", lsbMsbTransitionBit, PIXEL_COLOR_DEPTH_BITS - 1);
|
Serial.printf("Raised lsbMsbTransitionBit to %d/%d to meet minimum refresh rate\r\n", lsbMsbTransitionBit, PIXEL_COLOR_DEPTH_BITS - 1);
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Step 2a: lsbMsbTransition bit is now finalised - recalculate the DMA descriptor count required, which is used for
|
* Step 2a: lsbMsbTransition bit is now finalised - recalculate the DMA descriptor count required, which is used for
|
||||||
|
@ -207,7 +224,7 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
*/
|
*/
|
||||||
numDMAdescriptorsPerRow = 1;
|
numDMAdescriptorsPerRow = 1;
|
||||||
for(int i=lsbMsbTransitionBit + 1; i<PIXEL_COLOR_DEPTH_BITS; i++) {
|
for(int i=lsbMsbTransitionBit + 1; i<PIXEL_COLOR_DEPTH_BITS; i++) {
|
||||||
numDMAdescriptorsPerRow += 1<<(i - lsbMsbTransitionBit - 1);
|
numDMAdescriptorsPerRow += (1<<(i - lsbMsbTransitionBit - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refer to 'DMA_LL_PAYLOAD_SPLIT' code in configureDMA() below to understand why this exists.
|
// Refer to 'DMA_LL_PAYLOAD_SPLIT' code in configureDMA() below to understand why this exists.
|
||||||
|
@ -366,7 +383,11 @@ void RGB64x32MatrixPanel_I2S_DMA::configureDMA(int r1_pin, int g1_pin, int b1_
|
||||||
// we need 2^(i - LSBMSB_TRANSITION_BIT - 1) == 1 << (i - LSBMSB_TRANSITION_BIT - 1) passes from i to MSB
|
// we need 2^(i - LSBMSB_TRANSITION_BIT - 1) == 1 << (i - LSBMSB_TRANSITION_BIT - 1) passes from i to MSB
|
||||||
//Serial.printf("buffer %d: repeat %d times, size: %d, from %d - %d\r\n", current_dmadescriptor_offset, 1<<(i - lsbMsbTransitionBit - 1), (PIXEL_COLOR_DEPTH_BITS - i), i, PIXEL_COLOR_DEPTH_BITS-1);
|
//Serial.printf("buffer %d: repeat %d times, size: %d, from %d - %d\r\n", current_dmadescriptor_offset, 1<<(i - lsbMsbTransitionBit - 1), (PIXEL_COLOR_DEPTH_BITS - i), i, PIXEL_COLOR_DEPTH_BITS-1);
|
||||||
|
|
||||||
for(int k=0; k < 1<<(i - lsbMsbTransitionBit - 1); k++)
|
#if SERIAL_DEBUG
|
||||||
|
Serial.printf("configureDMA(): DMA Loops for PIXEL_COLOR_DEPTH_BITS %d is: %d.\r\n", i, (1<<(i - lsbMsbTransitionBit - 1)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(int k=0; k < (1<<(i - lsbMsbTransitionBit - 1)); k++)
|
||||||
{
|
{
|
||||||
link_dma_desc(&dmadesc_a[current_dmadescriptor_offset], previous_dmadesc_a, &(fb_malloc_ptr[0].rowdata[fb_malloc_j].rowbits[i].data), sizeof(rowBitStruct) * (PIXEL_COLOR_DEPTH_BITS - i));
|
link_dma_desc(&dmadesc_a[current_dmadescriptor_offset], previous_dmadesc_a, &(fb_malloc_ptr[0].rowdata[fb_malloc_j].rowbits[i].data), sizeof(rowBitStruct) * (PIXEL_COLOR_DEPTH_BITS - i));
|
||||||
previous_dmadesc_a = &dmadesc_a[current_dmadescriptor_offset];
|
previous_dmadesc_a = &dmadesc_a[current_dmadescriptor_offset];
|
||||||
|
@ -450,12 +471,26 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SPLIT_MEMORY_MODE
|
/* LED Brightness Compensation. Because if we do a basic "red & mask" for example,
|
||||||
#ifdef SERIAL_DEBUG
|
* we'll NEVER send the dimmest possible colour, due to binary skew.
|
||||||
int tmp_y_coord = y_coord;
|
|
||||||
#endif
|
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'
|
||||||
#endif
|
|
||||||
|
*/
|
||||||
|
red = lumConvTab[red];
|
||||||
|
green = lumConvTab[green];
|
||||||
|
blue = lumConvTab[blue];
|
||||||
|
/*
|
||||||
|
red = val2PWM(red);
|
||||||
|
green = val2PWM(green);
|
||||||
|
blue = val2PWM(blue);
|
||||||
|
*/
|
||||||
|
#ifdef SPLIT_MEMORY_MODE
|
||||||
|
#ifdef SERIAL_DEBUG
|
||||||
|
int tmp_y_coord = y_coord;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 1) Check that the co-ordinates are within range, or it'll break everything big time.
|
/* 1) Check that the co-ordinates are within range, or it'll break everything big time.
|
||||||
* Valid co-ordinates are from 0 to (MATRIX_XXXX-1)
|
* Valid co-ordinates are from 0 to (MATRIX_XXXX-1)
|
||||||
|
@ -475,6 +510,7 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
|
||||||
paint_top_half = false;
|
paint_top_half = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(int color_depth_idx=0; color_depth_idx<PIXEL_COLOR_DEPTH_BITS; color_depth_idx++) // color depth - 8 iterations
|
for(int color_depth_idx=0; color_depth_idx<PIXEL_COLOR_DEPTH_BITS; color_depth_idx++) // color depth - 8 iterations
|
||||||
{
|
{
|
||||||
uint16_t mask = (1 << color_depth_idx); // 24 bit color
|
uint16_t mask = (1 << color_depth_idx); // 24 bit color
|
||||||
|
@ -561,6 +597,15 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
|
||||||
} else {
|
} else {
|
||||||
tmp_x_coord += 1;
|
tmp_x_coord += 1;
|
||||||
} // end reordering
|
} // end reordering
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Development / testing code only.
|
||||||
|
Serial.printf("r value of %d, color depth: %d, mask: %d\r\n", red, color_depth_idx, mask);
|
||||||
|
if (red & mask) { Serial.println("Success - Binary"); v|=BIT_R1; }
|
||||||
|
Serial.printf("val2pwm r value: %d\r\n", val2PWM(red));
|
||||||
|
if (val2PWM(red) & mask) { Serial.println("Success - PWM"); v|=BIT_R2; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
if (paint_top_half)
|
if (paint_top_half)
|
||||||
{ // Need to copy what the RGB status is for the bottom pixels
|
{ // Need to copy what the RGB status is for the bottom pixels
|
||||||
|
@ -617,6 +662,16 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
|
||||||
void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint8_t blue)
|
void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint8_t blue)
|
||||||
{
|
{
|
||||||
if ( !everything_OK ) return;
|
if ( !everything_OK ) return;
|
||||||
|
|
||||||
|
/* https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/ */
|
||||||
|
/*
|
||||||
|
red = val2PWM(red);
|
||||||
|
green = val2PWM(green);
|
||||||
|
blue = val2PWM(blue);
|
||||||
|
*/
|
||||||
|
red = lumConvTab[red];
|
||||||
|
green = lumConvTab[green];
|
||||||
|
blue = lumConvTab[blue];
|
||||||
|
|
||||||
for (unsigned int matrix_frame_parallel_row = 0; matrix_frame_parallel_row < ROWS_PER_FRAME; matrix_frame_parallel_row++) // half height - 16 iterations
|
for (unsigned int matrix_frame_parallel_row = 0; matrix_frame_parallel_row < ROWS_PER_FRAME; matrix_frame_parallel_row++) // half height - 16 iterations
|
||||||
{
|
{
|
||||||
|
@ -698,9 +753,9 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t gre
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top and bottom matrix MATRIX_ROWS_IN_PARALLEL half colours
|
// Top and bottom matrix MATRIX_ROWS_IN_PARALLEL half colours
|
||||||
if (green & mask) { v|=BIT_G1; v|=BIT_R2; }
|
if (green & mask) { v|=BIT_G1; v|=BIT_G2; }
|
||||||
if (blue & mask) { v|=BIT_B1; v|=BIT_G2; }
|
if (blue & mask) { v|=BIT_B1; v|=BIT_B2; }
|
||||||
if (red & mask) { v|=BIT_R1; v|=BIT_B2; }
|
if (red & mask) { v|=BIT_R1; v|=BIT_R2; }
|
||||||
|
|
||||||
// 16 bit parallel mode
|
// 16 bit parallel mode
|
||||||
//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
|
||||||
|
|
|
@ -123,7 +123,7 @@
|
||||||
#define ESP32_I2S_DMA_MODE I2S_PARALLEL_BITS_16 // Pump 16 bits out in parallel
|
#define ESP32_I2S_DMA_MODE I2S_PARALLEL_BITS_16 // Pump 16 bits out in parallel
|
||||||
#define ESP32_I2S_DMA_STORAGE_TYPE uint16_t // one uint16_t at a time.
|
#define ESP32_I2S_DMA_STORAGE_TYPE uint16_t // one uint16_t at a time.
|
||||||
//#define ESP32_I2S_CLOCK_SPEED (20000000UL) // @ 20Mhz
|
//#define ESP32_I2S_CLOCK_SPEED (20000000UL) // @ 20Mhz
|
||||||
#define ESP32_I2S_CLOCK_SPEED (10000000UL) // @ 10Mhz
|
#define ESP32_I2S_CLOCK_SPEED (10000000UL) // @ 10Mhz
|
||||||
#define CLKS_DURING_LATCH 0 // Not used.
|
#define CLKS_DURING_LATCH 0 // Not used.
|
||||||
/***************************************************************************************/
|
/***************************************************************************************/
|
||||||
|
|
||||||
|
@ -173,6 +173,13 @@ typedef struct rgb_24 {
|
||||||
} rgb_24;
|
} rgb_24;
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************/
|
||||||
|
// Used by val2PWM
|
||||||
|
//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
|
||||||
|
const uint16_t 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};
|
||||||
|
|
||||||
/***************************************************************************************/
|
/***************************************************************************************/
|
||||||
#ifdef USE_GFX_ROOT
|
#ifdef USE_GFX_ROOT
|
||||||
class RGB64x32MatrixPanel_I2S_DMA : public GFX {
|
class RGB64x32MatrixPanel_I2S_DMA : public GFX {
|
||||||
|
@ -252,6 +259,7 @@ class RGB64x32MatrixPanel_I2S_DMA : public Adafruit_GFX {
|
||||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color); // overwrite adafruit implementation
|
virtual void drawPixel(int16_t x, int16_t y, uint16_t color); // overwrite adafruit implementation
|
||||||
virtual void fillScreen(uint16_t color); // overwrite adafruit implementation
|
virtual void fillScreen(uint16_t color); // overwrite adafruit implementation
|
||||||
void clearScreen() { fillScreen(0); }
|
void clearScreen() { fillScreen(0); }
|
||||||
|
void fillScreenRGB888(uint8_t r, uint8_t g, uint8_t b);
|
||||||
void drawPixelRGB565(int16_t x, int16_t y, uint16_t color);
|
void drawPixelRGB565(int16_t x, int16_t y, uint16_t color);
|
||||||
void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b);
|
void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b);
|
||||||
void drawPixelRGB24(int16_t x, int16_t y, rgb_24 color);
|
void drawPixelRGB24(int16_t x, int16_t y, rgb_24 color);
|
||||||
|
@ -367,6 +375,11 @@ inline void RGB64x32MatrixPanel_I2S_DMA::fillScreen(uint16_t color) // adafruit
|
||||||
updateMatrixDMABuffer(r, g, b); // the RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
updateMatrixDMABuffer(r, g, b); // the RGB only (no pixel coordinate) version of 'updateMatrixDMABuffer'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void RGB64x32MatrixPanel_I2S_DMA::fillScreenRGB888(uint8_t r, uint8_t g,uint8_t b) // adafruit virtual void override
|
||||||
|
{
|
||||||
|
updateMatrixDMABuffer(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
// For adafruit
|
// For adafruit
|
||||||
inline void RGB64x32MatrixPanel_I2S_DMA::drawPixelRGB565(int16_t x, int16_t y, uint16_t color)
|
inline void RGB64x32MatrixPanel_I2S_DMA::drawPixelRGB565(int16_t x, int16_t y, uint16_t color)
|
||||||
{
|
{
|
||||||
|
|
BIN
examples/AnimatedGIFPanel/data/gifs/shock-gs.gif
Normal file
BIN
examples/AnimatedGIFPanel/data/gifs/shock-gs.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
Before Width: | Height: | Size: 46 KiB |
|
@ -10,13 +10,13 @@
|
||||||
"name": "Faptastic",
|
"name": "Faptastic",
|
||||||
"url": "https://github.com/mrfaptastic/"
|
"url": "https://github.com/mrfaptastic/"
|
||||||
},
|
},
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"frameworks": "arduino",
|
"frameworks": "arduino",
|
||||||
"platforms": "esp32",
|
"platforms": "esp32",
|
||||||
"examples": [
|
"examples": [
|
||||||
"examples/AnimatedGIF/*.ino",
|
"examples/AnimatedGIFPanel/*.ino",
|
||||||
"examples/AnimatedGIF/*.cpp",
|
"examples/AnimatedGIFPanel/*.cpp",
|
||||||
"examples/AnimatedGIF/*.h",
|
"examples/AnimatedGIFPanel/*.h",
|
||||||
"examples/AuroraDemo/*.ino",
|
"examples/AuroraDemo/*.ino",
|
||||||
"examples/AuroraDemo/*.cpp",
|
"examples/AuroraDemo/*.cpp",
|
||||||
"examples/AuroraDemo/*.h",
|
"examples/AuroraDemo/*.h",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name=ESP32 64x32 LED MATRIX HUB75 DMA Display
|
name=ESP32 64x32 LED MATRIX HUB75 DMA Display
|
||||||
version=1.1.0
|
version=1.2.0
|
||||||
author=Faptastic
|
author=Faptastic
|
||||||
maintainer=Faptastic
|
maintainer=Faptastic
|
||||||
sentence=Experimental DMA based LED Matrix HUB75 Library
|
sentence=Experimental DMA based LED Matrix HUB75 Library
|
||||||
|
|
Loading…
Reference in a new issue