Skip to content

feat: enable the CrowPanel's USB 2.0 port as a fast deck link - #11

Merged
FadyFaheem merged 3 commits into
mainfrom
feat/crowpanel-usb2-link
Jul 27, 2026
Merged

feat: enable the CrowPanel's USB 2.0 port as a fast deck link#11
FadyFaheem merged 3 commits into
mainfrom
feat/crowpanel-usb2-link

Conversation

@FadyFaheem

Copy link
Copy Markdown
Owner

Why

The Elecrow CrowPanel's second USB-C port is wired straight to the ESP32-P4's
USB 2.0 high-speed PHY, but Elecrow ships it disabled — their wiki says "the
shipped firmware does not include USB functionality"
— so it only ever supplied
power. Every deck sync therefore ran through the CH340K bridge on UART0 at
115200 baud, where a single 2688-byte image chunk needs about 320 ms of wire
time. A 150 px key is ~17 chunks, so cold syncs took seconds per key.

Hardware verification

From Elecrow's own Eagle schematic (ESP32-P4 Display 10.1 inch V1.2.sch):

Net Connector Destination
USB1_D+/D- J1 (UART0) series resistors into U1 = CH340K
USB2_D+/D- J16 (USB 2.0) U7 = ESP32-P4NRW32 pads 50 / 49

Pads 49/50 are the P4's dedicated HS_PHY. Both FS PHYs are unavailable on
this board: GPIO24/25 (USB Serial/JTAG) carry I2S_MCLK and P4_IO25, and
GPIO26/27 (OTG-FS) carry I2S_SDIN2 and P4_TXD2. Elecrow's own USB example
confirms the port with CONFIG_TINYUSB_RHPORT_HS=y.

Two consequences: the bootloader is only reachable over UART0, so flashing
is unchanged
; and enabling the port is purely a firmware change.

What changed

Firmware 0.1.90.2.0 (espressif/esp_tinyusb 2.2.1, CDC-ACM). Both
transports stay live and share one line assembler and one dispatch lock, since
deck_protocol keeps static decode state. Replies and queued touch/press events
follow whichever link delivered the last host line. USB bring-up failure is
logged, never fatal — a panel must not lose the port it is flashed through.

The device enumerates as Stream32 CrowPanel 10.1 with the board's device ID as
its USB serial number, so the two ports are tellable apart in the port list.

Desktop. The board now answers on two ports with the same deviceId, and
reconnect opens every authorized port. The hello names its link
(transport-usb / transport-uart); the app ranks it and keeps one session per
device on the fastest one. Flashing had the same one-port-per-board assumption
and now releases every session for the board it resets.

No protocol version bump: features already exists, is validated, and is
optional, so older firmware and the Waveshare board are unaffected.

Testing

  • node boards/tools/build-catalog.js --validate-only — 2 profiles
  • node --test boards/tools/*.test.js — 15 pass (+1 firmware source contract)
  • desktop: npm test 228 pass (+4), npm run check clean

Not yet verified on hardware. I have no CrowPanel or ESP-IDF locally, so
this PR relies on Board CI for the compile, and the USB link still needs a
real-panel check: enumeration, a cold sync over USB 2.0, a flash over UART0
with the USB cable attached, and the panel working with only UART0 connected.

FadyFaheem and others added 3 commits July 27, 2026 13:38
The CrowPanel's second USB-C port wires D+/D- straight to the ESP32-P4's
high-speed USB PHY, but Elecrow ships it disabled, so the port only ever
supplied power and every deck sync crawled through the CH340 bridge at
115200 baud. One 2688-byte image chunk costs about 320 ms there, which
is seconds per key of artwork.

Bring the port up as a TinyUSB CDC-ACM link and run the same JSON line
protocol over it. UART0 stays live beside it because it is the only way
to flash this board and the link the desktop holds across the manual
post-flash reset, so both transports share one line assembler and one
dispatch lock. USB bring-up failures are logged rather than fatal: a
panel must never lose the port it is flashed through.

The hello now names its link so the desktop can tell the two ports of
one board apart, and the device enumerates as "Stream32 CrowPanel 10.1"
with the board's device ID as its USB serial number.

Co-authored-by: Cursor <cursoragent@cursor.com>
A CrowPanel on firmware 0.2.0 answers on both its CH340 bridge and its
native USB 2.0 port with the same deviceId. Reconnect opens every
authorized port, so the app would hold two sessions for one panel,
report it twice, and sync over whichever port enumerated first.

Rank the link the firmware names in its hello and keep only the fastest
session per device. Firmware that names no transport ranks lowest, so
single-port boards keep their existing session either way.

Flashing had the same one-port-per-board assumption: it released only
the port it flashes through, leaving a sibling session alive across a
reset that invalidates it.

Co-authored-by: Cursor <cursoragent@cursor.com>
Every guide called the CrowPanel's USB 2.0 port optional supplemental
power, which is what Elecrow's stock firmware makes it. It now also
carries the deck protocol, so say what each port is for: UART0 is the
only port that can flash the board, and USB 2.0 is the fast sync link.

Co-authored-by: Cursor <cursoragent@cursor.com>
@FadyFaheem
FadyFaheem merged commit f1acc4b into main Jul 27, 2026
6 checks passed
@FadyFaheem
FadyFaheem deleted the feat/crowpanel-usb2-link branch July 27, 2026 19:01
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