Skip to content

fix(isr): prevent WiFi blob from clearing unowned INTENABLE bits#46

Merged
deadprogram merged 2 commits into
mainfrom
irq-fix
Jun 13, 2026
Merged

fix(isr): prevent WiFi blob from clearing unowned INTENABLE bits#46
deadprogram merged 2 commits into
mainfrom
irq-fix

Conversation

@deadprogram

@deadprogram deadprogram commented Jun 5, 2026

Copy link
Copy Markdown
Member

espradio_ints_off passed the blob's cpu_int mask straight to INTENABLE, which could clear bits TinyGo owns (bit 10 = GPIO, bit 9 = timer alarm). After WiFi init, GPIO SetInterrupt callbacks would silently stop firing.

  • ints_on/ints_off (esp32s3) now only touch ESPRADIO_WIFI_CPU_INT (bit 12)
  • add espradio_mark_wifi_isr_slot() to track slots registered via set_intr
  • espradio_call_wifi_isr() iterates only those tracked slots instead of calling all 32

Should address #40

@deadprogram

Copy link
Copy Markdown
Member Author

@jwetzell PTAL

@jwetzell

jwetzell commented Jun 9, 2026

Copy link
Copy Markdown

@deadprogram the interrupt in my example in #40 still does not function properly with this branch

testing using an esp32s3

espradio_ints_off passed the blob's cpu_int mask straight to INTENABLE,
which could clear bits TinyGo owns (bit 10 = GPIO, bit 9 = timer alarm).
After WiFi init, GPIO SetInterrupt callbacks would silently stop firing.

- ints_on/ints_off (esp32s3) now only touch ESPRADIO_WIFI_CPU_INT (bit 12)
- add espradio_mark_wifi_isr_slot() to track slots registered via set_intr
- espradio_call_wifi_isr() iterates only those tracked slots instead of
  calling all 32

Should address #40

Signed-off-by: deadprogram <ron@hybridgroup.com>
@deadprogram

Copy link
Copy Markdown
Member Author

@jwetzell I made some additional changes and tested on both C3 and S3 boards using your reproducer. This time is working!

Three sources of GPIO interrupt loss after WiFi init:

1. ROM ets_isr_mask bypass: WiFi blob clears INTENABLE bits via ROM
   calls that bypass the OS adapter. Fix: snapshot INTENABLE at the
   start of schedOnce(), OR it back in espradio_wifi_unmask() so no
   TinyGo-owned bits (GPIO=bit10 on S3, bit6 on C3) are lost.

2. Interrupt matrix corruption: espradio_set_intr (S3) called
   intr_matrix_set for every blob-requested source, risking overwrite
   of the GPIO→CPU-int routing. Fix: make set_intr a no-op for routing
   (same as C3); prewire in espradio_prewire_wifi_interrupts() only.
   Restore GPIO source routing in espradio_wifi_unmask() each cycle.

3. Missed edge + stuck PS.INTLEVEL: TinyGo GC's tinygo_scanCurrentStack
   uses rsil/3 to flush Xtensa register windows; a goroutine yield
   during the recursive spill leaves PS.INTLEVEL=3 permanently, blocking
   all level-1 interrupts. Additionally, if a button edge arrived while
   INTENABLE[10]=0, the Xtensa edge latch missed it (GPIO_STATUS set but
   INTERRUPT[10]=0). Fix: espradio_wifi_unmask() lowers PS.INTLEVEL to 0
   and toggles the GPIO interrupt matrix routing (disconnect/reconnect
   with memw readback fence) to synthesize a new rising edge so any
   missed GPIO events are replayed.

Fixes #40.

Signed-off-by: deadprogram <ron@hybridgroup.com>
@deadprogram

Copy link
Copy Markdown
Member Author

Removed some debug code and rebased/force pushed.

@deadprogram

Copy link
Copy Markdown
Member Author

Merging because we need this fix for some further changes.

@deadprogram deadprogram merged commit 151d2a9 into main Jun 13, 2026
1 check passed
@deadprogram deadprogram deleted the irq-fix branch June 13, 2026 05:55
@jwetzell

Copy link
Copy Markdown

sorry, yeah couldn't get around to testing it until now but does indeed fix the interrupt issue!

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.

2 participants