Skip to content

fix(esp32s3): stop tulip.wifi() crashing with "No free interrupt inputs for AES interrupt"#1018

Open
bwhitman wants to merge 2 commits into
mainfrom
claude/gallant-germain-a3c409
Open

fix(esp32s3): stop tulip.wifi() crashing with "No free interrupt inputs for AES interrupt"#1018
bwhitman wants to merge 2 commits into
mainfrom
claude/gallant-germain-a3c409

Conversation

@bwhitman

Copy link
Copy Markdown
Collaborator

Problem

A TULIP4_R11 user reports tulip.wifi("ssid", "pass") crashes every time with:

No free interrupt inputs for AES interrupt

This is a tulipcc/IDF-config bug — deterministic, reproducible for anyone on this firmware — not a user issue.

Root cause

Wi-Fi's WPA2 handshake triggers a hardware-AES operation. On the ESP32-S3, IDF's default CONFIG_MBEDTLS_AES_USE_INTERRUPT=y makes the AES driver allocate a dedicated interrupt for it (esp_aes_intr_alloc()esp_intr_alloc(ETS_AES_INTR_SOURCE, …)).

But by the time Wi-Fi starts, tulipcc has already consumed the few free low-priority interrupt slots:

  • RGB LCD — GDMA bounce buffers, refreshing continuously (esp32s3_display.c)
  • I2S audio (AMY) — continuous DMA
  • USB hostESP_INTR_FLAG_LEVEL1 (usb_host.c:526)
  • the Wi-Fi/BT MAC, which grabs several when active(True) runs

So esp_intr_alloc returns ESP_ERR_NOT_FOUND, IDF logs "No free interrupt inputs for AES interrupt", and esp_aes_intr_alloc() then calls abort() — fatal by design. Nothing in tulipcc overrode the default, and this likely surfaced with the ESP-IDF 5.4.1 bump (older IDF busy-waited instead of using an interrupt).

Fix

One line in the shared tulip/esp32s3/boards/sdkconfig.tulip (included by every ESP32-S3 board and AMYboard):

CONFIG_MBEDTLS_AES_USE_INTERRUPT=n

The hardware AES accelerator now busy-waits/polls for completion instead of needing its own interrupt — removing the allocation that was aborting. The only cost is the CPU busy-waiting during long AES ops (TLS); DMA still does the work and audio runs on its own core. This is Espressif's recommended remedy for interrupt exhaustion.

Testing

This PR exercises the exact crash path on real hardware. The AMYboard PR preview workflow rebuilds the TULIP4_R11 firmware with this fix (it triggers on tulip/esp32s3/**), and HW CI then flashes that build onto the physical Tulip and runs tulip_hwci.py --require-wifi, which calls tulip.wifi(...) on-device (tulip_hwci.py:285). Before this fix that step crashes; with it, Wi-Fi should connect and the screenshot upload should pass.

🤖 Generated with Claude Code

Wi-Fi's WPA2 handshake triggers a hardware-AES op. With IDF's default
CONFIG_MBEDTLS_AES_USE_INTERRUPT=y, the driver calls esp_intr_alloc() to grab a
dedicated AES interrupt, but the RGB LCD (GDMA bounce buffers), I2S audio, USB
host (ESP_INTR_FLAG_LEVEL1) and the Wi-Fi/BT MAC have already claimed the few
free low-priority interrupt slots on the ESP32-S3. The alloc fails with
"No free interrupt inputs for AES interrupt" and esp_aes_intr_alloc() then
calls abort() — so tulip.wifi() crashes every time on TULIP4_R11.

Set CONFIG_MBEDTLS_AES_USE_INTERRUPT=n so the hardware AES accelerator
busy-waits/polls for completion instead of needing its own interrupt. The only
cost is the CPU busy-waiting during long AES ops (TLS); DMA still does the work
and audio runs on its own core. Lands in the shared esp32s3 sdkconfig.tulip, so
it covers every ESP32-S3 board and AMYboard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown

🔌 AMYboard PR preview

Editor + flasher: https://amyboard-pr-1018.vercel.app/editor/

This preview bundles this PR's firmware — its flasher only flashes this build (not the release). Rebuilt on every push; removed when the PR closes.

The hardware CI has been kicked off and should return within a few minutes, stand by!

@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown

🌷 Tulip Web PR preview

Tulip Web: https://tulip-pr-1018.vercel.app/run/

Firmware (this PR build):

On-device OTA: tulip.upgrade(pr=1018) (needs Wi‑Fi).

Rebuilt on every push; removed when the PR closes.

…mment

The Tulip Web PR-preview comment only pointed at `tulip.upgrade(pr=N)`, which
needs Wi‑Fi — unhelpful when the PR itself is a Wi‑Fi fix and the board can't
get online. Surface direct download links to each firmware file bundled at
/firmware/, ordered full -> app -> sys with a per-file note, so a user can
USB-flash the full image (at 0x0, no Wi‑Fi) straight from the comment.

The flatten step now emits the bundled .bin filenames as an output; the comment
step renders one link per file. Web-only PRs (no firmware bundled) fall back to
the previous behavior with no firmware section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🎛️ HW CI (physical bench)

AMYboard (USB-MIDI + AMY zP → audio): ✅ PASS — flashed this PR’s firmware; all checks matched the references.

Tulip (TULIP4_R11; serial-REPL audio + WiFi screenshot): ✅ PASS — flashed this PR’s firmware; all checks matched the references.

⬇️ Artifacts: recordings · screenshot · serial logs · run logs

Self-hosted bench. Audio spectral-compared to ref/hwci_basic.wav + ref/tulip_basic.wav; Tulip screenshot pixel-compared to ref/tulip_screenshot.png. Both analog outs share one capture card, so the tests run sequentially.

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.

1 participant