Merge pull request #474 from oseiler2/feature/DP3246_SM5368-support
Support for DP3246 / SM5368 based panels
This commit is contained in:
commit
e00a622ed1
4 changed files with 123 additions and 3 deletions
|
@ -82,7 +82,8 @@ Due to the high-speed optimized nature of this library, only specific panels are
|
||||||
* ICND2012
|
* ICND2012
|
||||||
* [RUC7258](http://www.ruichips.com/en/products.html?cateid=17496)
|
* [RUC7258](http://www.ruichips.com/en/products.html?cateid=17496)
|
||||||
* FM6126A AKA ICN2038S, [FM6124](https://datasheet4u.com/datasheet-pdf/FINEMADELECTRONICS/FM6124/pdf.php?id=1309677) (Refer to [PatternPlasma](/examples/2_PatternPlasma) example on how to use.)
|
* FM6126A AKA ICN2038S, [FM6124](https://datasheet4u.com/datasheet-pdf/FINEMADELECTRONICS/FM6124/pdf.php?id=1309677) (Refer to [PatternPlasma](/examples/2_PatternPlasma) example on how to use.)
|
||||||
* SM5266P
|
* SM5266P
|
||||||
|
* DP3246 with SM5368 row addressing registers
|
||||||
|
|
||||||
## Unsupported chips
|
## Unsupported chips
|
||||||
* [SM1620B](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/issues/416)
|
* [SM1620B](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/issues/416)
|
||||||
|
@ -95,7 +96,7 @@ Please use an [alternative library](https://github.com/2dom/PxMatrix) if you bou
|
||||||
# Getting Started
|
# Getting Started
|
||||||
## 1. Library Installation
|
## 1. Library Installation
|
||||||
|
|
||||||
* Dependancy: You will need to install Adafruit_GFX from the "Library > Manage Libraries" menu.
|
* Dependency: You will need to install Adafruit_GFX from the "Library > Manage Libraries" menu.
|
||||||
* Install this library from the Arduino Library manager.
|
* Install this library from the Arduino Library manager.
|
||||||
|
|
||||||
Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate. Or just add it into [platformio.ini](/doc/BuildOptions.md) [lib_deps](https://docs.platformio.org/en/latest/projectconf/section_env_library.html#lib-deps) section.
|
Library also tested to work fine with PlatformIO, install into your PlatformIO projects' lib/ folder as appropriate. Or just add it into [platformio.ini](/doc/BuildOptions.md) [lib_deps](https://docs.platformio.org/en/latest/projectconf/section_env_library.html#lib-deps) section.
|
||||||
|
|
|
@ -513,6 +513,10 @@ 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 if (m_cfg.driver == HUB75_I2S_CFG::DP3246_SM5368)
|
||||||
|
{
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = 0x0000;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = abcde;
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = abcde;
|
||||||
|
@ -533,6 +537,10 @@ 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 if (m_cfg.driver == HUB75_I2S_CFG::DP3246_SM5368)
|
||||||
|
{
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = 0x0000;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = abcde;
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = abcde;
|
||||||
|
@ -557,6 +565,15 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id)
|
||||||
} while (serialCount);
|
} while (serialCount);
|
||||||
} // end SM5266P
|
} // end SM5266P
|
||||||
|
|
||||||
|
// row selection for SM5368 shift regs with ABC-only addressing. A is row clk, B is BK and C is row data
|
||||||
|
if (m_cfg.driver == HUB75_I2S_CFG::DP3246_SM5368)
|
||||||
|
{
|
||||||
|
x_pixel = fb->rowBits[row_idx]->width - 1; // last pixel in first block)
|
||||||
|
uint16_t c = (row_idx == 0) ? BIT_C : 0x0000; // set row data (C) when row==0, then push through shift regs for all other rows
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel - 1)] |= c; // set row data
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel + 0)] |= c | BIT_A | BIT_B; // set row clk and bk, carry row data
|
||||||
|
} // end DP3246_SM5368
|
||||||
|
|
||||||
// let's set LAT/OE control bits for specific pixels in each colour_index subrows
|
// let's set LAT/OE control bits for specific pixels in each colour_index subrows
|
||||||
// Need to consider the original ESP32's (WROOM) DMA TX FIFO reordering of bytes...
|
// Need to consider the original ESP32's (WROOM) DMA TX FIFO reordering of bytes...
|
||||||
uint8_t colouridx = fb->rowBits[row_idx]->colour_depth;
|
uint8_t colouridx = fb->rowBits[row_idx]->colour_depth;
|
||||||
|
@ -567,6 +584,13 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id)
|
||||||
// switch pointer to a row for a specific colour index
|
// switch pointer to a row for a specific colour index
|
||||||
row = fb->rowBits[row_idx]->getDataPtr(colouridx, -1);
|
row = fb->rowBits[row_idx]->getDataPtr(colouridx, -1);
|
||||||
|
|
||||||
|
// DP3246 needs the latch high for 3 clock cycles, so start 2 cycles earlier
|
||||||
|
if (m_cfg.driver == HUB75_I2S_CFG::DP3246_SM5368)
|
||||||
|
{
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(fb->rowBits[row_idx]->width - 3)] |= BIT_LAT; // DP3246 needs 3 clock cycle latch
|
||||||
|
row[ESP32_TX_FIFO_POSITION_ADJUST(fb->rowBits[row_idx]->width - 2)] |= BIT_LAT; // DP3246 needs 3 clock cycle latch
|
||||||
|
} // DP3246_SM5368
|
||||||
|
|
||||||
row[ESP32_TX_FIFO_POSITION_ADJUST(fb->rowBits[row_idx]->width - 1)] |= BIT_LAT; // -1 pixel to compensate array index starting at 0
|
row[ESP32_TX_FIFO_POSITION_ADJUST(fb->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)
|
// ESP32_TX_FIFO_POSITION_ADJUST(dma_buff.rowBits[row_idx]->width - 1)
|
||||||
|
|
|
@ -243,7 +243,8 @@ struct HUB75_I2S_CFG
|
||||||
FM6126A,
|
FM6126A,
|
||||||
ICN2038S,
|
ICN2038S,
|
||||||
MBI5124,
|
MBI5124,
|
||||||
SM5266P
|
SM5266P,
|
||||||
|
DP3246_SM5368
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -768,6 +769,11 @@ private:
|
||||||
*/
|
*/
|
||||||
void fm6124init(const HUB75_I2S_CFG &_cfg);
|
void fm6124init(const HUB75_I2S_CFG &_cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief - DP3246-family chips initialization routine
|
||||||
|
*/
|
||||||
|
void dp3246init(const HUB75_I2S_CFG& _cfg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief - reset OE bits in DMA buffer in a way to control brightness
|
* @brief - reset OE bits in DMA buffer in a way to control brightness
|
||||||
* @param brt - brightness level from 0 to row_width
|
* @param brt - brightness level from 0 to row_width
|
||||||
|
|
|
@ -27,6 +27,9 @@ void MatrixPanel_I2S_DMA::shiftDriver(const HUB75_I2S_CFG& _cfg){
|
||||||
case HUB75_I2S_CFG::FM6126A:
|
case HUB75_I2S_CFG::FM6126A:
|
||||||
fm6124init(_cfg);
|
fm6124init(_cfg);
|
||||||
break;
|
break;
|
||||||
|
case HUB75_I2S_CFG::DP3246_SM5368:
|
||||||
|
dp3246init(_cfg);
|
||||||
|
break;
|
||||||
case HUB75_I2S_CFG::MBI5124:
|
case HUB75_I2S_CFG::MBI5124:
|
||||||
/* MBI5124 chips must be clocked with positive-edge, since it's LAT signal
|
/* MBI5124 chips must be clocked with positive-edge, since it's LAT signal
|
||||||
* resets on clock's rising edge while high
|
* resets on clock's rising edge while high
|
||||||
|
@ -97,4 +100,90 @@ void MatrixPanel_I2S_DMA::fm6124init(const HUB75_I2S_CFG& _cfg) {
|
||||||
gpio_set_level((gpio_num_t) _cfg.gpio.lat, LOW);
|
gpio_set_level((gpio_num_t) _cfg.gpio.lat, LOW);
|
||||||
gpio_set_level((gpio_num_t) _cfg.gpio.oe, LOW); // Enable Display
|
gpio_set_level((gpio_num_t) _cfg.gpio.oe, LOW); // Enable Display
|
||||||
CLK_PULSE
|
CLK_PULSE
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatrixPanel_I2S_DMA::dp3246init(const HUB75_I2S_CFG& _cfg) {
|
||||||
|
|
||||||
|
ESP_LOGI("LEDdrivers", "MatrixPanel_I2S_DMA - initializing DP3246 driver...");
|
||||||
|
|
||||||
|
// DP3246 needs positive clock edge
|
||||||
|
m_cfg.clkphase = true;
|
||||||
|
|
||||||
|
// 15:13 3 000 reserved
|
||||||
|
// 12:9 4 0000 OE widening (= OE_ADD * 6ns)
|
||||||
|
// 8 1 0 reserved
|
||||||
|
// 7:0 8 11111111 Iout = (Igain+1)/256 * 17.6 / Rext
|
||||||
|
bool REG1[16] = { 0,0,0, 0,0,0,0, 0, 1,1,1,1,1,1,1,1 }; // MSB first
|
||||||
|
|
||||||
|
// 15:11 5 11111 Blanking potential selection, step 77mV, 00000: VDD-0.8V
|
||||||
|
// 10:8 3 111 Constant current source output inflection point selection
|
||||||
|
// 7 1 0 Disable dead pixel removel, 1: Enable
|
||||||
|
// 6 1 0 0->1: (OPEN_DET rising edge) start detection, 0: reset to ready-to-detect state
|
||||||
|
// 5 1 0 0: Enable black screen power saving, 1: Turn off the black screen to save energy
|
||||||
|
// 4 1 0 0: Do not enable the fading function, 1: Enable the fade function
|
||||||
|
// 3 1 0 Reserved
|
||||||
|
// 2:0 3 000 000: single edge pass, others: double edge transfer
|
||||||
|
bool REG2[16] = { 1,1,1,1,1, 1,1,1, 0, 0, 0, 0, 0, 0,0,0 }; // MSB first
|
||||||
|
|
||||||
|
for (uint8_t _pin : {_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2, _cfg.gpio.clk, _cfg.gpio.lat, _cfg.gpio.oe}) {
|
||||||
|
gpio_reset_pin((gpio_num_t)_pin); // some pins are not in gpio mode after reset => https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html#gpio-summary
|
||||||
|
gpio_set_direction((gpio_num_t)_pin, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_level((gpio_num_t)_pin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.oe, HIGH); // disable Display
|
||||||
|
|
||||||
|
// clear registers - this seems to help with reliability
|
||||||
|
for (int l = 0; l < PIXELS_PER_ROW; ++l) {
|
||||||
|
if (l == PIXELS_PER_ROW - 3) { // DP3246 wants the latch dropped for 3 clk cycles
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, HIGH);
|
||||||
|
}
|
||||||
|
CLK_PULSE
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, LOW);
|
||||||
|
|
||||||
|
// Send Data to control register REG1
|
||||||
|
for (int l = 0; l < PIXELS_PER_ROW; l++) {
|
||||||
|
for (uint8_t _pin : {_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2})
|
||||||
|
gpio_set_level((gpio_num_t)_pin, REG1[l % 16]); // we have 16 bits shifters and write the same value all over the matrix array
|
||||||
|
|
||||||
|
if (l == PIXELS_PER_ROW - 11) { // pull the latch 11 clocks before the end of matrix so that REG1 starts counting to save the value
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, HIGH);
|
||||||
|
}
|
||||||
|
CLK_PULSE
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop the latch and save data to the REG1 all over the DP3246 chips
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, LOW);
|
||||||
|
|
||||||
|
// Send Data to control register REG2
|
||||||
|
for (int l = 0; l < PIXELS_PER_ROW; l++) {
|
||||||
|
for (uint8_t _pin : {_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2})
|
||||||
|
gpio_set_level((gpio_num_t)_pin, REG2[l % 16]); // we have 16 bits shifters and we write the same value all over the matrix array
|
||||||
|
|
||||||
|
if (l == PIXELS_PER_ROW - 12) { // pull the latch 12 clocks before the end of matrix so that REG2 starts counting to save the value
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, HIGH);
|
||||||
|
}
|
||||||
|
CLK_PULSE
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop the latch and save data to the REG2 all over the DP3246 chips
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, LOW);
|
||||||
|
CLK_PULSE
|
||||||
|
|
||||||
|
// blank data regs to keep matrix clear after manipulations
|
||||||
|
for (uint8_t _pin : {_cfg.gpio.r1, _cfg.gpio.r2, _cfg.gpio.g1, _cfg.gpio.g2, _cfg.gpio.b1, _cfg.gpio.b2})
|
||||||
|
gpio_set_level((gpio_num_t)_pin, LOW);
|
||||||
|
|
||||||
|
for (int l = 0; l < PIXELS_PER_ROW; ++l) {
|
||||||
|
if (l == PIXELS_PER_ROW - 3) { // DP3246 wants the latch dropped for 3 clk cycles
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, HIGH);
|
||||||
|
}
|
||||||
|
CLK_PULSE
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.lat, LOW);
|
||||||
|
gpio_set_level((gpio_num_t)_cfg.gpio.oe, LOW); // enable Display
|
||||||
|
CLK_PULSE
|
||||||
}
|
}
|
Loading…
Reference in a new issue