Skip to content

Conversation

@DedeHai
Copy link
Collaborator

@DedeHai DedeHai commented Oct 26, 2025

  • added proper config parameters to allow multiple panels
  • added config checks
  • fixed crashes on S3
  • changed constant variables to constexpr
  • added "wled.h" to bus_manager.cpp and removed local function prototypes (needed for buffer allocations)
  • speed optimisations: yields about 10% higher FPS
  • proper brightness handling
  • updated platformio_override.sample.ini
  • some code cleanup

I do not own any quarter-scan HUB75 panels nor a suitable ESP32, so please test if this is working, I tested this on 2x half-scan 64x32 panels using an S3 only.

Summary by CodeRabbit

  • Bug Fixes

    • Improved HUB75 matrix display handling and pixel color accuracy.
    • Enhanced memory management for large display configurations.
  • New Features

    • Added validation for HUB75 panel configuration to prevent invalid setups.
    • Expanded HUB75 configuration UI with improved row/column tracking.
  • Documentation

    • Added brightness guidance notes for HUB75 displays to prevent ghosting artifacts.

- added proper config parameters to allow multiple panels
- added config checks
- fixed crashes on S3
- changed constant variables to constexpr
- added "wled.h" to bus_manager.cpp and removed local function prototypes (needed for buffer allocations)
- speed optimisations: yields about 10% higher FPS
- proper brightness handling
- updated platformio_override.sample.ini
- some code cleanup
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Walkthrough

This pull request refactors the HUB75 matrix display handling with memory management improvements, bitwise operation optimizations, and virtual display support in the bus manager. API signature changes update pin counts, configuration validation is added to the HUB75 UI settings, and documentation adjustments are made to platformio configuration and color processing.

Changes

Cohort / File(s) Summary
Configuration & Documentation
platformio_override.sample.ini
Minor documentation and formatting adjustments to Hub75 environment blocks; added notes about maximum brightness, board file placement, and environment-specific URLs.
Core Bus Manager Implementation
wled00/bus_manager.cpp
Significant refactoring: replaced integer division/modulo with bitwise operations; introduced memory allocation wrappers (d_malloc/d_free); added virtual/physical HUB75 display handling with virtualDisp member, panel geometry aliases, and per-pixel dirty-bit tracking; updated setPixelColor/getPixelColor for virtual display paths; added IRAM_ATTR to setPixelColor; expanded getPins to return 5 values; reworked show() for virtual display height handling.
Core Bus Manager Headers
wled00/bus_manager.h
Updated getNumberOfPins() public static method: Hub75-type branch now returns 5 pins instead of 3; other bus types unchanged.
Color Processing
wled00/colors.cpp
Minor update to color_fade: replaced literal 0 comparison with named BLACK constant for edge case handling.
UI Settings & Validation
wled00/data/settings_leds.htm
Added HUB75 configuration validation (panel count, height restrictions); updated UI labels for panel size and row/column counts; increased HUB75-specific pin contribution from 2 to 4; extended conflict/availability logic to prevent multiple HUB75 buses and enforce defaults.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • bus_manager.cpp virtual display logic: Initialization, rendering, and memory management of VirtualMatrixPanel require careful validation of rotation settings, brightness application, and display height calculations.
  • Memory allocation patterns: Transition to d_malloc/d_free wrappers and cleanup paths—verify all allocation/deallocation pairs are correctly matched and handle edge cases.
  • getPins signature change: Return value changed from 3 to 5 for Hub75; verify all callers properly handle the expanded array and new return semantics.
  • Bitwise optimization accuracy: Integer division/modulo replacements (>> 3 for /8, & 0x07 for %8) should be audited for correctness across different input ranges.
  • HUB75 UI validation logic: Configuration constraints and defaults in settings_leds.htm need verification against actual panel layout and device memory limits.

Possibly related PRs

