Skip to content

Light a HUB75 panel's last row as long as every other - #211

Merged
ewowi merged 4 commits into
MoonModules:mainfrom
AnjinMeili:hub75-seam-row
Oct 30, 2026
Merged

ewowi merged 4 commits into
MoonModules:mainfrom
AnjinMeili:hub75-seam-row

Conversation

@AnjinMeili

Copy link
Copy Markdown
Contributor

What it changes, and why

Two chained 64x64 HUB75 panels on a MatrixPortal S3 showed a line along the seam between the panel halves and along the bottom edge: brighter than its neighbors below half gray, nearly dark just above it, invisible on white. It may be the "line across HUB75 panels" mentioned on Discord, for panels driven straight from the board's pins.

The cause is in hub75Encode (Hub75Slots.h). A panel lights what the previous row latched, so row 0's words light the last row of the plane before. Those words took the lit window of the plane being clocked in, so the last scan row of each half weighed its lower bits double and its top bit at the shortest window. The fix gives row 0's words the window of the plane its latched data came from, and the top plane's for plane 0, where the buffer wraps.

On a directly driven panel the affected rows were the last row of every scan block: 31 and 63 at 1/32 scan, 15, 31, 47 and 63 on a 64-row 1/16 panel. Panels behind a ColorLight receiving card are unaffected; the card does its own scanning.

Also in this PR:

  • moonlive/effects/basics/ramp.mle: a gray ramp, the same on every row. Any row that differs from its neighbors is a drive fault, so it is a quick test pattern for any panel, loaded as a script with no firmware build.
  • docs/work/present/atlas/example-hub75-seam-row.md: how the cause was found from the report, the bench results, and the session's transcript. It shows the MoonAtlas query tool from my fork's moonatlas branch, which is not upstream yet; I am happy to drop the file here if you would rather see it with that branch.

What an agent wrote

Claude (Opus) traced the cause from the report, wrote the fix, the test, the ramp script and the doc, and I reviewed each line. The diagnosis and the fix were confirmed on my panels before committing.

What you tested, and on which hardware

  • Desktop: test_desktop --module Hub75Driver, 21 passed, including a new test that reads the encoded frame as the panel does and requires every row of a value to be lit equally. It fails against the old encoder: rows 31 and 63 light 123 words where every other row lights 62. test_desktop --module MoonLive, 394 passed, with ramp.mle's IR golden hash added.
  • Hardware: Adafruit MatrixPortal S3 (esp32s3-n8r2) driving two chained 64x64 1/32-scan panels, 128x64. Before the fix, with ramp.mle running: a dark segment on the seam row, and with the camera out of sync with the panel, bright lines on rows 31 and 63. After the fix, flashed over the air through MoonBase: no line at the seam or the bottom edge across the whole ramp.

Two chained 64x64 panels showed a line along the seam between the halves and along the bottom edge: brighter than its neighbors below half gray, nearly dark just above it, invisible on white. Each half-panel's last row now holds its color the way every other row does.

**Light domain**
- Hub75Slots.h: row 0's words light the last row of the plane before, still in the latch, so they take that plane's lit window, and plane 0's take the top plane's, the one the buffer wraps from. They took the window of the plane being clocked in, so the last row of each half weighed its lower bits double and its top bit at the shortest window. The `@technical` section says why the window follows the latched data.

**Tests**
- unit_Hub75Slots: every row of a value is lit as long as every other, the last row of each half included, read as the panel sees it (a row lights what the row before it latched); it fails against the old window. litWords and the output-enable test measure the row that lights a plane's data rather than the row that clocks it in.
- moonlive_ir_golden.inc: ramp.mle's IR hash, captured with MM_PRINT_IR_GOLDEN=1.
- test_desktop --module Hub75Driver: 21 passed. --module MoonLive: 394 passed.

**Docs/CI**
- moonlive/effects/basics/ramp.mle: a gray ramp, the same on every row, the test pattern that shows a row driven wrong; script_catalog.h regenerated with its entry.
- docs/work/present/atlas/example-hub75-seam-row.md: how the cause was found from the report, with the session's transcript to the test pattern.
Copilot AI balanced review requested due to automatic review settings October 30, 2026 01:23
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues remain to block approval.

No open issues 🎉

What changed in this PR

Corrects HUB75 output-enable timing so the last scan row receives the same bit-plane weighting as other rows, addressing seam and bottom-edge brightness artifacts on directly driven panels.

Changes:

  • Uses the latched plane’s lighting window at row and frame boundaries.
  • Adds a row-brightness regression test and a registered grayscale ramp effect.
  • Documents the diagnosis, bench results, and MoonAtlas investigation.
File Description
test/​unit/​light/​unit_Hub75Slots.cpp Tests equal row lighting and updates timing helpers.
test/​unit/​light/​moonlive_ir_golden.inc Adds the ramp effect’s compiler golden hash.
src/​light/​drivers/​Hub75Slots.h Aligns lighting duration with the latched bit plane.
src/​core/​moonlive/​script_catalog.h Registers the ramp effect and updates catalog counts.
moonlive/​effects/​basics/​ramp.mle Adds a grayscale ramp identical on every row.
docs/​work/​present/​atlas/​example-hub75-seam-row.md Records the investigation and hardware verification.

Review effort: Balanced

AnjinMeili and others added 3 commits October 29, 2026 18:33
check_docgen failed MoonModules#211: the new test's two-line comment is a hard wrap, and three lines ran past the length limits.

**Light domain**
- Hub75Slots.h: the paragraph on the lit window splits in two, each within a doc line's 250 characters, and the encoder's brief keeps its earlier wording.

**Tests**
- unit_Hub75Slots: the new test's comments, one line each, within a comment line's 250 characters.
- check_docgen: 0 errors, every count at or below the committed one.
The example cites the encoder and its test by line, and the fix moved those lines: the page now says its line numbers are the code before the fix.

**Docs/CI**
- docs/work/present/atlas/example-hub75-seam-row.md: one clause in the intro.
…r's comment says what is

**Light domain**
- Hub75Slots.h: the paragraph on the lit window's earlier behavior goes; git holds it.

**Docs/CI**
- docs/work/present/atlas/example-hub75-seam-row.md removed: it needs the MoonAtlas branch, which is not upstream.
- docgen.json: warnings 2050 → 2038.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ewowi
ewowi merged commit 4e653f4 into MoonModules:main Oct 30, 2026
11 checks passed
@ewowi

ewowi commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Thanks James, merged. This is a clean find. The encoder had the right idea, that the latch lags the data by one row, but gave row 0 the wrong plane's timing, and white hid it. The test that reads the frame the way the panel does now pins it for every value, not only 255. ramp.mle is a useful pattern for any panel too.

I added one commit on your branch before merging:

  • Removed the MoonAtlas example page, as you offered. It relies on your moonatlas branch and its claim files, which aren't upstream. docs/work/ holds plans and the backlog mirror. When MoonAtlas comes up for review, the example could come with it.
  • Removed the second paragraph you added to Hub75Slots.h's @technical, the one on the earlier behavior. Docs describe the code as it is, and git keeps the history.

Looking forward to more!

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.

3 participants