ch32: portable async USBFS host driver — hub, multi-device, hotplug (v20x + v307)#3682
ch32: portable async USBFS host driver — hub, multi-device, hotplug (v20x + v307)#3682RobertDaleSmith wants to merge 1 commit into
Conversation
1f528bc to
c05ab16
Compare
|
| target | .text | .rodata | .data | .bss | total | % diff |
|---|---|---|---|---|---|---|
| ch32v307v_r1_1v0/hid_generic_inout | 10,520 → 11,636 (+1,116) | — | — | — | 11,016 → 12,132 (+1,116) | +10.1% |
| ch32v307v_r1_1v0/dfu_runtime | 9,380 → 10,504 (+1,124) | — | — | — | 13,068 → 14,188 (+1,120) | +8.6% |
| ch32v307v_r1_1v0/printer_to_cdc | 13,308 → 14,424 (+1,116) | — | — | — | 13,796 → 14,912 (+1,116) | +8.1% |
| ch32v307v_r1_1v0/webusb_serial | 13,528 → 14,632 (+1,104) | — | — | — | 14,072 → 15,176 (+1,104) | +7.8% |
| ch32v307v_r1_1v0/usbtmc | 13,976 → 15,072 (+1,096) | — | — | — | 14,592 → 15,688 (+1,096) | +7.5% |
| ch32v307v_r1_1v0/hid_boot_interface | 11,364 → 12,480 (+1,116) | — | — | — | 15,132 → 16,244 (+1,112) | +7.3% |
| ch32v307v_r1_1v0/hid_multiple_interface | 11,340 → 12,452 (+1,112) | — | — | — | 15,108 → 16,216 (+1,108) | +7.3% |
| ch32v307v_r1_1v0/hid_composite | 11,712 → 12,828 (+1,116) | — | — | — | 15,504 → 16,616 (+1,112) | +7.2% |
| ch32v203c_r0_1v0/hid_controller | 18,380 → 19,588 (+1,208) | — | — | 1,716 → 2,016 (+300) | 22,680 → 24,192 (+1,512) | +6.7% |
| ch32v307v_r1_1v0/audio_test | 13,008 → 14,140 (+1,132) | — | — | — | 17,384 → 18,512 (+1,128) | +6.5% |
c05ab16 to
c3ac096
Compare
|
Thank you for this work! I tested on CH32V203 and found an enumeration issue with some Low Speed PR: joypad-ai#1 Please take a look when you get a chance. |
|
@verylowfreq thank you for testing so quickly. i merged your changes in and verified it all still works on my end with a v307. 🙏 |
HiFiPhile
left a comment
There was a problem hiding this comment.
Thanks for your hard work ! But I've to say in current state it's not mergeable due to:
wch_usbfs_llis not MIT licensed to be included insrc(although I believe WCH doesn't care)wch_usbfs_llis a black box and nightmare to maintain, previously we had very limited support from WCH, if anything goes wrong we have to spend a lot of time.- Many functions are unused like
USBFS_RCC_InitandUSBFS_Host_Initwhich make things confusing. USBFSH_CtrlTransferimplement control transfer Synchronously with a maximum blocking time ofDEF_CTRL_TRANS_TIMEOVER_CNTwhich against TinyUSB's asynchronous approach especially when no RTOS is used.
|
@HiFiPhile thank you so much for taking the time to review this and for the feedback. I totally understandable the concerns. I will circle back to this and see what I can come up with. 🙏 |
67d4804 to
434051d
Compare
…v20x + v307) Add a TinyUSB HCD for the CH32 USBFS host controller (CH32V20x and CH32V307). Control, interrupt and bulk transfers all run through one ISR-driven async ep[] scheduler modeled on the MAX3421 HCD, with a single transaction outstanding on the controller's single host engine. A per-(daddr, ep) endpoint model supports USB hubs, multiple downstream devices and hotplug. Control transfers are fully asynchronous: hcd_setup_send queues the SETUP, the DATA and STATUS stages run via hcd_edpt_xfer, and each stage completes from the transfer-done IRQ. Nothing blocks the caller, so it works without an RTOS. Root-port reset/enable and the transaction layer are native register sequences derived only from the CH32 register definitions in ch32_usbfs_reg.h — no vendor host code is included. Also wires the USBFS host into the ch32v20x and ch32v30x BSPs (IRQ handler, family glue, linker) and makes tusb_verify's ebreak a no-op on CH32 RISC-V cores so a TU_VERIFY failure does not trap the core. Low-speed-via-hub speed-select and register-update fixes contributed by verylowfreq.
434051d to
34f3170
Compare
Hardware-in-the-loop (HIL) Test Reporthfp.json
Legend: ✅ pass · ❌ fail · ⚪ skipped · blank not run tinyusb.json
Legend: ✅ pass · ❌ fail · ⚪ skipped · blank not run |
Summary
Reworks the CH32 USBFS host controller driver into a portable, fully
interrupt-driven asynchronous scheduler that supports USB hubs, multiple
simultaneous devices, and hotplug, covering both CH32V20x and CH32V307
from one driver.
The existing driver (added in #2793 by @verylowfreq) drives a single device with
a blocking per-transfer model on v20x, and v307 USBFS host wasn't wired up at
all. This replaces the transfer core with an
ep[]-scheduler model and routescontrol transfers through WCH's reference transaction layer, keeping the same
CFG_TUH_WCH_USBIP_USBFSentry point.Important
This supersedes @verylowfreq's v20x driver with a hub-capable one for the whole
family. v307 is hardware-verified; v20x is build-verified only (I don't have
a v20x board). The silicon and registers are identical across the family, but
v20x should get a hardware pass before merge — happy to coordinate.
Why
The CH32 USBFS peripheral has a single host transfer engine (one
DEV_ADDRlatch, one
HOST_EP_PIDtoken, one shared toggle pair, one RX/TX DMA pair).One-transfer-at-a-time works for a single boot device but can't fan out to a hub
plus several interrupt endpoints — which real adapters need.
What changed
hcd_ch32_usbfs.c— asyncep[]scheduler. Modeled on the max3421 HCD:ISR-driven round-robin over a flat
ep[]array keyed by(daddr, ep_num, dir), one transaction outstanding on the engine, interrupt EPs paced tobInterval.hcd_init()enables SOFgeneration so the 1 ms SOF interrupt runs even before a device attaches; that
tick polls
DEV_ATTACH(a device present at power-up makes no DETECT edge) andthe no-response disconnect counter. Hot-plug also takes the DETECT edge as a
fast path. No application poll hook is required — the stock host examples
work unmodified.
wch_usbfs_ll.{c,h}(new) — WCH reference transaction layer. Controltransfers run through WCH's proven synchronous primitives
(
USBFSH_CtrlTransfer) + root-port reset/enable — this is what reliablyenumerates bus-powered hubs and a broad range of controllers. Derived from
WCH's
HOST_KMreference, © WCH; thin config header is MIT.ch32_usbfs_reg.h. The selector also picksch32v20x_usb.h/ch32v30x_usb.hbyCFG_TUSB_MCU; the driver and LL includeonly the selector (no hardcoded MCU header). v20x's SDK has no
RCC_USBFSCLKConfig, so the LL defers USB clock-source setup toboard_init()there (as v307 already does).
tusb_mcu.hauto-enablesCFG_TUH_WCH_USBIP_USBFSfor v307 (mirroring the v20x block). The host sourcesare wired into both the make (
family.mk) and cmake (family.cmake)builds. v307 BSP routes the USBFS IRQ to
tuh_int_handler(the vector isUSBFS_IRQHandler, notOTG_FS_IRQHandler) and bumps the linker stack; v20x'sUSBHD_IRQHandler -> tuh_int_handlerwiring is unchanged.tusb_verify.h. No-op the assertebreakon CH32 RISC-V cores: a failedTU_ASSERT/TU_VERIFYwas soft-resetting the chip (the WCH-LinkE leaves thedebug module enabled) instead of returning the error, turning recoverable
enumeration hiccups into reboot loops. Helps device-mode CH32 users too.
Testing
Hardware — CH32V307VCT6 (USBFS host PA11/PA12 → USBHS device out):
device already present at power-up.
Build —
riscv-none-elf-gcc13.2.0, make + cmake, every example, all boards:ch32v203c_r0_1v0,ch32v203g_r0_1v0,nanoch32v203ch32v307v_r1_1v0,nanoch32v305v20x runtime: not validated — needs a hardware pass (cc @verylowfreq).