Skip to content

raspberrypi: make tusb_time_millis_api RAM-resident; core1 calls it#11114

Merged
dhalbert merged 1 commit into
adafruit:mainfrom
mikeysklar:tusb-time-millis-api-ram
Jul 14, 2026
Merged

raspberrypi: make tusb_time_millis_api RAM-resident; core1 calls it#11114
dhalbert merged 1 commit into
adafruit:mainfrom
mikeysklar:tusb-time-millis-api-ram

Conversation

@mikeysklar

@mikeysklar mikeysklar commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Fixes the USB host regression from #11093, reported in #10243. Fixes #10243.

On RP2 boards, core1 drives the PIO-USB host and must only run code that lives in RAM, never flash. The TinyUSB update (hathach/tinyusb@3a262cb6e, from #3566) made core1 ask "what time is it?" via tusb_time_millis_api() and that function lived in flash. Core1 crashed at the first device attach, so no USB host device was ever detected.

Fix: move tusb_time_millis_api() into RAM for this port (weak shared default, PLACE_IN_ITCM override reading the timer directly).

Tested on Feather RP2040 USB Host and Fruit Jam with a flash drive: never detected on main, enumerates immediately with this change. TinyUSB submodule unchanged.

Since the TinyUSB update in adafruit#11093, tuh_task_event_ready() calls
tusb_time_millis_api() (added upstream in hathach/tinyusb@3a262cb6e to
report a due deferred call_after callback).

On RP2 boards, usb_host polls tuh_task_event_ready() from core1's
PIO-USB frame loop (common-hal/usb_host/Port.c). tuh_task_event_ready()
is deliberately placed in RAM by link-rp2*.ld, and everything it calls
must be RAM-resident: on RP2350 core1 sets an MPU region that makes
flash execute-never, and on RP2040 flash may be unavailable while core0
writes to it. The shared tusb_time_millis_api() implementation
(supervisor_ticks_ms32) lives in flash, so core1 died at the first
device attach (the first time call_after was pending) and the PIO-USB
bus went silent: no USB host device was ever detected. Fixes the
regression reported in adafruit#10243.

Make the shared implementation MP_WEAK and override it in the
raspberrypi port with a PLACE_IN_ITCM function that reads the timer
directly. time_us_32() >> 10 yields ~1.024 ms units rather than exact
milliseconds, which is fine because TinyUSB only uses this API for
relative delay arithmetic and every use goes through the same function.

Tested on Feather RP2040 USB Host and Fruit Jam with a USB flash drive:
both fail to enumerate on current main and enumerate immediately with
this change, with the TinyUSB submodule pristine at 5453ed09f.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@dhalbert dhalbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Great, thank you for the quick fix!

@hathach FYI. I wonder if there's any way to detect this at compile or link time.

@dhalbert dhalbert merged commit 938716c into adafruit:main Jul 14, 2026
665 checks passed
@mikeysklar

mikeysklar commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

I know this wasn't directed to me, but yes you can detect this at link time. I'll submit a PR for it. The script picked up two other lives in flash, but needs to be moved to RAM scenarios to run on core1.

  • Pico-PIO-USB calc_usb_crc16
  • queue-send mutex contended path
    • hcd_event_handlertu_fifo_writemutex_enter_block_until
      • time_us_64 / best_effort_wfe_or_timeout

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.

USB Host Issues Using Gamepads

2 participants