firmware-ch32x: USB-PD DR_Swap — a PC on the output port enumerates the RP2040 CDC while being powered#6
Merged
Merged
Conversation
…he RP2040 CDC while being powered
Dock-style behavior on the output USB-C port: a laptop attached instead
of a Pi negotiates power as a sink and takes the USB host data role, so
the RP2040 WUPS CDC is reachable without a Pi in the loop. Verified E2E
on MacBook Pro M4 (macOS 26.5.2): stable 15 V + /dev/cu.usbmodem* for
5+ min, including on battery.
Protocol (PD_Process.c/.h):
- DR_Swap Accept: STA_IDLE-only, NumDO==0 guard (type 0x09 collides with
PD3.1 EPR_REQUEST), MessageID retransmission dedup (latch invalidated
by any other dispatched message — 3-bit counter wraps), role TOGGLE
only after TX-confirmed Accept inside an IRQ-guarded RMW (Flag word is
shared with the ISR), Wait when busy, HRST on ambiguous TX failure;
GoodCRC byte0 is now role-aware (0x61 DFP / 0x41 UFP)
- post-swap host traffic answered instead of ignored — PD3 treats
GoodCRC-then-silence as a protocol error and macOS loops
Soft_Reset -> renegotiate -> re-swap (CDC flapped sub-second):
default -> Not_Supported (PD3-negotiated only; PD2 keeps the shipped
silent behavior), VCONN_Swap -> Reject, Get_Source_Cap -> inline
SRC_CAP (the STA_TX_SRC_CAP path has a 160 ms dwell, over
tSenderResponse), Get_Sink_Cap -> Not_Supported
- Discover Identity received as UFP -> honest ACK (USB Device Capable,
Peripheral, VID 0x2E8A); with a NAK macOS never sends Enter_USB and
tears the port down right after electrical attach (and remembers the
verdict per physical port). The RPi-27W identity reply is now gated
on PD_Role==DFP so a post-swap host is never told we are a Pi PSU
- Enter_USB (DATA type 0x08) -> Accept for USB2, Reject for USB3/USB4
- PDO#1 advertises USB Communications Capable (B26) alongside the
long-shipped Dual-Role Data bit
- spec-complete Soft_Reset RX: MessageID counter reset + SRC_CAP
re-advertise (previously Accept-then-dead-air escalated through
SinkWaitCap timeout to Hard Reset = VBUS drop)
- data-role restore to DFP + dedup reset on TX Hard Reset and on
Power_Output_Restart via new PD_DataRole_Reset() (a swapped role must
not leak into the fresh session after ups.power.cycle)
- STA_RX_REQ_WAIT timeout no longer fires while a received message is
still awaiting dispatch (the state machine runs before RX dispatch;
telemetry-heavy loop iterations exceeded the 29 ms window and our own
latency HRST'd a valid Request)
Diagnostics + latency (main.c):
- PD event trace ring drained into system.log frames ("[CH32X log]
PD: ...") visible on the Probe/USB-CDC debug stream; writers only
store a byte so tracing adds zero latency to protocol paths;
rate-limited to 1 frame per 4 ms (RP2040 forwarder drops a 3rd
back-to-back frame)
- PD_Service() wrapper with its own ms-delta accounting, called between
the heavy bit-bang I2C telemetry blocks: worst-case PD dispatch
latency was 10-30 ms against tSenderResponse 24-30 ms (calling
PD_Main_Proc repeatedly with the loop-top delta would multiply-count
time and break the attach timing)
NOT for production units yet: PDO#1 changed (B26) — the mandatory Pi 5
regression run (5V/5A contract, VDM 5A unlock, CDC enumeration, load
soak) has not been done.
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.
What
Dock-style behavior on the output USB-C port: a laptop attached instead of a Pi negotiates power as a sink and takes the USB host data role via PD DR_Swap, so the RP2040 WUPS CDC is reachable without a Pi in the loop. Companion desktop viewer: Web3-Pi-UPS-Service#3 (
ups-live).The full recipe (each piece required, discovered iteratively on the bench):
Also fixes two pre-existing protocol bugs (spec-incomplete Soft_Reset RX that escalated to Hard Reset + VBUS drop; STA_RX_REQ_WAIT timeout firing on our own dispatch latency) and adds a PD event trace ring (visible as
[CH32X log] PD: ...via RP2040 debug/Probe) plusPD_Service()latency relief between the heavy I2C telemetry blocks.Verification
0x0E0191F4) andmax_current=5000— the VDM 5 A unlock works; CDC enumerates; w3p-ups agent parses the stream with zero errors; no undervoltageBefore flashing the production run
Still outstanding (tracked for the release checklist, not blockers for main):