max3421: prevent USB host hang at startup#3748
Conversation
On some boards the MAX3421E doesn't report its oscillator ready after a soft reset (CHIPRES), so hcd_init() waits on USBIRQ_OSCOK forever and the host hangs at startup before any USB device can be used. Bound the wait so it proceeds after a timeout; it is a no-op where OSCOK arrives normally. Needed on the Adafruit Feather ESP32 V2 (classic ESP32) + USB Host FeatherWing, which otherwise hangs on essentially every cold boot. Relates to adafruit/circuitpython#10053.
3daa572 to
2957c10
Compare
|
@claude review |
|
Claude finished @hathach's task in 3m 4s —— View job Claude finished @hathach's taskTasks
ReviewChange is small and sound. Correctness — looks right
Minor, non-blocking suggestions
No bugs found that would block merging. |
There was a problem hiding this comment.
Pull request overview
This PR prevents a startup hang in the MAX3421E host controller init path by bounding the wait for the oscillator-ready (OSCOK) IRQ, allowing host initialization to continue even when OSCOK never latches after a soft reset.
Changes:
- Replace the unbounded OSCOK polling loop in
hcd_init()with a millisecond-based timeout (4 ms). - Add in-code rationale and datasheet timing reference to explain why proceeding after timeout is acceptable.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Wait for the oscillator to stabilize (OSCOK), bounded by a timeout. On boards where the | ||
| // MAX3421E is only soft-reset via CHIPRES (no hardware reset on the nRST pin), the OSCOK IRQ | ||
| // may never latch and would otherwise hang the host forever. The oscillator is generally | ||
| // running regardless, so proceed once the timeout elapses. |
|
Size Difference ReportBecause 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 sizeNo entries. Changes <1% in sizeNo entries. No changes
|
Hardware-in-the-loop (HIL) Test Reporthfp.json✅ 52 passed · ❌ 0 failed · ⚪ 0 skipped · blank not run
tinyusb.json✅ 339 passed · ❌ 0 failed · ⚪ 11 skipped · blank not run
|
2957c10 to
4202e1e
Compare
| // hangs if the edge is still missed on some board - the clock is running regardless. | ||
| const uint32_t oscok_start_ms = tusb_time_millis_api(); | ||
| while (!(reg_read(rhport, USBIRQ_ADDR, false) & USBIRQ_OSCOK_IRQ) && | ||
| (tusb_time_millis_api() - oscok_start_ms < TIME_TO_EXIT_SUSPEND_MS)) {} |
There was a problem hiding this comment.
@mikeysklar after checking the datasheet/programming guide, I think the issue is probably we are writing the CHIPRES too fast within ~us that reset signal isn't long enough for the osc is fully stopped to assert the bit. Would you mind trying to comment out the (tusb_time_millis_api() - oscok_start_ms < TIME_TO_EXIT_SUSPEND_MS) the delay in this loop to see if that the above delay work. We will add this anyway, since it prevent actual host hang, any other race condition

The MAX3421E can fail to report its oscillator ready after a soft reset, so
hcd_init()waits onUSBIRQ_OSCOKforever and the host hangs at startup. This bounds the wait so it proceeds instead (no-op when OSCOK arrives normally).Needed on the Adafruit Feather ESP32 V2 + USB Host FeatherWing. Relates to adafruit/circuitpython#10053; complements adafruit/circuitpython#11081.