Skip to content

rp2 hcd rework: epx for non-interrupt and ping-pong double buffered#3561

Merged
hathach merged 30 commits intomasterfrom
rp2040-hcd-epx
Apr 2, 2026
Merged

rp2 hcd rework: epx for non-interrupt and ping-pong double buffered#3561
hathach merged 30 commits intomasterfrom
rp2040-hcd-epx

Conversation

@hathach
Copy link
Copy Markdown
Owner

@hathach hathach commented Mar 19, 2026

Summary

Major rework for rp2 hcd (mostly) driver. Implement ping-pong double-buffered USB transfers for both device and host mode on RP2040/RP2350, with round-robin EPX scheduling for host. This significantly improves throughput.

device read/write ~ 620.1 kB/s, host read/write ~1100 kB/s

Key Changes

Ping-pong double-buffered transfers (rp2040_usb.c, rp2040_usb.h)

  • Implement double-buffered (ping-pong) mode for both device and host endpoints
  • Properly handle short packet abort for double-buffered RX (stop controller, save future data if other buffer already received)
  • Fix RP2040-E15 errata workaround for double-buffered bulk IN transfers

Host double-buffered EPX (hcd_rp2040.c)

  • Enable double-buffered mode for all host bulk/control EPX transfers
  • Single-buffered mode had race conditions with RP2040-E4 errata (status written to wrong buffer half), causing duplicate transactions on multi-packet transfers

