Fix bug with fillScreen and re-implement colour correction

Forgot to implement this two years ago... nobody noticed.
This commit is contained in:
mrfaptastic 2020-08-11 20:44:47 +01:00
parent 4fd25c4a4e
commit 9b2caddbed
6 changed files with 87 additions and 19 deletions

View file

@ -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

View file

@ -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)
{ {

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View file

@ -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",

View file

@ -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