Fix hidden TX FIFO ordering bugs
On ESP32 original only. Turn byte ordering logic into a compiler macro.
This commit is contained in:
parent
1d29c7b520
commit
69686a3747
2 changed files with 44 additions and 16 deletions
|
@ -8,6 +8,16 @@ static const char* TAG = "MatrixPanel";
|
||||||
*/
|
*/
|
||||||
#define getRowDataPtr(row, _dpth, buff_id) &(dma_buff.rowBits[row]->data[_dpth * dma_buff.rowBits[row]->width + buff_id*(dma_buff.rowBits[row]->width * dma_buff.rowBits[row]->colour_depth)])
|
#define getRowDataPtr(row, _dpth, buff_id) &(dma_buff.rowBits[row]->data[_dpth * dma_buff.rowBits[row]->width + buff_id*(dma_buff.rowBits[row]->width * dma_buff.rowBits[row]->colour_depth)])
|
||||||
|
|
||||||
|
// We need to update the correct uint16_t in the rowBitStruct array, that gets sent out in parallel
|
||||||
|
// 16 bit parallel mode - Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
|
||||||
|
// Irrelevant for ESP32-S2 the way the FIFO ordering works is different - refer to page 679 of S2 technical reference manual
|
||||||
|
#if defined (ESP32_THE_ORIG)
|
||||||
|
#define ESP32_TX_FIFO_POSITION_ADJUST(x_coord) (x_coord & 1U ? (x_coord-1):(x_coord+1))
|
||||||
|
#else
|
||||||
|
#define ESP32_TX_FIFO_POSITION_ADJUST(x_coord) x_coord
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool MatrixPanel_I2S_DMA::allocateDMAmemory()
|
bool MatrixPanel_I2S_DMA::allocateDMAmemory()
|
||||||
{
|
{
|
||||||
|
@ -240,15 +250,17 @@ void MatrixPanel_I2S_DMA::configureDMA(const HUB75_I2S_CFG& _cfg)
|
||||||
* Let's put it into IRAM to avoid situations when it could be flushed out of instruction cache
|
* Let's put it into IRAM to avoid situations when it could be flushed out of instruction cache
|
||||||
* and had to be read from spi-flash over and over again.
|
* and had to be read from spi-flash over and over again.
|
||||||
* Yes, it is always a tradeoff between memory/speed/size, but compared to DMA-buffer size is not a big deal
|
* Yes, it is always a tradeoff between memory/speed/size, but compared to DMA-buffer size is not a big deal
|
||||||
|
*
|
||||||
|
* Note: Cannot pass a negative co-ord as it makes no sense in the DMA bit array lookup.
|
||||||
*/
|
*/
|
||||||
void IRAM_ATTR MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t y_coord, uint8_t red, uint8_t green, uint8_t blue)
|
void IRAM_ATTR MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint16_t x_coord, uint16_t y_coord, uint8_t red, uint8_t green, uint8_t blue)
|
||||||
{
|
{
|
||||||
if ( !initialized ) return;
|
if ( !initialized ) return;
|
||||||
|
|
||||||
/* 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)
|
||||||
*/
|
*/
|
||||||
if ( x_coord < 0 || y_coord < 0 || x_coord >= PIXELS_PER_ROW || y_coord >= m_cfg.mx_height) {
|
if ( x_coord >= PIXELS_PER_ROW || y_coord >= m_cfg.mx_height) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,13 +286,15 @@ void IRAM_ATTR MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16
|
||||||
* so we have to check for this and check the correct position of the MATRIX_DATA_STORAGE_TYPE
|
* so we have to check for this and check the correct position of the MATRIX_DATA_STORAGE_TYPE
|
||||||
* data.
|
* data.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
#if defined (ESP32_THE_ORIG)
|
#if defined (ESP32_THE_ORIG)
|
||||||
// We need to update the correct uint16_t in the rowBitStruct array, that gets sent out in parallel
|
// We need to update the correct uint16_t in the rowBitStruct array, that gets sent out in parallel
|
||||||
// 16 bit parallel mode - Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
|
// 16 bit parallel mode - Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
|
||||||
// Irrelevant for ESP32-S2 the way the FIFO ordering works is different - refer to page 679 of S2 technical reference manual
|
// Irrelevant for ESP32-S2 the way the FIFO ordering works is different - refer to page 679 of S2 technical reference manual
|
||||||
x_coord & 1U ? --x_coord : ++x_coord;
|
x_coord & 1U ? --x_coord : ++x_coord;
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
|
x_coord = ESP32_TX_FIFO_POSITION_ADJUST(x_coord);
|
||||||
|
|
||||||
|
|
||||||
uint16_t _colourbitclear = BITMASK_RGB1_CLEAR, _colourbitoffset = 0;
|
uint16_t _colourbitclear = BITMASK_RGB1_CLEAR, _colourbitoffset = 0;
|
||||||
|
@ -417,7 +431,7 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
// https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164
|
// https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164
|
||||||
row[x_pixel] = abcde & (0x18 << BITS_ADDR_OFFSET); // mask out the bottom 3 bits which are the clk di bk inputs
|
row[x_pixel] = abcde & (0x18 << BITS_ADDR_OFFSET); // mask out the bottom 3 bits which are the clk di bk inputs
|
||||||
} else {
|
} else {
|
||||||
row[x_pixel] = abcde;
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = abcde;
|
||||||
}
|
}
|
||||||
// ESP_LOGI(TAG, "x pixel 1: %d", x_pixel);
|
// ESP_LOGI(TAG, "x pixel 1: %d", x_pixel);
|
||||||
} while(x_pixel!=dma_buff.rowBits[row_idx]->width && x_pixel);
|
} while(x_pixel!=dma_buff.rowBits[row_idx]->width && x_pixel);
|
||||||
|
@ -433,7 +447,7 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
// https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164
|
// https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/164
|
||||||
row[x_pixel] = abcde & (0x18 << BITS_ADDR_OFFSET); // mask out the bottom 3 bits which are the clk di bk inputs
|
row[x_pixel] = abcde & (0x18 << BITS_ADDR_OFFSET); // mask out the bottom 3 bits which are the clk di bk inputs
|
||||||
} else {
|
} else {
|
||||||
row[x_pixel] = abcde;
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = abcde;
|
||||||
}
|
}
|
||||||
//row[x_pixel] = abcde;
|
//row[x_pixel] = abcde;
|
||||||
// ESP_LOGI(TAG, "x pixel 2: %d", x_pixel);
|
// ESP_LOGI(TAG, "x pixel 2: %d", x_pixel);
|
||||||
|
@ -465,6 +479,7 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
// switch pointer to a row for a specific color index
|
// switch pointer to a row for a specific color index
|
||||||
row = dma_buff.rowBits[row_idx]->getDataPtr(colouridx, _buff_id);
|
row = dma_buff.rowBits[row_idx]->getDataPtr(colouridx, _buff_id);
|
||||||
|
|
||||||
|
/*
|
||||||
#if defined(ESP32_THE_ORIG)
|
#if defined(ESP32_THE_ORIG)
|
||||||
// We need to update the correct uint16_t in the rowBitStruct array, that gets sent out in parallel
|
// We need to update the correct uint16_t in the rowBitStruct array, that gets sent out in parallel
|
||||||
// 16 bit parallel mode - Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
|
// 16 bit parallel mode - Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
|
||||||
|
@ -474,13 +489,17 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
// -1 works better on ESP32-S2 ? Because bytes get sent out in order...
|
// -1 works better on ESP32-S2 ? Because bytes get sent out in order...
|
||||||
row[dma_buff.rowBits[row_idx]->width - 1] |= BIT_LAT; // -1 pixel to compensate array index starting at 0
|
row[dma_buff.rowBits[row_idx]->width - 1] |= BIT_LAT; // -1 pixel to compensate array index starting at 0
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(dma_buff.rowBits[row_idx]->width - 1)] |= BIT_LAT; // -1 pixel to compensate array index starting at 0
|
||||||
|
|
||||||
|
//ESP32_TX_FIFO_POSITION_ADJUST(dma_buff.rowBits[row_idx]->width - 1)
|
||||||
|
|
||||||
// need to disable OE before/after latch to hide row transition
|
// need to disable OE before/after latch to hide row transition
|
||||||
// Should be one clock or more before latch, otherwise can get ghosting
|
// Should be one clock or more before latch, otherwise can get ghosting
|
||||||
uint8_t _blank = m_cfg.latch_blanking;
|
uint8_t _blank = m_cfg.latch_blanking;
|
||||||
do {
|
do {
|
||||||
--_blank;
|
--_blank;
|
||||||
|
/*
|
||||||
#if defined(ESP32_THE_ORIG)
|
#if defined(ESP32_THE_ORIG)
|
||||||
// Original ESP32 WROOM FIFO Ordering Sucks
|
// Original ESP32 WROOM FIFO Ordering Sucks
|
||||||
uint8_t _blank_row_tx_fifo_tmp = 0 + _blank;
|
uint8_t _blank_row_tx_fifo_tmp = 0 + _blank;
|
||||||
|
@ -494,6 +513,11 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id){
|
||||||
row[0 + _blank] |= BIT_OE;
|
row[0 + _blank] |= BIT_OE;
|
||||||
row[dma_buff.rowBits[row_idx]->width - _blank - 1 ] |= BIT_OE; // (LAT pulse is (width-2) -1 pixel to compensate array index starting at 0
|
row[dma_buff.rowBits[row_idx]->width - _blank - 1 ] |= BIT_OE; // (LAT pulse is (width-2) -1 pixel to compensate array index starting at 0
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(0 + _blank)] |= BIT_OE;
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(dma_buff.rowBits[row_idx]->width - _blank - 1)] |= BIT_OE; // (LAT pulse is (width-2) -1 pixel to compensate array index starting at 0
|
||||||
|
|
||||||
|
|
||||||
} while (_blank);
|
} while (_blank);
|
||||||
|
|
||||||
|
@ -535,11 +559,11 @@ void MatrixPanel_I2S_DMA::brtCtrlOE(int brt, const bool _buff_id){
|
||||||
--x_coord;
|
--x_coord;
|
||||||
|
|
||||||
// clear OE bit for all other pixels
|
// clear OE bit for all other pixels
|
||||||
row[x_coord] &= BITMASK_OE_CLEAR;
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_coord)] &= BITMASK_OE_CLEAR;
|
||||||
|
|
||||||
// Brightness control via OE toggle - disable matrix output at specified x_coord
|
// Brightness control via OE toggle - disable matrix output at specified x_coord
|
||||||
if((colouridx > lsbMsbTransitionBit || !colouridx) && ((x_coord) >= brt)){
|
if((colouridx > lsbMsbTransitionBit || !colouridx) && ((x_coord) >= brt)){
|
||||||
row[x_coord] |= BIT_OE; // Disable output after this point.
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_coord)] |= BIT_OE; // Disable output after this point.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// special case for the bits *after* LSB through (lsbMsbTransitionBit) - OE is output after data is shifted, so need to set OE to fractional brightness
|
// special case for the bits *after* LSB through (lsbMsbTransitionBit) - OE is output after data is shifted, so need to set OE to fractional brightness
|
||||||
|
@ -547,7 +571,7 @@ void MatrixPanel_I2S_DMA::brtCtrlOE(int brt, const bool _buff_id){
|
||||||
// divide brightness in half for each bit below lsbMsbTransitionBit
|
// divide brightness in half for each bit below lsbMsbTransitionBit
|
||||||
int lsbBrightness = brt >> (lsbMsbTransitionBit - colouridx + 1);
|
int lsbBrightness = brt >> (lsbMsbTransitionBit - colouridx + 1);
|
||||||
if((x_coord) >= lsbBrightness) {
|
if((x_coord) >= lsbBrightness) {
|
||||||
row[x_coord] |= BIT_OE; // Disable output after this point.
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_coord)] |= BIT_OE; // Disable output after this point.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -560,7 +584,7 @@ void MatrixPanel_I2S_DMA::brtCtrlOE(int brt, const bool _buff_id){
|
||||||
uint8_t _blank = m_cfg.latch_blanking;
|
uint8_t _blank = m_cfg.latch_blanking;
|
||||||
do {
|
do {
|
||||||
--_blank;
|
--_blank;
|
||||||
|
/*
|
||||||
#if defined(ESP32_THE_ORIG)
|
#if defined(ESP32_THE_ORIG)
|
||||||
// Original ESP32 WROOM FIFO Ordering Sucks
|
// Original ESP32 WROOM FIFO Ordering Sucks
|
||||||
uint8_t _blank_row_tx_fifo_tmp = 0 + _blank;
|
uint8_t _blank_row_tx_fifo_tmp = 0 + _blank;
|
||||||
|
@ -569,6 +593,10 @@ void MatrixPanel_I2S_DMA::brtCtrlOE(int brt, const bool _buff_id){
|
||||||
#else
|
#else
|
||||||
row[0 + _blank] |= BIT_OE;
|
row[0 + _blank] |= BIT_OE;
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(0 + _blank)] |= BIT_OE;
|
||||||
|
|
||||||
|
|
||||||
//row[0 + _blank] |= BIT_OE;
|
//row[0 + _blank] |= BIT_OE;
|
||||||
// no need, has been done already
|
// no need, has been done already
|
||||||
|
|
|
@ -113,8 +113,8 @@
|
||||||
#define BITMASK_CTRL_CLEAR (0b1110000000111111) // inverted bitmask for control bits ABCDE,LAT,OE in pixel vector
|
#define BITMASK_CTRL_CLEAR (0b1110000000111111) // inverted bitmask for control bits ABCDE,LAT,OE in pixel vector
|
||||||
#define BITMASK_OE_CLEAR (0b1111111101111111) // inverted bitmask for control bit OE in pixel vector
|
#define BITMASK_OE_CLEAR (0b1111111101111111) // inverted bitmask for control bit OE in pixel vector
|
||||||
|
|
||||||
// How many clock cycles to blank OE before/after LAT signal change, default is 1 clock
|
// How many clock cycles to blank OE before/after LAT signal change, default is 2 clocks
|
||||||
#define DEFAULT_LAT_BLANKING 1
|
#define DEFAULT_LAT_BLANKING 2
|
||||||
|
|
||||||
// Max clock cycles to blank OE before/after LAT signal change
|
// Max clock cycles to blank OE before/after LAT signal change
|
||||||
#define MAX_LAT_BLANKING 4
|
#define MAX_LAT_BLANKING 4
|
||||||
|
@ -280,7 +280,7 @@ struct HUB75_I2S_CFG {
|
||||||
shift_driver _drv = SHIFTREG,
|
shift_driver _drv = SHIFTREG,
|
||||||
bool _dbuff = false,
|
bool _dbuff = false,
|
||||||
clk_speed _i2sspeed = HZ_10M,
|
clk_speed _i2sspeed = HZ_10M,
|
||||||
uint8_t _latblk = 1, // 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,
|
||||||
uint8_t _min_refresh_rate = 85
|
uint8_t _min_refresh_rate = 85
|
||||||
) : mx_width(_w),
|
) : mx_width(_w),
|
||||||
|
@ -406,7 +406,7 @@ class MatrixPanel_I2S_DMA {
|
||||||
/**
|
/**
|
||||||
* A wrapper to fill whatever selected DMA buffer / screen with black
|
* A wrapper to fill whatever selected DMA buffer / screen with black
|
||||||
*/
|
*/
|
||||||
inline void clearScreen(){ updateMatrixDMABuffer(0,0,0); };
|
inline void clearScreen(){ clearFrameBuffer(back_buffer_id); /*updateMatrixDMABuffer(0,0,0);*/ };
|
||||||
|
|
||||||
#ifndef NO_FAST_FUNCTIONS
|
#ifndef NO_FAST_FUNCTIONS
|
||||||
/**
|
/**
|
||||||
|
@ -582,7 +582,7 @@ class MatrixPanel_I2S_DMA {
|
||||||
void clearFrameBuffer(bool _buff_id = 0);
|
void clearFrameBuffer(bool _buff_id = 0);
|
||||||
|
|
||||||
/* Update a specific pixel in the DMA buffer to a colour */
|
/* Update a specific pixel in the DMA buffer to a colour */
|
||||||
void updateMatrixDMABuffer(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t blue);
|
void updateMatrixDMABuffer(uint16_t x, uint16_t y, uint8_t red, uint8_t green, uint8_t blue);
|
||||||
|
|
||||||
/* Update the entire DMA buffer (aka. The RGB Panel) a certain colour (wipe the screen basically) */
|
/* Update the entire DMA buffer (aka. The RGB Panel) a certain colour (wipe the screen basically) */
|
||||||
void updateMatrixDMABuffer(uint8_t red, uint8_t green, uint8_t blue);
|
void updateMatrixDMABuffer(uint8_t red, uint8_t green, uint8_t blue);
|
||||||
|
|
Loading…
Reference in a new issue