Skip to content

fix(dcd_ch32_usbfs): fix dropped bulk OUT packets by properly re-arming EP_RX_CTRL state#3622

Merged
HiFiPhile merged 16 commits into
hathach:masterfrom
mickabrig7:master
May 23, 2026
Merged

fix(dcd_ch32_usbfs): fix dropped bulk OUT packets by properly re-arming EP_RX_CTRL state#3622
HiFiPhile merged 16 commits into
hathach:masterfrom
mickabrig7:master

Conversation

@mickabrig7
Copy link
Copy Markdown
Contributor

When stress-testing a custom Vendor interface with lots of fast bulk transfers on CH32V30x (which use the USBFS controller), I noticed that a lot of data was dropped because tud_vendor_rx_cb() would not always fire.

After investigating, it seemed like dcd_ch32_usbfs wasn't updating the EP_RX_CTRL register after a transfer completed or when a new one was queued.

update_out() now properly sets EP_RX_CTRL to ACK or NAK for all endpoints based on transfer state, and dcd_edpt_xfer() explicitly re-enables ACK when re-queuing an OUT transfer.
Bulk transfers now complete reliably without data loss or missed callbacks.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

MemBrowse Memory Report

Top 10 targets by memory change (%) (out of 2305 targets) View Project Dashboard →

target .text .rodata .data .bss total % diff
ch32v307v_r1_1v0/net_lwip_webserver 52,120 → 56,304 (+4,184) 18,276 → 26,492 (+8,216) 73,388 → 85,792 (+12,404) +16.9%
ch32v307v_r1_1v0/dfu_runtime 8,908 → 9,360 (+452) 1,056 → 1,092 (+36) 12,556 → 13,048 (+492) +3.9%
ch32v307v_r1_1v0/hid_generic_inout 10,032 → 10,500 (+468) 1,260 → 1,296 (+36) 13,884 → 14,388 (+504) +3.6%
ch32v307v_r1_1v0/hid_multiple_interface 10,852 → 11,316 (+464) 1,136 → 1,172 (+36) 14,580 → 15,084 (+504) +3.5%
ch32v307v_r1_1v0/hid_boot_interface 10,876 → 11,340 (+464) 1,136 → 1,172 (+36) 14,604 → 15,108 (+504) +3.5%
ch32v307v_r1_1v0/hid_composite 11,224 → 11,692 (+468) 1,160 → 1,196 (+36) 14,976 → 15,484 (+508) +3.4%
ch32f205r-r0/dfu_runtime 7,580 → 7,928 (+348) 1,416 → 1,452 (+36) 11,440 → 11,824 (+384) +3.4%
ch32f205r-r0/hid_generic_inout 8,588 → 8,944 (+356) 1,620 → 1,656 (+36) 12,480 → 12,872 (+392) +3.1%
ch32v307v_r1_1v0/audio_test 12,508 → 12,984 (+476) 1,712 → 1,748 (+36) 16,844 → 17,360 (+516) +3.1%
ch32f205r-r0/hid_multiple_interface 9,200 → 9,556 (+356) 1,496 → 1,532 (+36) 13,140 → 13,532 (+392) +3.0%

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR targets reliability of bulk OUT transfers on WCH CH32 USBFS device controller by ensuring OUT endpoints are properly re-armed via EP_RX_CTRL, preventing missed receive callbacks and dropped packets during sustained high-rate transfers.

Changes:

  • Update update_out() to program EP_RX_CTRL (ACK/NAK) for non-EP0 OUT endpoints based on whether an OUT transfer is still active.
  • Update dcd_edpt_xfer() to explicitly re-enable OUT endpoint RX ACK when a new OUT transfer is queued.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 118 to 124

if (ep == 0) {
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
} else {
EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) |
(xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK);
}
Comment thread src/portable/wch/dcd_ch32_usbfs.c Outdated
if (dir == TUSB_DIR_IN) {
update_in(rhport, ep, true);
} else {
EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_ACK;
@HiFiPhile
Copy link
Copy Markdown
Collaborator

Thank you, I think we should also remove ACK enablement in dcd_edpt_open()

I don't have CH30V20x at hand but surprised by their USB IP implementation, if CPU load is high setting NAK after packet received can still missing data.

@HiFiPhile
Copy link
Copy Markdown
Collaborator

HiFiPhile commented May 19, 2026

I bought a nanoch32v203 (and v305), I do observe OUT EP send ACK blindly without checking if data is actually read 😱 😱

Captured with CDC example:
image

I think to fix it correctly we need to disable AUTO_TOG and only toggle the PID once data is actually received.

HiFiPhile added 7 commits May 22, 2026 15:23
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
OUT is still buggy

Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
HiFiPhile added 3 commits May 23, 2026 13:00
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
HiFiPhile added 4 commits May 23, 2026 17:45
Signed-off-by: HiFiPhile <admin@hifiphile.com>
It would casue race condition, SETUP packet is always acked.

Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Refactor the driver to follow USBFS style for easier maintenance.
Replace the old packet/response helpers with explicit queue and update paths for IN and OUT transfers.
Introduce transfer validity tracking and per-endpoint data toggle state.
Reset toggle state on init, close-all, endpoint close, clear-stall, and bus reset.
Initialize endpoint controls consistently in NAK + TOG_0 mode.
Tighten EP0 setup/status handling and route transfer IRQ processing through the transfer-flag path.
Stop enabling ISO_ACT in INT_EN and clear unhandled interrupt flags explicitly.

Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
@HiFiPhile
Copy link
Copy Markdown
Collaborator

I've included a large transfer reliability patch for both USBFS/USBHS driver.

  • Resolve race condition on control transfer status OUT / next SETUP
  • Spurious transfer when EP is not ready

Tested on CH32V203/CH32V305 with audio_4_channel_mic, cdc_dual_ports, dfu, cdc_msc, net_lwip_webserver examples.

Concurrent ISO transfer is not working yet, eg uac2_headset

@HiFiPhile HiFiPhile merged commit 65fb8df into hathach:master May 23, 2026
290 of 293 checks passed
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.

3 participants