Make PIXEL_COLOR_DEPTH_BITS part of HUB75_I2S_CFG (able to set at runtime)

This commit is contained in:
Lukas 2023-03-10 11:46:17 +01:00
parent 2abd685b7a
commit c804f0d7af
2 changed files with 78 additions and 36 deletions

View file

@ -27,14 +27,15 @@
* 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 * 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. * is adjusted accordingly to ensure the LSB's are shifted left to MSB, by the difference. Otherwise the colours will be all screwed up.
*/ */
#if PIXEL_COLOR_DEPTH_BITS > 12 //#if PIXEL_COLOR_DEPTH_BITS > 12
#error "Color depth bits cannot be greater than 12." // #error "Color depth bits cannot be greater than 12."
#elif PIXEL_COLOR_DEPTH_BITS < 2 //#elif PIXEL_COLOR_DEPTH_BITS < 2
#error "Color depth bits cannot be less than 2." // #error "Color depth bits cannot be less than 2."
#endif //#endif
#define MASK_OFFSET (16 - PIXEL_COLOR_DEPTH_BITS) //#define MASK_OFFSET (16 - PIXEL_COLOR_DEPTH_BITS)
#define PIXEL_COLOR_MASK_BIT(color_depth_index) (1 << (color_depth_index + MASK_OFFSET)) //#define PIXEL_COLOR_MASK_BIT(color_depth_index) (1 << (color_depth_index + MASK_OFFSET))
#define PIXEL_COLOR_MASK_BIT(color_depth_index, mask_offset) (1 << (color_depth_index + mask_offset))
//static constexpr uint8_t const MASK_OFFSET = 8-PIXEL_COLOUR_DEPTH_BITS; //static constexpr uint8_t const MASK_OFFSET = 8-PIXEL_COLOUR_DEPTH_BITS;
/* /*
@ -57,15 +58,16 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
// lets allocate a chunk of memory for each row (a row could span multiple panels if chaining is in place) // lets allocate a chunk of memory for each row (a row could span multiple panels if chaining is in place)
dma_buff.rowBits.reserve(ROWS_PER_FRAME); dma_buff.rowBits.reserve(ROWS_PER_FRAME);
ESP_LOGI("I2S-DMA", "allocating rowBitStructs with pixel_color_depth_bits of %d", m_cfg.getPixelColorDepthBits());
// iterate through number of rows, allocate memory for each // iterate through number of rows, allocate memory for each
size_t allocated_fb_memory = 0; size_t allocated_fb_memory = 0;
for (int malloc_num =0; malloc_num < ROWS_PER_FRAME; ++malloc_num) for (int malloc_num =0; malloc_num < ROWS_PER_FRAME; ++malloc_num)
{ {
auto ptr = std::make_shared<rowBitStruct>(PIXELS_PER_ROW, PIXEL_COLOR_DEPTH_BITS, m_cfg.double_buff); auto ptr = std::make_shared<rowBitStruct>(PIXELS_PER_ROW, m_cfg.getPixelColorDepthBits(), m_cfg.double_buff);
if (ptr->data == nullptr) if (ptr->data == nullptr)
{ {
ESP_LOGE("I2S-DMA", "CRITICAL ERROR: Not enough memory for requested colour depth! Please reduce PIXEL_COLOR_DEPTH_BITS value.\r\n"); ESP_LOGE("I2S-DMA", "CRITICAL ERROR: Not enough memory for requested colour depth! Please reduce pixel_color_depth_bits value.\r\n");
ESP_LOGE("I2S-DMA", "Could not allocate rowBitStruct %d!.\r\n", malloc_num); ESP_LOGE("I2S-DMA", "Could not allocate rowBitStruct %d!.\r\n", malloc_num);
return false; return false;
@ -88,11 +90,11 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
int nsPerLatch = ((PIXELS_PER_ROW + CLKS_DURING_LATCH) * psPerClock) / 1000; int nsPerLatch = ((PIXELS_PER_ROW + CLKS_DURING_LATCH) * psPerClock) / 1000;
// add time to shift out LSBs + LSB-MSB transition bit - this ignores fractions... // add time to shift out LSBs + LSB-MSB transition bit - this ignores fractions...
int nsPerRow = PIXEL_COLOR_DEPTH_BITS * nsPerLatch; int nsPerRow = m_cfg.getPixelColorDepthBits() * nsPerLatch;
// add time to shift out MSBs // add time to shift out MSBs
for(int i=lsbMsbTransitionBit + 1; i<PIXEL_COLOR_DEPTH_BITS; i++) for(int i=lsbMsbTransitionBit + 1; i < m_cfg.getPixelColorDepthBits(); i++)
nsPerRow += (1<<(i - lsbMsbTransitionBit - 1)) * (PIXEL_COLOR_DEPTH_BITS - i) * nsPerLatch; nsPerRow += (1<<(i - lsbMsbTransitionBit - 1)) * (m_cfg.getPixelColorDepthBits() - i) * nsPerLatch;
int nsPerFrame = nsPerRow * ROWS_PER_FRAME; int nsPerFrame = nsPerRow * ROWS_PER_FRAME;
int actualRefreshRate = 1000000000UL/(nsPerFrame); int actualRefreshRate = 1000000000UL/(nsPerFrame);
@ -103,7 +105,7 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
if (actualRefreshRate > m_cfg.min_refresh_rate) if (actualRefreshRate > m_cfg.min_refresh_rate)
break; break;
if(lsbMsbTransitionBit < PIXEL_COLOR_DEPTH_BITS - 1) if(lsbMsbTransitionBit < m_cfg.getPixelColorDepthBits() - 1)
lsbMsbTransitionBit++; lsbMsbTransitionBit++;
else else
break; break;
@ -114,6 +116,8 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
ESP_LOGW("I2S-DMA", "lsbMsbTransitionBit of %d used to achieve refresh rate of %d Hz. Percieved colour depth to the eye may be reduced.", lsbMsbTransitionBit, m_cfg.min_refresh_rate); ESP_LOGW("I2S-DMA", "lsbMsbTransitionBit of %d used to achieve refresh rate of %d Hz. Percieved colour depth to the eye may be reduced.", lsbMsbTransitionBit, m_cfg.min_refresh_rate);
} }
ESP_LOGI("I2S-DMA", "DMA has pixel_color_depth_bits of %d", m_cfg.getPixelColorDepthBits() - lsbMsbTransitionBit);
#endif #endif
@ -122,7 +126,7 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
* memory allocation of the DMA linked list memory structure. * memory allocation of the DMA linked list memory structure.
*/ */
int numDMAdescriptorsPerRow = 1; int numDMAdescriptorsPerRow = 1;
for(int i=lsbMsbTransitionBit + 1; i<PIXEL_COLOR_DEPTH_BITS; i++) { for(int i=lsbMsbTransitionBit + 1; i < m_cfg.getPixelColorDepthBits(); i++) {
numDMAdescriptorsPerRow += (1<<(i - lsbMsbTransitionBit - 1)); numDMAdescriptorsPerRow += (1<<(i - lsbMsbTransitionBit - 1));
} }
@ -133,9 +137,9 @@ bool MatrixPanel_I2S_DMA::allocateDMAmemory()
if ( dma_buff.rowBits[0]->size() > DMA_MAX ) if ( dma_buff.rowBits[0]->size() > DMA_MAX )
{ {
ESP_LOGW("I2S-DMA", "rowBits struct is too large to fit in one DMA transfer payload, splitting required. Adding %d DMA descriptors\n", PIXEL_COLOR_DEPTH_BITS-1); ESP_LOGW("I2S-DMA", "rowBits struct is too large to fit in one DMA transfer payload, splitting required. Adding %d DMA descriptors\n", m_cfg.getPixelColorDepthBits()-1);
numDMAdescriptorsPerRow += PIXEL_COLOR_DEPTH_BITS-1; numDMAdescriptorsPerRow += m_cfg.getPixelColorDepthBits()-1;
// Note: If numDMAdescriptorsPerRow is even just one descriptor too large, DMA linked list will not correctly loop. // Note: If numDMAdescriptorsPerRow is even just one descriptor too large, DMA linked list will not correctly loop.
} }
@ -169,7 +173,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
int current_dmadescriptor_offset = 0; int current_dmadescriptor_offset = 0;
// HACK: If we need to split the payload in 1/2 so that it doesn't breach DMA_MAX, lets do it by the colour_depth. // HACK: If we need to split the payload in 1/2 so that it doesn't breach DMA_MAX, lets do it by the colour_depth.
int num_dma_payload_colour_depths = PIXEL_COLOR_DEPTH_BITS; int num_dma_payload_colour_depths = m_cfg.getPixelColorDepthBits();
if ( dma_buff.rowBits[0]->size() > DMA_MAX ) { if ( dma_buff.rowBits[0]->size() > DMA_MAX ) {
num_dma_payload_colour_depths = 1; num_dma_payload_colour_depths = 1;
} }
@ -195,7 +199,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
if ( dma_buff.rowBits[0]->size() > DMA_MAX ) if ( dma_buff.rowBits[0]->size() > DMA_MAX )
{ {
for (int cd = 1; cd < PIXEL_COLOR_DEPTH_BITS; cd++) for (int cd = 1; cd < m_cfg.getPixelColorDepthBits(); cd++)
{ {
dma_bus.create_dma_desc_link(dma_buff.rowBits[row]->getDataPtr(cd, 0), dma_buff.rowBits[row]->size(num_dma_payload_colour_depths), false); dma_bus.create_dma_desc_link(dma_buff.rowBits[row]->getDataPtr(cd, 0), dma_buff.rowBits[row]->size(num_dma_payload_colour_depths), false);
@ -209,7 +213,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
} // row depth struct } // row depth struct
for(int i=lsbMsbTransitionBit + 1; i<PIXEL_COLOR_DEPTH_BITS; i++) for(int i=lsbMsbTransitionBit + 1; i < m_cfg.getPixelColorDepthBits(); i++)
{ {
// binary time division setup: we need 2 of bit (LSBMSB_TRANSITION_BIT + 1) four of (LSBMSB_TRANSITION_BIT + 2), etc // binary time division setup: we need 2 of bit (LSBMSB_TRANSITION_BIT + 1) four of (LSBMSB_TRANSITION_BIT + 2), etc
// because we sweep through to MSB each time, it divides the number of times we have to sweep in half (saving linked list RAM) // because we sweep through to MSB each time, it divides the number of times we have to sweep in half (saving linked list RAM)
@ -217,10 +221,10 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
for(int k=0; k < (1<<(i - lsbMsbTransitionBit - 1)); k++) for(int k=0; k < (1<<(i - lsbMsbTransitionBit - 1)); k++)
{ {
dma_bus.create_dma_desc_link(dma_buff.rowBits[row]->getDataPtr(i, 0), dma_buff.rowBits[row]->size(PIXEL_COLOR_DEPTH_BITS - i), false); dma_bus.create_dma_desc_link(dma_buff.rowBits[row]->getDataPtr(i, 0), dma_buff.rowBits[row]->size(m_cfg.getPixelColorDepthBits() - i), false);
if (m_cfg.double_buff) { if (m_cfg.double_buff) {
dma_bus.create_dma_desc_link(dma_buff.rowBits[row]->getDataPtr(i, 1), dma_buff.rowBits[row]->size(PIXEL_COLOR_DEPTH_BITS - i), true ); dma_bus.create_dma_desc_link(dma_buff.rowBits[row]->getDataPtr(i, 1), dma_buff.rowBits[row]->size(m_cfg.getPixelColorDepthBits() - i), true );
} }
current_dmadescriptor_offset++; current_dmadescriptor_offset++;
@ -237,7 +241,7 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
// //
auto bus_cfg = dma_bus.config(); // バス設定用の構造体を取得します。 auto bus_cfg = dma_bus.config(); // バス設定用の構造体を取得します。
bus_cfg.bus_freq = _cfg.i2sspeed; bus_cfg.bus_freq = m_cfg.i2sspeed;
bus_cfg.pin_wr = m_cfg.gpio.clk; // WR を接続しているピン番号 bus_cfg.pin_wr = m_cfg.gpio.clk; // WR を接続しているピン番号
bus_cfg.pin_d0 = m_cfg.gpio.r1; bus_cfg.pin_d0 = m_cfg.gpio.r1;
@ -352,7 +356,7 @@ uint16_t red16, green16, blue16;
} }
// Iterating through colour depth bits, which we assume are 8 bits per RGB subpixel (24bpp) // Iterating through colour depth bits, which we assume are 8 bits per RGB subpixel (24bpp)
uint8_t colour_depth_idx = PIXEL_COLOR_DEPTH_BITS; uint8_t colour_depth_idx = m_cfg.getPixelColorDepthBits();
do { do {
--colour_depth_idx; --colour_depth_idx;
/* /*
@ -363,7 +367,7 @@ uint16_t red16, green16, blue16;
uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit color (8 bits per RGB subpixel) uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit color (8 bits per RGB subpixel)
#endif #endif
*/ */
uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx); uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx, m_cfg.getMaskOffset());
uint16_t RGB_output_bits = 0; uint16_t RGB_output_bits = 0;
/* Per the .h file, the order of the output RGB bits is: /* Per the .h file, the order of the output RGB bits is:
@ -410,7 +414,7 @@ uint16_t red16, green16, blue16;
blue16 = blue << 8; blue16 = blue << 8;
#endif #endif
for(uint8_t colour_depth_idx=0; colour_depth_idx<PIXEL_COLOR_DEPTH_BITS; colour_depth_idx++) // colour depth - 8 iterations for(uint8_t colour_depth_idx=0; colour_depth_idx < m_cfg.getPixelColorDepthBits(); colour_depth_idx++) // colour depth - 8 iterations
{ {
// let's precalculate RGB1 and RGB2 bits than flood it over the entire DMA buffer // let's precalculate RGB1 and RGB2 bits than flood it over the entire DMA buffer
uint16_t RGB_output_bits = 0; uint16_t RGB_output_bits = 0;
@ -421,7 +425,7 @@ uint16_t red16, green16, blue16;
// uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit colour (8 bits per RGB subpixel) // uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit colour (8 bits per RGB subpixel)
// #endif // #endif
uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx); uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx, m_cfg.getMaskOffset());
/* Per the .h file, the order of the output RGB bits is: /* Per the .h file, the order of the output RGB bits is:
* BIT_B2, BIT_G2, BIT_R2, BIT_B1, BIT_G1, BIT_R1 */ * BIT_B2, BIT_G2, BIT_R2, BIT_B1, BIT_G1, BIT_R1 */
@ -864,7 +868,7 @@ uint16_t red16, green16, blue16;
} }
// Iterating through colour depth bits (8 iterations) // Iterating through colour depth bits (8 iterations)
uint8_t colour_depth_idx = PIXEL_COLOR_DEPTH_BITS; uint8_t colour_depth_idx = m_cfg.getPixelColorDepthBits();
do { do {
--colour_depth_idx; --colour_depth_idx;
@ -876,7 +880,7 @@ uint16_t red16, green16, blue16;
// #else // #else
// uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit colour (8 bits per RGB subpixel) // uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit colour (8 bits per RGB subpixel)
// #endif // #endif
uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx); uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx, m_cfg.getMaskOffset());
/* Per the .h file, the order of the output RGB bits is: /* Per the .h file, the order of the output RGB bits is:
* BIT_B2, BIT_G2, BIT_R2, BIT_B1, BIT_G1, BIT_R1 */ * BIT_B2, BIT_G2, BIT_R2, BIT_B1, BIT_G1, BIT_R1 */
@ -957,7 +961,7 @@ uint16_t red16, green16, blue16;
*/ */
x_coord = ESP32_TX_FIFO_POSITION_ADJUST(x_coord); x_coord = ESP32_TX_FIFO_POSITION_ADJUST(x_coord);
uint8_t colour_depth_idx = PIXEL_COLOR_DEPTH_BITS; uint8_t colour_depth_idx = m_cfg.getPixelColorDepthBits();
do { // Iterating through colour depth bits (8 iterations) do { // Iterating through colour depth bits (8 iterations)
--colour_depth_idx; --colour_depth_idx;
@ -969,7 +973,7 @@ uint16_t red16, green16, blue16;
// uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit colour (8 bits per RGB subpixel) // uint8_t mask = (1 << (colour_depth_idx)); // expect 24 bit colour (8 bits per RGB subpixel)
// #endif // #endif
uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx); uint16_t mask = PIXEL_COLOR_MASK_BIT(colour_depth_idx, m_cfg.getMaskOffset());
uint16_t RGB_output_bits = 0; uint16_t RGB_output_bits = 0;
/* Per the .h file, the order of the output RGB bits is: /* Per the .h file, the order of the output RGB bits is:

View file

@ -71,10 +71,14 @@
#define PIXEL_COLOR_DEPTH_BITS PIXEL_COLOUR_DEPTH_BITS #define PIXEL_COLOR_DEPTH_BITS PIXEL_COLOUR_DEPTH_BITS
#endif #endif
#ifndef PIXEL_COLOR_DEPTH_BITS //support backwarts compatibility
#define PIXEL_COLOR_DEPTH_BITS 8 #ifdef PIXEL_COLOR_DEPTH_BITS
#define PIXEL_COLOR_DEPTH_BITS_DEFAULT PIXEL_COLOR_DEPTH_BITS
#else
#define PIXEL_COLOR_DEPTH_BITS_DEFAULT 8
#endif #endif
#define PIXEL_COLOR_DEPTH_BITS_MAX 12
/***************************************************************************************/ /***************************************************************************************/
/* Definitions below should NOT be ever changed without rewriting library logic */ /* Definitions below should NOT be ever changed without rewriting library logic */
@ -290,7 +294,8 @@ struct HUB75_I2S_CFG {
clk_speed _i2sspeed = HZ_15M, clk_speed _i2sspeed = HZ_15M,
uint8_t _latblk = DEFAULT_LAT_BLANKING, // Anything > 1 seems to cause artefacts on ICS panels uint8_t _latblk = DEFAULT_LAT_BLANKING, // Anything > 1 seems to cause artefacts on ICS panels
bool _clockphase = true, bool _clockphase = true,
uint16_t _min_refresh_rate = 60 uint16_t _min_refresh_rate = 60,
uint8_t _pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_DEFAULT
) : mx_width(_w), ) : mx_width(_w),
mx_height(_h), mx_height(_h),
chain_length(_chain), chain_length(_chain),
@ -300,7 +305,40 @@ struct HUB75_I2S_CFG {
double_buff(_dbuff), double_buff(_dbuff),
latch_blanking(_latblk), latch_blanking(_latblk),
clkphase(_clockphase), clkphase(_clockphase),
min_refresh_rate (_min_refresh_rate) {} min_refresh_rate(_min_refresh_rate)
{
setPixelColorDepthBits(_pixel_color_depth_bits);
}
//pixel_color_depth_bits must be between 12 and 2, and mask_offset needs to be calculated accordently
//so they have to be private with getter (and setter)
void setPixelColorDepthBits(uint8_t _pixel_color_depth_bits){
if(_pixel_color_depth_bits > PIXEL_COLOR_DEPTH_BITS_MAX || _pixel_color_depth_bits < 2){
if(_pixel_color_depth_bits > PIXEL_COLOR_DEPTH_BITS_MAX){
pixel_color_depth_bits = PIXEL_COLOR_DEPTH_BITS_MAX;
}else{
pixel_color_depth_bits = 2;
}
ESP_LOGW("HUB75_I2S_CFG", "Invalid pixel_color_depth_bits (%d): 2 <= pixel_color_depth_bits <= %d, choosing nearest valid %d", _pixel_color_depth_bits, PIXEL_COLOR_DEPTH_BITS_MAX, pixel_color_depth_bits);
}else{
pixel_color_depth_bits = _pixel_color_depth_bits;
}
mask_offset = 16 - pixel_color_depth_bits;
}
uint8_t getPixelColorDepthBits(){
return pixel_color_depth_bits;
}
uint8_t getMaskOffset(){
return mask_offset;
}
private:
//these were priviously handeld as defines (PIXEL_COLOR_DEPTH_BITS, MASK_OFFSET)
//to make it changable after compilation, it is now part of the config
uint8_t pixel_color_depth_bits;
uint8_t mask_offset;
}; // end of structure HUB75_I2S_CFG }; // end of structure HUB75_I2S_CFG