Skip to content

Scaling beyond one panel — what one board can drive, and the routes to a bigger display #271

Description

@engmung

Why this exists

Two questions keep arriving in different disguises: "my new high-refresh panel is black" (#259) and "can I run a big wall with this?" They have the same root, and it is not the one people expect. This issue writes down what one Patternflow board can and cannot drive, why, and what the routes to a larger display actually look like.

Short version: nothing about reactive patterns is limited. What is limited is how many pixels one ESP32-S3 can push, and which panel protocol it speaks. Those are two separate walls and they need different answers.


1. The two walls

Wall A — protocol: S-PWM panels cannot be driven directly

Classic panels (74HC595, FM6124, ICN2037, DP5125D…) are dumb shift registers. They have no brightness control of their own, so the controller manufactures PWM by re-sending bit-planes hundreds of times per second. That is what Patternflow does today.

Newer S-PWM / GCLK chips (ICN2053, FM6353, FM6363C, MBI5153, DP3264…) moved that work into the chip: on-chip frame memory plus a PWM engine. The controller writes a frame once and the chip runs its own 3840 Hz output. To talk to them you need a register init sequence, commands encoded as LAT pulse widths, and a continuously supplied grey-scale clock.

Same 16-pin HUB75E connector, same signal names, incompatible conversation. This is why the panel is completely black rather than dim or ugly — it is not a performance shortfall, it is a language mismatch.

Three things worth knowing:

  • It is not an ESP32 weakness. rpi-rgb-led-matrix has no official S-PWM support either, and a Raspberry Pi is far faster. A continuous GCLK is a timing problem, not a throughput problem.
  • It is not impossible either. LAutour's fork drives ICN2053/FM6353 on a plain ESP32 with no added hardware. It is just slow (≤13 MHz, 16-bit colour, ~30 Hz at 8192 px) and unmaintained since 2023.
  • Upstream declined on purpose. Discussion #324 — supporting memory-based drivers is "a fundamental change to what this library was designed for"; maintainer recommends a separate codebase. #642 closed wontfix.

Already own one? docs/panel-compatibility.md §11 lists the options.

Wall B — throughput: one board tops out around one 128×64 panel

Because Patternflow manufactures the PWM, work scales directly with pixels per row. Chaining panels divides the available time.

Measured/derived at the shipped settings (16 MHz, 8-bit, min_refresh_rate 240, 1/32 scan):

Chain Resolution Refresh Properly-weighted colour
1 128×64 260 Hz 4 bit
2 256×64 244 Hz 1 bit
4 512×64 122 Hz 1 bit
8 1024×64 61 Hz 1 bit

Colour collapses at the second panel: the driver raises lsbMsbTransitionBit to hold 240 Hz and the low bits lose their weighting. It is a tunable trade, not a cliff —

min_refresh_rate chain 1 chain 2 chain 4
240 Hz 260 Hz / 4 bit 244 Hz / 1 bit 122 Hz / 1 bit
120 Hz 169 Hz / 5 bit 130 Hz / 4 bit 122 Hz / 1 bit
60 Hz 100 Hz / 6 bit 84 Hz / 5 bit 65 Hz / 4 bit

— but every extra panel is paid for in refresh or in colour. The 240 Hz default exists so phone cameras don't band on video; a wall build would relax it.

Two hard limits sit in front of that table.

Memory. SPIRAM_DMA_BUFFER is not defined, so the DMA framebuffer lives in internal RAM — of which a running v3.0 board reports ~11 KB free (/api/statusheapInternal:11420), while 8 MB of PSRAM sits idle. Chain 2 roughly doubles the buffer. Enabling PSRAM for the buffer should move this wall, at the cost of a lower clock ceiling. Untested.

Power. A 128×64 P2.5 panel draws about 2.5 A at 5 V at full brightness (derived from the measured runtime table in the README: 10,000 mAh ≈ 4 h). A typical USB power-bank port tops out at 2.4 A. One panel already sits at the ceiling; two do not start.

Confirmed on hardware: a chain-2 attempt on a power bank never booted — power LED blinking, immediate cut-out, repeating. That is the bank's over-current protection tripping on panel inrush, not a firmware fault. A memory failure looks different: Matrix begin FAILED and a silent hang with the rail still up (core_display.h). We never got far enough to find out whether chain 2 works in firmware.

⚠️ If you do feed two panels: don't run 5 A through J3. Panel current currently flows J4 → board traces → J3 → panel, which is sized for one panel. Split the supply at the PSU — panels direct, board on logic power only.

And note what a wall-powered build costs: Patternflow stops being the thing you carry around on a power bank.


2. What is not limited

Worth stating plainly, because the two walls above get mistaken for a limit on the concept itself.

A Patternflow pattern is a function — (x, y, time, audio, knobs) → colour. That is hardware-independent. The same patterns already run in two unrelated runtimes today: Pattern Lab's browser preview (JS) and the device (C++). Audio reactivity, encoder input and OSC are all upstream of the panel driver.

So: reactive patterns on a large display are not blocked. Only the last step — pushing finished pixels onto specific hardware — is hardware-bound.


3. Routes to a bigger display

A. Tiling — several Patternflow nodes, one surface

Each node drives its own section; a shared clock and per-node coordinate offset make them one canvas. Standard practice for large LED art installations, and the most Patternflow-native answer.

Ingredients that already exist: bidirectional OSC, Wi-Fi, PANEL_RES_W/H/CHAIN as build config, @matrix frames.

Missing, and this is real feature work, not configuration:

  • shared time base (frame sync across nodes; Wi-Fi jitter is the hard part)
  • per-node canvas offset — a node must render its window of a larger virtual canvas
  • one-to-many parameter distribution (a knob turn on one unit reaching all of them)
  • provisioning/addressing so nodes know their position in the grid

Nearest existing groundwork: #224.

B. Render elsewhere, feed the wall

Run the pattern function on a PC or Pi, ship frames to whatever already drives the wall (commonly a Colorlight/Novastar receiving card over Ethernet).

The key property: you write the output backend once, not once per pattern. Every existing pattern, and every future one, works the moment the renderer exists. Audio reactivity gets easier here, not harder — the host has a real audio stack.

This is also the only route that reaches genuinely large commercial surfaces, which already have receiving cards in them. Those installations do not want an MCU in the chain.

C. Direct S-PWM support in firmware

Would remove Wall A and substantially soften Wall B — a chip that runs its own PWM means writing a frame once instead of 260 times a second, so one ESP32 covers far more area. Tempting for that reason.

Cost is high: per-family command protocols reconstructed from partly reverse-engineered documentation, two synchronised output streams (frame data + uninterrupted GCLK), a driver abstraction inside Patternflow, and split firmware images since a panel cannot be detected at runtime. Plus at least one physical panel per chip family to develop against.

Realistically an open R&D project with an indefinite maintenance tail — which is exactly why upstream declined it.

D. Add an FPGA/CPLD to the board

Rejected. That is what a receiving card is, and it would delete every property of the current board (all through-hole, 5 unique parts, ~$35, beginner-solderable) to produce a worse Colorlight 5A-75B — a finished board that costs about $20.


4. Where this leaves things

Question Answer
Reactive patterns ✅ Not limited
A different classic panel ✅ Three lines in config.h#224
Chain of 2 on one board ❓ Untested — blocked on power before firmware was reached
S-PWM panel, direct ❌ Not supported, see §1
Patternflow patterns on a large wall ✅ Route A or B
One Patternflow board driving a large wall ❌ Not a goal, and not reachable

No work is being scheduled from this issue. It exists so the question stops being re-litigated from scratch, and so anyone who wants to attempt route A or B has the numbers in one place.

Corrections and contradicting measurements are welcome — particularly a successful chain-2 with a proper 5 V supply, which would settle the memory question left open in §1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:firmwareESP32 firmware running on the devicearea:pcbCircuit board, components, power, solderingtype:questionOpen question or discussion needed

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions