feat: enable the CrowPanel's USB 2.0 port as a fast deck link - #11
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
UART0at115200 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):USB1_D+/D-J1(UART0)U1= CH340KUSB2_D+/D-J16(USB 2.0)U7= ESP32-P4NRW32 pads 50 / 49Pads 49/50 are the P4's dedicated HS_PHY. Both FS PHYs are unavailable on
this board: GPIO24/25 (USB Serial/JTAG) carry
I2S_MCLKandP4_IO25, andGPIO26/27 (OTG-FS) carry
I2S_SDIN2andP4_TXD2. Elecrow's own USB exampleconfirms the port with
CONFIG_TINYUSB_RHPORT_HS=y.Two consequences: the bootloader is only reachable over
UART0, so flashingis unchanged; and enabling the port is purely a firmware change.
What changed
Firmware
0.1.9→0.2.0(espressif/esp_tinyusb2.2.1, CDC-ACM). Bothtransports stay live and share one line assembler and one dispatch lock, since
deck_protocolkeeps static decode state. Replies and queued touch/press eventsfollow 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.1with the board's device ID asits 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, andreconnect opens every authorized port. The hello names its link
(
transport-usb/transport-uart); the app ranks it and keeps one session perdevice 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:
featuresalready exists, is validated, and isoptional, so older firmware and the Waveshare board are unaffected.
Testing
node boards/tools/build-catalog.js --validate-only— 2 profilesnode --test boards/tools/*.test.js— 15 pass (+1 firmware source contract)desktop:npm test228 pass (+4),npm run checkcleanNot 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.