Suggested reviewers

  • netmindz
  • softhack007
  • willmmiles

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Improvements & fixes for HUB75" is fully related to the changeset, which encompasses multiple HUB75-related enhancements across configuration, performance, crash fixes, UI updates, and general code cleanup. The title correctly identifies HUB75 as the primary focus and accurately conveys that the PR contains both improvements and bug fixes. While the title could be more specific about particular changes (such as multi-panel support or ESP32-S3 crash fixes), it is sufficiently clear and specific enough that a teammate scanning the history would immediately understand this is a comprehensive HUB75 enhancement effort.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
wled00/colors.cpp (1)

66-66: Consider using BLACK constant consistently.

For consistency, the return statement should also use BLACK instead of the literal 0:

-  if (c1 == BLACK || amount == 0) return 0; // black or full fade
+  if (c1 == BLACK || amount == 0) return BLACK; // black or full fade
wled00/data/settings_leds.htm (1)

115-128: Address TODO: conditional reboot warning.

The reboot warning currently shows for all S3 HUB75 form submissions. The TODO comment suggests checking if config actually changed before warning.

Consider tracking the initial HUB75 configuration and only showing the reboot alert when values actually change:

// At page load, store initial config
let initialHub75Config = {};

// In trySubmit, compare and warn only if changed
if(isS3() && configChanged(n, initialHub75Config)) {
  alert("HUB75 changes require a reboot");
}

This improves UX by avoiding unnecessary reboot warnings when users haven't modified HUB75 settings.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b60313e and 5552c05.