EPX round-robin scheduling (hcd_rp2040.c)

  • All non-interrupt endpoints share a single EPX register. Round-robin scheduling switches between pending endpoints.
  • RP2350: Uses hardware STOP_EPX_ON_NAK, controller stops cleanly between packets on NAK, allowing immediate context save and switch
  • RP2040: Uses SOF-based 2-frame preemption. STOP_TRANS during active data transfer corrupts double-buffered DATA PID tracking (can't distinguish ACK vs NAK for in-flight packets).
    Instead:
    a. First SOF with pending EP: set epx_switch_request flag
    b. Any packet completion: clear flag ? data is flowing, switch happens naturally at transfer completion via xfer_complete_isr
    c. Second SOF with flag still set: endpoint is NAK-retrying, STOP_TRANS is safe ? save context and switch

EPX context save/restore for preemption (hcd_rp2040.c: epx_save_context)

  • After STOP_TRANS, determine which buffers completed on the wire using the FULL bit per RP2040 datasheet:
    • OUT: FULL=0 ? ACKed (keep PID), FULL=1 ? not ACKed (undo PID)
    • IN: FULL=1 ? data received (keep PID), FULL=0 ? no data (undo PID)
  • Properly undo PID toggles, remaining length, and buffer pointers for incomplete buffers

Critical section for EPX access (hcd_rp2040.c, rp2040_usb.h)

  • rp2usb_critical_enter/exit guards EPX active check + assignment in hcd_edpt_xfer and hcd_setup_send against ISR and cross-core races

Common refactoring (rp2040_usb.c, rp2040_usb.h)

  • Refactor buffer control and endpoint control handling shared between device and host
  • Per-buffer interrupt mode (INTERRUPT_PER_BUFFER) enables processing each buffer individually for ping-pong

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 19, 2026

Size Difference Report

Because TinyUSB code size varies by port and configuration, the metrics below represent the averaged totals across all example builds.

Note: If there is no change, only one value is shown.

Changes >1% in size

file .text .rodata .data .bss size % diff
dcd_rp2040.c 836 ➙ 838 (+2) 20 ➙ 0 (-20) 604 ➙ 764 (+160) 655 2115 ➙ 2257 (+142) +6.7%
hcd_rp2040.c 976 ➙ 2000 (+1024) 73 ➙ 17 (-56) 416 ➙ 4 (-412) 384 ➙ 321 (-63) 1849 ➙ 2342 (+493) +26.7%
rp2040_usb.c 120 ➙ 380 (+260) 75 ➙ 35 (-40) 669 ➙ 615 (-54) 4 ➙ 11 (+7) 868 ➙ 1042 (+174) +20.0%
TOTAL 1932 ➙ 3218 (+1286) 168 ➙ 52 (-116) 1689 ➙ 1383 (-306) 1043 ➙ 987 (-56) 4832 ➙ 5641 (+809) +16.7%

Changes <1% in size

file .text .bss size % diff
hcd_ch32_usbfs.c 2484 ➙ 2485 (+1) 498 2982 ➙ 2983 (+1) +0.0%
TOTAL 2484 ➙ 2485 (+1) 498 2982 ➙ 2983 (+1) +0.0%
No changes
file .text .rodata .data .bss size % diff
audio_device.c 2897 0 1260 1627 4518 +0.0%
cdc_device.c 1252 16 1106 684 1935 +0.0%
cdc_host.c 6617 487 15 1498 8327 +0.0%
dcd_ch32_usbfs.c 1473 0 0 2444 3917 +0.0%
dcd_ch32_usbhs.c 1469 0 0 448 1917 +0.0%
dcd_ci_fs.c 1925 0 0 1290 3215 +0.0%
dcd_ci_hs.c 1759 0 0 1344 2538 +0.0%
dcd_da146xx.c 3067 0 0 144 3211 +0.0%
dcd_dwc2.c 4210 25 0 265 4500 +0.0%
dcd_eptri.c 2271 0 0 259 2530 +0.0%
dcd_ft9xx.c 3276 0 0 172 3448 +0.0%
dcd_khci.c 1953 0 0 1290 3243 +0.0%
dcd_lpc17_40.c 1474 0 0 648 1798 +0.0%
dcd_lpc_ip3511.c 1463 0 0 264 1683 +0.0%
dcd_mm32f327x_otg.c 1478 0 0 1290 2768 +0.0%
dcd_msp430x5xx.c 1798 0 0 176 1974 +0.0%
dcd_musb.c 2445 0 0 160 2605 +0.0%
dcd_nrf5x.c 2918 0 0 292 3210 +0.0%
dcd_nuc120.c 1094 0 0 78 1172 +0.0%
dcd_nuc121.c 1168 0 0 101 1269 +0.0%
dcd_nuc505.c 0 0 1531 157 1688 +0.0%
dcd_rusb2.c 2919 0 0 156 3075 +0.0%
dcd_samd.c 1034 0 0 266 1300 +0.0%
dcd_samg.c 1320 0 0 72 1392 +0.0%
dcd_stm32_fsdev.c 2558 0 0 291 2849 +0.0%
dfu_device.c 777 28 712 140 916 +0.0%
dfu_rt_device.c 157 0 134 0 157 +0.0%
dwc2_common.c 602 30 0 0 618 +0.0%
ecm_rndis_device.c 1037 0 1 2858 3896 +0.0%
ehci.c 2763 0 0 6043 7597 +0.0%
fsdev_common.c 180 0 0 0 180 +0.0%
hcd_ci_hs.c 184 0 0 0 184 +0.0%
hcd_dwc2.c 4994 33 1 513 5540 +0.0%
hcd_khci.c 2442 0 0 449 2891 +0.0%
hcd_musb.c 3073 0 0 157 3230 +0.0%
hcd_pio_usb.c 262 0 240 0 502 +0.0%
hcd_rusb2.c 2923 0 0 245 3168 +0.0%
hcd_samd.c 2220 0 0 324 2544 +0.0%
hcd_stm32_fsdev.c 3287 0 1 420 3708 +0.0%
hid_device.c 1125 44 997 119 1244 +0.0%
hid_host.c 1240 0 0 1251 2491 +0.0%
hub.c 1384 8 8 30 1418 +0.0%
midi_device.c 1151 0 1007 623 1772 +0.0%
midi_host.c 1341 7 7 3635 4979 +0.0%
msc_device.c 2525 108 2286 547 3071 +0.0%
msc_host.c 1587 0 0 394 1982 +0.0%
mtp_device.c 1696 22 735 588 2292 +0.0%
ncm_device.c 1538 28 718 5843 7395 +0.0%
ohci.c 1940 0 0 2414 4353 +0.0%
printer_device.c 830 0 706 566 1394 +0.0%
rusb2_common.c 160 0 16 0 176 +0.0%
tusb.c 451 0 383 3 453 +0.0%
tusb_fifo.c 841 0 480 0 836 +0.0%
typec_stm32.c 820 8 2 12 842 +0.0%
usbc.c 420 2 20 166 608 +0.0%
usbd.c 3224 57 88 275 3564 +0.0%
usbd_control.c 538 0 484 79 616 +0.0%
usbh.c 4652 55 99 961 5734 +0.0%
usbtmc_device.c 2196 24 68 316 2544 +0.0%
vendor_device.c 641 0 534 565 1204 +0.0%
video_device.c 4443 5 1235 479 4914 +0.0%
TOTAL 113482 987 14874 45431 159095 +0.0%

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 19, 2026

MemBrowse Memory Report

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

target .text .rodata .data .bss total % diff
frdm_kl25z/msc_file_explorer 34,072 → 35,028 (+956) 7,492 → 11,076 (+3,584) 43,800 → 48,340 (+4,540) +10.4%
ea4357/msc_file_explorer 35,076 → 35,956 (+880) 15,684 → 19,780 (+4,096) 51,206 → 56,182 (+4,976) +9.7%
ch32v203c_r0_1v0/msc_file_explorer 38,784 → 39,880 (+1,096) 7,272 → 10,856 (+3,584) 48,548 → 53,228 (+4,680) +9.6%
stm32g0b1nucleo/msc_file_explorer 36,092 → 36,776 (+684) 3,068 → 3,340 (+272) 7,296 → 10,880 (+3,584) 48,380 → 52,920 (+4,540) +9.4%
stm32c071nucleo/msc_file_explorer 34,052 → 34,736 (+684) 3,072 → 3,344 (+272) 7,296 → 10,880 (+3,584) 48,388 → 52,928 (+4,540) +9.4%
feather_stm32f405/msc_file_explorer 35,984 → 36,596 (+612) 3,040 → 3,312 (+272) 7,244 → 10,828 (+3,584) 48,576 → 53,044 (+4,468) +9.2%
metro_m7_1011/msc_file_explorer 36,460 → 37,344 (+884) 15,712 → 19,808 (+4,096) 54,412 → 59,392 (+4,980) +9.2%
double_m33_express/msc_file_explorer 36,632 → 37,516 (+884) 9,888 → 13,472 (+3,584) 49,784 → 54,252 (+4,468) +9.0%
stlinkv3mini/msc_file_explorer 37,008 → 37,620 (+612) 3,040 → 3,312 (+272) 7,240 → 10,824 (+3,584) 49,816 → 54,284 (+4,468) +9.0%
portenta_c33/msc_file_explorer 34,505 → 35,389 (+884) 7,060 → 10,644 (+3,584) 49,973 → 54,441 (+4,468) +8.9%

@hathach hathach requested a review from Copilot March 19, 2026 09:54
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 refactors the RP2040 USB portable layer to make endpoint transfers operate on explicit DPRAM register pointers (EP/BUF ctrl), and reworks the host HCD to manage a pool of endpoint state structures while continuing to use the shared EPX hardware for non-interrupt transfers.

Changes:

  • Updates hw_endpoint_* APIs to take explicit ep_reg/buf_reg pointers, and renames/clarifies endpoint fields (max_packet_size, dpram_buf, pending).
  • Refactors RP2040 host HCD endpoint allocation/tracking (interrupt endpoints + shared EPX) and adjusts IRQ buffer-status handling accordingly.
  • Moves device-mode DPRAM register helper inlines out of the shared header and into dcd_rp2040.c.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/portable/raspberrypi/rp2040/rp2040_usb.h Updates endpoint struct fields and changes hw endpoint transfer API signatures to pass explicit regs.
src/portable/raspberrypi/rp2040/rp2040_usb.c Implements the new reg-parameterized endpoint/buffer helpers and updates buffer prep/sync logic to use renamed fields.
src/portable/raspberrypi/rp2040/hcd_rp2040.c Reworks host endpoint allocation/state and IRQ buffer-status routing for EPX + interrupt endpoints.
src/portable/raspberrypi/rp2040/dcd_rp2040.c Adds device-mode helper inlines for DPRAM register selection and updates calls to new hw endpoint APIs.

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

You can also share your feedback on Copilot code review. Take the survey.

@hathach hathach marked this pull request as ready for review March 31, 2026 15:03
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ab63ef436d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@hathach hathach changed the title rp2040-hcd-epx rp2 hcd rework with ping-pong double buffered and epx for non-interrupt endpoints Mar 31, 2026
@hathach hathach changed the title rp2 hcd rework with ping-pong double buffered and epx for non-interrupt endpoints rp2 hcd rework: epx for non-interrupt and ping-pong double buffered Mar 31, 2026
@rumbledethumps
Copy link
Copy Markdown

Wow. Wow. Wow. This is 10X faster on MSC-BOT!

  • FatFs throughput:
  • Write: 679 KB/s
  • Read: 559 KB/s

I used AI to apply many fixes to support my enhanced MSC driver. Here's what I'm overriding:
https://github.com/picocomputer/rp6502/tree/main/src/tinyusb_rp6502

@hathach
Copy link
Copy Markdown
Owner Author

hathach commented Apr 2, 2026

Wow. Wow. Wow. This is 10X faster on MSC-BOT!

  • FatFs throughput:
  • Write: 679 KB/s
  • Read: 559 KB/s

I used AI to apply many fixes to support my enhanced MSC driver. Here's what I'm overriding: https://github.com/picocomputer/rp6502/tree/main/src/tinyusb_rp6502

Thanks for testing, would you mind making a pr, that would be easier to review

Copy link
Copy Markdown
Owner Author

@hathach hathach left a comment

Choose a reason for hiding this comment

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

hil failed on imxrt and stm32f7 due to updated host cdc (more stress). It is not caused by this PR. probably an bug on those ports. We will fix it later.

@hathach hathach merged commit 871b843 into master Apr 2, 2026
410 of 414 checks passed
@hathach hathach deleted the rp2040-hcd-epx branch April 2, 2026 04:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants