From 88a14afa1ce12de31cb29a80996bb66d3389de43 Mon Sep 17 00:00:00 2001 From: Oliver Seiler Date: Wed, 5 Jul 2023 10:32:22 +1200 Subject: [PATCH] Initial support for DP3246_SM5368 --- src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp | 24 +++++++ src/ESP32-HUB75-MatrixPanel-I2S-DMA.h | 8 ++- src/ESP32-HUB75-MatrixPanel-leddrivers.cpp | 75 ++++++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp index 35225e1..c2a725e 100644 --- a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp +++ b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp @@ -513,6 +513,10 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id) // 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 } + else if (m_cfg.driver == HUB75_I2S_CFG::DP3246_SM5368) + { + row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = 0x0000; + } else { 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 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 { row[ESP32_TX_FIFO_POSITION_ADJUST(x_pixel)] = abcde; @@ -557,6 +565,15 @@ void MatrixPanel_I2S_DMA::clearFrameBuffer(bool _buff_id) } while (serialCount); } // 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 // Need to consider the original ESP32's (WROOM) DMA TX FIFO reordering of bytes... 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 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 // ESP32_TX_FIFO_POSITION_ADJUST(dma_buff.rowBits[row_idx]->width - 1) diff --git a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h index 7332db6..978715b 100644 --- a/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h +++ b/src/ESP32-HUB75-MatrixPanel-I2S-DMA.h @@ -243,7 +243,8 @@ struct HUB75_I2S_CFG FM6126A, ICN2038S, MBI5124, - SM5266P + SM5266P, + DP3246_SM5368 }; /** @@ -768,6 +769,11 @@ private: */ 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 * @param brt - brightness level from 0 to row_width diff --git a/src/ESP32-HUB75-MatrixPanel-leddrivers.cpp b/src/ESP32-HUB75-MatrixPanel-leddrivers.cpp index 0bb20f7..d3a70eb 100644 --- a/src/ESP32-HUB75-MatrixPanel-leddrivers.cpp +++ b/src/ESP32-HUB75-MatrixPanel-leddrivers.cpp @@ -27,6 +27,9 @@ void MatrixPanel_I2S_DMA::shiftDriver(const HUB75_I2S_CFG& _cfg){ case HUB75_I2S_CFG::FM6126A: fm6124init(_cfg); break; + case HUB75_I2S_CFG::DP3246_SM5368: + dp3246init(_cfg); + break; case HUB75_I2S_CFG::MBI5124: /* MBI5124 chips must be clocked with positive-edge, since it's LAT signal * resets on clock's rising edge while high @@ -97,4 +100,76 @@ 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.oe, LOW); // Enable Display CLK_PULSE +} + +void MatrixPanel_I2S_DMA::dp3246init(const HUB75_I2S_CFG& _cfg) { + + ESP_LOGI("LEDdrivers", "MatrixPanel_I2S_DMA - initializing DP3246 driver..."); + + // 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_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 + + // 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 } \ No newline at end of file