From 834a90278beecc1496880b246366a4c378f11b00 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:02:32 +0200 Subject: [PATCH 1/6] add SEENGREAT_V2 pin-out (S3) https://seengreat.com/wiki/186 --- wled00/bus_manager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index af3f419c91..69f3095287 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -887,6 +887,12 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. // HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN}; mxconfig.gpio = {4, 5, 6, 7, 15, 16, 18, 8, 3, 42, 9, 40, 2, 41}; +#elif defined(SEENGREAT_V2_PINOUT) + DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA - S3 devKit-C with PSRAM, SEENGREAT_V2 pinout"); + mxconfig.gpio = { 18, 8, 17, // R1_PIN, G1_PIN, B1_PIN, + 16, 1, 15, // R2_PIN, G2_PIN, B2_PIN, + 7, 48, 6, 47, 2, // A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, + 21, 4, 5 }; //LAT_PIN, OE_PIN,CLK_PIN #else DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA - S3 with PSRAM"); // HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN}; From f1a99ce7419bbfd624f106658951bf8b0962b92d Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:04:15 +0200 Subject: [PATCH 2/6] allow HUB75 panel width up to 128px align with settings page that also allows up to 64x128 per panel --- wled00/bus_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 69f3095287..67b7c8ad20 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -835,11 +835,11 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. } if (bc.type == TYPE_HUB75MATRIX_HS) { - mxconfig.mx_width = min((uint8_t) 64, panelWidth); // TODO: UI limit is 128, this limits to 64 + mxconfig.mx_width = min((uint8_t) 128, panelWidth); // TODO: UI limit is 128, this limits to 64 mxconfig.mx_height = min((uint8_t) 64, panelHeight); } else if (bc.type == TYPE_HUB75MATRIX_QS) { _isVirtual = true; - mxconfig.mx_width = min((uint8_t) 64, panelWidth) * 2; + mxconfig.mx_width = min((uint8_t) 128, panelWidth) * 2; mxconfig.mx_height = min((uint8_t) 64, panelHeight) / 2; mxconfig.driver = HUB75_I2S_CFG::FM6124; // use FM6124 for "outdoor" 4-scan panels - workaround until we can make the driver user-configurable } else { From c530e13bdc705b726ec6f61a2c8abeabf9f10563 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:08:00 +0200 Subject: [PATCH 3/6] bugfixes: 4-scan HUB75 driver setup * prevent panels going flatter each time that cfg.json is saved * correct VirtualMatrixPanel setup: provide real panel dimensions * only set chainType when chain length > 1 * use a chaintype that does not flip the display upside-down --- wled00/bus_manager.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 67b7c8ad20..6e4dcf06b9 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -802,6 +802,7 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. _hasRgb = true; _hasWhite = false; virtualDisp = nullptr; // todo: this should be solved properly, can cause memory leak (if omitted here, nothing seems to work) + _isVirtual = false; // aliases for easier reading uint8_t panelWidth = bc.pins[0]; uint8_t panelHeight = bc.pins[1]; @@ -1017,15 +1018,15 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. // chained panels with cols and rows define need the virtual display driver, so do quarter-scan panels if (chainLength > 1 && (_rows > 1 || _cols > 1) || bc.type == TYPE_HUB75MATRIX_QS) { _isVirtual = true; - chainType = CHAIN_BOTTOM_LEFT_UP; // TODO: is there any need to support other chaining types? - DEBUGBUS_PRINTF_P(PSTR("Using virtual matrix: %ux%u panels of %ux%u pixels\n"), _cols, _rows, mxconfig.mx_width, mxconfig.mx_height); + if (chainLength > 1 && (_rows > 1 || _cols > 1)) chainType = CHAIN_TOP_RIGHT_DOWN; // we need to use a _DOWN chainType, otherwise the display is upside-down + DEBUGBUS_PRINTF_P(PSTR("Using virtual matrix: %ux%u panels of %ux%u pixels\n"), _cols, _rows, mxconfig.mx_width/2, mxconfig.mx_height*2); } else { _isVirtual = false; } if (_isVirtual) { - virtualDisp = new VirtualMatrixPanel((*display), _rows, _cols, mxconfig.mx_width, mxconfig.mx_height, chainType); + virtualDisp = new VirtualMatrixPanel((*display), _rows, _cols, mxconfig.mx_width/2, mxconfig.mx_height*2, chainType); virtualDisp->setRotation(0); if (bc.type == TYPE_HUB75MATRIX_QS) { switch(panelHeight) { @@ -1161,8 +1162,8 @@ std::vector BusHub75Matrix::getLEDTypes() { size_t BusHub75Matrix::getPins(uint8_t* pinArray) const { if (pinArray) { - pinArray[0] = mxconfig.mx_width; - pinArray[1] = mxconfig.mx_height; + pinArray[0] = _isVirtual ? mxconfig.mx_width /2 : mxconfig.mx_width; + pinArray[1] = _isVirtual ? mxconfig.mx_height *2 : mxconfig.mx_height; pinArray[2] = mxconfig.chain_length; pinArray[3] = _rows; pinArray[4] = _cols; From 1ee4c617f2f860f93b2624c1a72ba552af968d19 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:23:10 +0200 Subject: [PATCH 4/6] prevent 8-bit wrap-around on 128x64 4-scan panels change local variables to unsigned (=32bit) --- wled00/bus_manager.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 6e4dcf06b9..49b7443c98 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -804,9 +804,9 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. virtualDisp = nullptr; // todo: this should be solved properly, can cause memory leak (if omitted here, nothing seems to work) _isVirtual = false; // aliases for easier reading - uint8_t panelWidth = bc.pins[0]; - uint8_t panelHeight = bc.pins[1]; - uint8_t chainLength = bc.pins[2]; + unsigned panelWidth = bc.pins[0]; + unsigned panelHeight = bc.pins[1]; + unsigned chainLength = bc.pins[2]; _rows = bc.pins[3]; _cols = bc.pins[4]; @@ -823,7 +823,7 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. mxconfig.clkphase = bc.reversed; // allow chain length up to 4, limit to prevent bad data from preventing boot due to low memory - mxconfig.chain_length = max((uint8_t) 1, min(chainLength, (uint8_t) 4)); + mxconfig.chain_length = max(1U, min(chainLength, 4U)); if (mxconfig.mx_height >= 64 && (mxconfig.chain_length > 1)) { #if defined(BOARD_HAS_PSRAM) // limitation to one panel only applies to boards without PSRAM @@ -836,12 +836,12 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. } if (bc.type == TYPE_HUB75MATRIX_HS) { - mxconfig.mx_width = min((uint8_t) 128, panelWidth); // TODO: UI limit is 128, this limits to 64 - mxconfig.mx_height = min((uint8_t) 64, panelHeight); + mxconfig.mx_width = min(128U, panelWidth); // TODO: UI limit is 128, this limits to 64 + mxconfig.mx_height = min(64U, panelHeight); } else if (bc.type == TYPE_HUB75MATRIX_QS) { _isVirtual = true; - mxconfig.mx_width = min((uint8_t) 128, panelWidth) * 2; - mxconfig.mx_height = min((uint8_t) 64, panelHeight) / 2; + mxconfig.mx_width = min(128U, panelWidth) * 2; + mxconfig.mx_height = min(64U, panelHeight) / 2; mxconfig.driver = HUB75_I2S_CFG::FM6124; // use FM6124 for "outdoor" 4-scan panels - workaround until we can make the driver user-configurable } else { DEBUGBUS_PRINTLN("Unknown type"); From 22fead8f38d21725be47dbce15a586542c0f49f0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:45:24 +0200 Subject: [PATCH 5/6] comment correction --- wled00/bus_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 49b7443c98..b992ad2042 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -836,7 +836,7 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. } if (bc.type == TYPE_HUB75MATRIX_HS) { - mxconfig.mx_width = min(128U, panelWidth); // TODO: UI limit is 128, this limits to 64 + mxconfig.mx_width = min(128U, panelWidth); // UI limit is 128 mxconfig.mx_height = min(64U, panelHeight); } else if (bc.type == TYPE_HUB75MATRIX_QS) { _isVirtual = true; From 32412c9aa1b31f3105d9bc7936e2923b258ebf27 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:16:57 +0200 Subject: [PATCH 6/6] HUB75 tiny bugfix ensure that BusHub75Matrix::getPixelColor() returns RGBW format, not RGBA. Currently busses.getPixelColor() is not used by the WLED core. --- wled00/bus_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index b992ad2042..c676c89fc9 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -1097,7 +1097,7 @@ void IRAM_ATTR BusHub75Matrix::setPixelColor(unsigned pix, uint32_t c) { uint32_t BusHub75Matrix::getPixelColor(unsigned pix) const { if (!_valid) return IS_BLACK; // note: no need to check pix >= _len as that is checked in containsPixel() if (_ledBuffer) - return uint32_t(_ledBuffer[pix]); + return uint32_t(_ledBuffer[pix]) & 0x00FFFFFF; // FastLED 32bit is RGBA, we need RGBW else return getBitFromArray(_ledsDirty, pix) ? IS_DARKGREY: IS_BLACK; // just a hack - we only know if the pixel is black or not }