📒 Files selected for processing (5)
  • platformio_override.sample.ini (3 hunks)
  • wled00/bus_manager.cpp (11 hunks)
  • wled00/bus_manager.h (2 hunks)
  • wled00/colors.cpp (1 hunks)
  • wled00/data/settings_leds.htm (5 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
wled00/**/*.cpp

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use 2-space indentation for C++ source files (.cpp)

Files:

  • wled00/colors.cpp
  • wled00/bus_manager.cpp
wled00/data/**/*.{htm,html,css,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use tabs for indentation in web files (.htm/.html/.css/.js) under wled00/data

Files:

  • wled00/data/settings_leds.htm
wled00/data/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

wled00/data/**: When modifying web UI files, run npm run build to regenerate embedded headers before any firmware build
For web UI changes, edit files only under wled00/data (not firmware or generated files)

Files:

  • wled00/data/settings_leds.htm
wled00/data/settings*.htm

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Name settings pages as settings*.htm within the web UI

Files:

  • wled00/data/settings_leds.htm
wled00/**/!(html_*)*.h

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use 2-space indentation for non-generated C++ header files (.h)

Files:

  • wled00/bus_manager.h
🧠 Learnings (2)
📚 Learning: 2025-09-13T13:13:35.817Z
Learnt from: netmindz
PR: wled/WLED#3777
File: wled00/bus_manager.cpp:941-947
Timestamp: 2025-09-13T13:13:35.817Z
Learning: For HUB75 matrix panels in WLED, pins are physically dedicated to the matrix hardware and don't need to be deallocated on driver initialization failure since they cannot be reused for other purposes without hardware changes.

Applied to files:

  • wled00/bus_manager.cpp
  • wled00/bus_manager.h
📚 Learning: 2025-09-13T13:13:36.092Z
Learnt from: netmindz
PR: wled/WLED#3777
File: wled00/bus_manager.cpp:982-989
Timestamp: 2025-09-13T13:13:36.092Z
Learning: In the WLED HUB75 implementation, when HUB75 matrix initialization fails after pin allocation, pins are intentionally not deallocated because they're physically connected to the HUB75 panel and cannot be reused for other purposes. This design choice prioritizes simplicity over strict software resource management consistency.

Applied to files:

  • wled00/bus_manager.cpp
  • wled00/data/settings_leds.htm
  • wled00/bus_manager.h
  • platformio_override.sample.ini
🧬 Code graph analysis (2)
wled00/colors.cpp (1)
usermods/Analog_Clock/Analog_Clock.cpp (2)
  • c1 (110-117)
  • c1 (110-110)
wled00/bus_manager.cpp (3)
wled00/fcn_declare.h (2)
  • d_free (446-446)
  • d_free (448-448)
wled00/util.cpp (6)
  • d_malloc (658-662)
  • d_malloc (658-658)
  • d_malloc (690-707)
  • d_malloc (690-690)
  • allocate_buffer (750-811)
  • allocate_buffer (750-750)
wled00/bus_manager.h (5)
  • show (248-254)
  • show (307-308)
  • show (334-335)
  • show (355-359)
  • show (381-389)
🔇 Additional comments (21)
platformio_override.sample.ini (5)

532-532: Added helpful ghosting guidance for HUB75 configurations.

This new comment documents a common HUB75 issue and provides a concrete solution (max brightness setting), which improves user experience and reduces support questions.


565-566: Added board file placement guidance with reference URL.

The comment about manual board file placement and the link to the official board definition is helpful for users encountering missing board file errors. This reduces friction during environment setup.


573-574: Improved USB configuration flag organization and clarity.

Separating ARDUINO_USB_CDC_ON_BOOT and ARDUINO_USB_MODE into distinct lines with explanatory comments makes the ESP32-S3 USB troubleshooting guidance clearer and easier to debug if users need to adjust these settings. The mention of possible boot issues is valuable context.


576-576: Clarified TX power reduction in LOLIN_WIFI_FIX comment.

The updated comment now explicitly documents that this flag sets lower TX power, which explains why it helps with WiFi stability on ESP32-S3 boards with active HUB75 panels. This is more informative than the previous wording.


602-602: Consistent TX power clarification in second HUB75 environment.

The same LOLIN_WIFI_FIX comment update applied here maintains consistency across both ESP32-S3 HUB75 configurations.

wled00/bus_manager.h (2)

398-406: LGTM - Well-structured additions for virtual display support.

The new member variables and constants are properly typed and support the expanded HUB75 functionality:

  • _rows and _cols enable multi-panel configurations
  • _ledBuffer type change from uint32_t* to CRGB* is more semantically appropriate for FastLED integration
  • Constants use proper constexpr with explicit typing

169-169: API change correctly implements expanded HUB75 pin configuration.

The change from 3 to 5 pins for HUB75 type is properly implemented and consistent throughout the codebase:

  • BusHub75Matrix::getPins() returns exactly 5 values (width, height, chain_length, rows, cols)
  • All callers treat the pin count as a dynamic value via loops—no hardcoded assumptions
  • OUTPUT_MAX_PINS is already defined as 5, supporting the expanded configuration
  • Call sites in cfg.cpp and xml.cpp scale correctly with the returned pin count
wled00/data/settings_leds.htm (4)

121-123: LGTM - Robust validation with sensible defaults.

The validation logic correctly enforces:

  1. Panel count must equal rows × cols
  2. Panels with height ≥ 64 are limited to single panel (memory constraint)

The ||1 defaults handle missing values gracefully.


263-268: LGTM - Clear and descriptive UI labels.

The updated labels correctly reflect the HUB75 configuration model with width, height, panel count, rows, and columns.


275-275: LGTM - Pin calculation aligns with API change.

The change from 2*isHub75(t) to 4*isHub75(t) correctly reflects the expanded HUB75 configuration from 3 to 5 "pins" (width, height, chain_length, rows, cols).


385-391: LGTM - Sensible defaults and constraints.

The field validation correctly:

  • Limits chain length, rows, and cols to 1-4 (matching C++ limits)
  • Defaults empty values to 1
  • Prevents invalid configurations
wled00/bus_manager.cpp (10)

26-26: LGTM - Explicit dependency inclusion.

Including "wled.h" makes buffer allocation dependencies (d_malloc, d_free, allocate_buffer) explicit and supports the memory management improvements in this PR.


34-54: LGTM - Micro-optimization using bit operations.

Replacing division and modulo with bit shifts is a classic optimization:

  • position / 8position >> 3
  • position % 8position & 0x07

While modern compilers typically optimize these automatically, the explicit bit operations make the intent clearer and may provide minor performance benefits on embedded targets.


762-768: LGTM - Clear initialization and readable aliases.

Explicitly initializing virtualDisp = nullptr prevents potential use-after-free issues, and the pin aliases (panelWidth, panelHeight, chainLength, rows, cols) improve code readability.


781-787: LGTM - Defensive memory constraints.

The chain length validation correctly:

  1. Clamps to maximum of 4 panels (prevents excessive memory allocation)
  2. Forces single panel for height ≥ 64 (prevents memory exhaustion)
  3. Provides clear debug output

This aligns with the UI validation in settings_leds.htm.


927-946: LGTM - Careful memory management with proper cleanup.

The memory allocation logic demonstrates good practices:

  • Defensive freeing of existing buffers (Lines 927-928)
  • Proper error handling with cleanup on allocation failure
  • Using allocate_buffer with appropriate flags (BFRALLOC_PREFER_DRAM | BFRALLOC_CLEAR)
  • Clear debug messages for troubleshooting

949-980: LGTM - Comprehensive virtual display initialization.

The virtual display setup correctly:

  1. Determines when virtualization is needed (multi-panel chains or quarter-scan)
  2. Creates VirtualMatrixPanel with proper geometry
  3. Configures scan rates for quarter-scan panels based on height
  4. Handles unsupported configurations with cleanup

998-998: LGTM - Appropriate IRAM placement for hot path.

Adding IRAM_ATTR to setPixelColor is appropriate as this is a frequently-called hot-path function. Placing it in IRAM reduces instruction cache misses and improves performance, especially during LED updates.


1045-1061: LGTM - Efficient show() with proper brightness handling.

The implementation correctly:

  1. Selects virtual or physical display based on configuration
  2. Applies brightness using FastLED's nscale8_video() (video scaling)
  3. Updates only dirty pixels for performance
  4. Clears dirty flags after display update

1063-1078: LGTM - Careful cleanup with S3 workaround.

The cleanup implementation demonstrates proper resource management:

  • Stops DMA output before cleanup
  • Deallocates pins
  • Works around ESP32-S3 DMA deletion crash (Lines 1070-1075)
  • Properly frees buffers using d_free

The S3 workaround is well-documented and aligns with the "requests additional testing" note in the PR objectives.

Based on learnings: "For HUB75 matrix panels in WLED, pins are physically dedicated to the matrix hardware and don't need to be deallocated on driver initialization failure."


1093-1102: LGTM - getPins correctly returns 5 configuration values.

The implementation returns the expanded HUB75 configuration:

  1. Width (mxconfig.mx_width)
  2. Height (mxconfig.mx_height)
  3. Chain length (mxconfig.chain_length)
  4. Rows (_rows)
  5. Columns (_cols)

This aligns with the API change in bus_manager.h (Line 169) and the UI implementation in settings_leds.htm.

Comment on lines 789 to 796
if (bc.type == TYPE_HUB75MATRIX_HS) {
mxconfig.mx_width = min((uint8_t) 64, bc.pins[0]);
mxconfig.mx_height = min((uint8_t) 64, bc.pins[1]);
// Disable chains of panels for now, incomplete UI changes
// if(bc.pins[2] > 1 && bc.pins[3] != 0 && bc.pins[4] != 0 && bc.pins[3] != 255 && bc.pins[4] != 255) {
// virtualDisp = new VirtualMatrixPanel((*display), bc.pins[3], bc.pins[4], mxconfig.mx_width, mxconfig.mx_height, CHAIN_BOTTOM_LEFT_UP);
// }
mxconfig.mx_width = min((uint8_t) 64, 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) {
mxconfig.mx_width = min((uint8_t) 64, bc.pins[0]) * 2;
mxconfig.mx_height = min((uint8_t) 64, bc.pins[1]) / 2;
virtualDisp = new VirtualMatrixPanel((*display), 1, 1, bc.pins[0], bc.pins[1]);
virtualDisp->setRotation(0);
switch(bc.pins[1]) {
case 16:
virtualDisp->setPhysicalPanelScanRate(FOUR_SCAN_16PX_HIGH);
break;
case 32:
virtualDisp->setPhysicalPanelScanRate(FOUR_SCAN_32PX_HIGH);
break;
case 64:
virtualDisp->setPhysicalPanelScanRate(FOUR_SCAN_64PX_HIGH);
break;
default:
DEBUGBUS_PRINTLN("Unsupported height");
return;
}
_isVirtual = true;
mxconfig.mx_width = min((uint8_t) 64, panelWidth) * 2;
mxconfig.mx_height = min((uint8_t) 64, panelHeight) / 2;
} else {
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Address dimension limit inconsistency.

The code limits panel dimensions to 64 pixels, but Line 790's TODO notes "UI limit is 128, this limits to 64". This creates a mismatch between what the UI allows and what the backend accepts.

Verify the correct maximum dimension for HUB75 panels. If 64 is the correct limit, update the UI validation in settings_leds.htm. If 128 is correct, adjust the code here.


🏁 Script executed:

#!/bin/bash
# Check UI field limits for HUB75 width/height
rg -n "LC.*max.*128" wled00/data/settings_leds.htm -A 2 -B 2

Length of output: 164



And check for any related constants or configuration:



🏁 Script executed:

#!/bin/bash
# Search for more context about HUB75 matrix dimensions and type handling
rg -n "TYPE_HUB75MATRIX" wled00/bus_manager.cpp -B 2 -A 5

Length of output: 1805


🏁 Script executed:

#!/bin/bash
# Look for HUB75-related constants or limits in the codebase
rg -n "HUB75|mx_width|mx_height" wled00/bus_manager.cpp -B 1 -A 1 | head -100

Length of output: 4927


Update the UI to enforce type-specific dimension limits for HUB75 panels.

The code correctly handles different limits for panel types:

  • Half-Scan (HS): limited to 64×64 via min((uint8_t) 64, panelWidth)
  • Quarter-Scan (QS): can reach 128×128 via min(64, panelWidth) * 2

However, the UI allows 128 for both types without differentiation. This means users can set invalid 128×128 dimensions for Half-Scan panels through the UI, which the code silently clamps to 64×64. Update settings_leds.htm to set LC.max = 64 when isHub75(t) AND the panel type is Half-Scan, or dynamically adjust based on selected panel type. Remove or resolve the TODO comment at line 790 once fixed.

🤖 Prompt for AI Agents
In wled00/bus_manager.cpp around lines 789-796 the code clamps HS panels to
64×64 but the UI still allows 128×128 causing silent clamping; update
settings_leds.htm to enforce type-specific limits: when isHub75(t) is true and
panel type is Half-Scan set LC.max = 64, when panel type is Quarter-Scan set
LC.max = 128 (or compute from selected type), add a change handler to
dynamically adjust LC.max when the panel type dropdown changes and
validate/submit to prevent values above the type limit, and remove or resolve
the TODO comment at the C++ line once the UI enforces the correct limit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, this is what the TODO sais.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DedeHai, understood! Since this is a known issue already documented in the TODO comment, would you like to:

  1. Address it in this PR - I can help update the UI validation logic in settings_leds.htm to enforce type-specific limits (64 for Half-Scan, 128 for Quarter-Scan)
  2. Defer to a follow-up - If this is out of scope for the current PR, I can create a tracking issue that references this PR and the TODO comment for future work

Which would you prefer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant