This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 8205f941d6bd4fc5aa0354cef885c7ee06a0d197 Author: Ricard Rosson <[email protected]> AuthorDate: Wed Jul 8 22:05:03 2026 +0100 arch/rp2040: set buffer AVAILABLE bit after the rest of buffer control Per the RP2040 datasheet section 4.1.2.5.1, when handing a buffer to the USB controller the AVAILABLE bit must be written after the rest of the buffer-control register (length and data PID) and after a short delay, because buffer control crosses from the system clock domain into the USB clock domain. Writing everything in a single store risks the controller acting on a stale length or PID. rp2040_update_buffer_control() wrote the whole word, AVAILABLE included, in one access. Follow the sequence the datasheet (and the Pico SDK) use: write the control word with AVAILABLE cleared, wait ~12 CPU cycles, then set AVAILABLE. The delay covers system clocks up to 12x the 48 MHz USB clock. Validated on raspberrypi-pico (RP2040) as part of bringing up cdcncm; no regression on cdcacm/usbmsc. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AHJRvWeBMTHwzpwjaUg4HW Signed-off-by: Ricard Rosson <[email protected]> --- arch/arm/src/rp2040/rp2040_usbdev.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/src/rp2040/rp2040_usbdev.c b/arch/arm/src/rp2040/rp2040_usbdev.c index 0bdc06deb29..ceb7a9e965c 100644 --- a/arch/arm/src/rp2040/rp2040_usbdev.c +++ b/arch/arm/src/rp2040/rp2040_usbdev.c @@ -473,6 +473,7 @@ static void rp2040_update_buffer_control(struct rp2040_ep_s *privep, uint32_t or_mask) { uint32_t value = 0; + int i; if (and_mask) { @@ -482,6 +483,24 @@ static void rp2040_update_buffer_control(struct rp2040_ep_s *privep, if (or_mask) { value |= or_mask; + + if (or_mask & RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL) + { + /* RP2040 datasheet 4.1.2.5.1: the AVAILABLE bit must be set + * after the rest of the buffer control register has been + * written and had time to settle across the clock domain + * crossing, or the controller may act on a stale length/PID. + * 12 CPU cycles covers system clocks up to 12x clk_usb. + */ + + putreg32(value & ~RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL, + privep->buf_ctrl); + + for (i = 0; i < 12; i++) + { + __asm__ volatile("nop"); + } + } } putreg32(value, privep->buf_ctrl);
