Skip to content

max3421e: don't run tuh_task() while the shared SPI bus is held - #11695

Merged
mikeysklar merged 1 commit into
adafruit:mainfrom
jedgarpark:max3421e-shared-spi
Oct 30, 2026
Merged

mikeysklar merged 1 commit into
adafruit:mainfrom
jedgarpark:max3421e-shared-spi

Conversation

@jedgarpark

Copy link
Copy Markdown

Fixes #11692.

tuh_max3421_spi_cs_api() can't wait for an SPI bus that other code holds, so it skips the transfer silently. TinyUSB then acts on register values it never read. When the dropped write is the one that starts a transfer, busy_lock stays set with no transfer-done interrupt to clear it, and the host stalls until reset. Python code, a display refresh or an SD card read can all run background tasks while holding the bus, so tuh_task() can run at any of those times.

This adds max3421e_spi_busy(), which try-locks the MAX3421E's bus and releases it again. usb_background() checks it before tuh_task(), and when the bus is held it reschedules itself instead, so the host task only runs when its transfers can go through. Boards without CIRCUITPY_MAX3421E are unchanged.

Testing:

  • @mikeysklar's debugger runs on a Feather RP2350 under a 4 MHz SPI write load: unpatched, stuck 9/15 with 1 to 3 dropped transfers in each stuck run; patched, stuck 0/10 with no dropped transfers (details in the issue).
  • Feather RP2350 + MAX3421E FeatherWing sharing board.SPI() with an HX8357 TFT and an SD card, enumerating and flashing a USB MIDI device over many runs.

🤖 Generated with Claude Code

tuh_max3421_spi_cs_api() can't wait for a bus that other code holds, so
it skips the transfer. TinyUSB then acts on register values it never
read; a dropped transfer start leaves busy_lock set with no
transfer-done interrupt to clear it, and the host stalls until reset.

usb_background() now checks max3421e_spi_busy() first and reschedules
itself when the bus is held, so tuh_task() only runs when its transfers
can go through.

Fixes adafruit#11692

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@mikeysklar

Copy link
Copy Markdown
Collaborator

I moved some hardware around to free up a Feather doubler and I'm running some tests just to be safe. Will get back to you this afternoon.

13/34 trials, about 27 min 00 s left
Estimated finish 14:13

Build  Test       Done  Stuck  Drops  Errs  HF
Parent Host alone  2/2      0      0     0   0
Parent Real SD    10/10    10     66     0   0
Parent SPI load    1/5      0      0     0   0
PR     Host alone  0/2      0      -     0   0
PR     Real SD     0/10     0      -     0   0
PR     SPI load    0/5      0      -     0   0

@mikeysklar mikeysklar 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.

Tested this PR and its parent on a Feather RP2350 with real SD reads.

Build Test Stuck until reset
Parent Host alone 0/2
Parent Real SD 10/10
Parent SPI load 2/5
PR Host alone 0/2
PR Real SD 0/10
PR SPI load 0/5

No hard fault. Not tested with SD-over-USB on, or on other ports.

@mikeysklar
mikeysklar merged commit 1eed2ea into adafruit:main Oct 30, 2026
696 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.

max3421e: USB host drops SPI transfers when a display or SD card shares the bus (no enumeration, hard fault)

2 participants