Skip to content

rp2: use irq_add_shared_handler() for DMA_IRQ_0 instead of fixed isr_dma_0()#11054

Merged
dhalbert merged 1 commit into
adafruit:mainfrom
dhalbert:dhalbert/rp2-dma-shared-irq
Jun 12, 2026
Merged

rp2: use irq_add_shared_handler() for DMA_IRQ_0 instead of fixed isr_dma_0()#11054
dhalbert merged 1 commit into
adafruit:mainfrom
dhalbert:dhalbert/rp2-dma-shared-irq

Conversation

@dhalbert

@dhalbert dhalbert commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

This post was mostly written by Claude Code. I originally addressed this bug using Copilot, which was using ChatGPT-4.5, but Claude did a much better job. Copilot's own tests would not run. The Claude code is cleaner as well. -- @dhalbert

Addresses #9992.

Problem

ports/raspberrypi/audio_dma.c defined the DMA_IRQ_0 handler as the fixed isr_dma_0() linker symbol and dispatched to both audio and rp2pio from it. Per the Pico SDK docs, defining isr_dma_0 makes that function the permanent DMA_IRQ_0 vector and prevents other code from cooperating on the IRQ at runtime ("can cause link conflicts at runtime, and offers no runtime performance benefit"). See also the discussion in #9868.

Two concrete issues:

  1. The single handler lived entirely inside #if CIRCUITPY_AUDIOCORE, yet rp2pio relied on it — so rp2pio background DMA was silently broken when CIRCUITPY_AUDIOCORE=0.
  2. Nothing documented which DMA IRQs are shared vs. exclusive.

Change

Convert DMA_IRQ_0 to per-subsystem shared handlers:

  • audiocore (audio_dma.c) and rp2pio (StateMachine.c) each register their own handler via irq_add_shared_handler(), add it on the first channel they enable and remove it on the last, and acknowledge only their own channels.
  • Raw dma_hw->inte0 / irq_set_mask_enabled() manipulation is replaced with dma_irqn_set_channel_enabled() / irq_set_enabled().
  • picodvi's exclusive DMA_IRQ_1 handler is unchanged.
  • The DMA IRQ allocation policy (DMA_IRQ_0 shared; DMA_IRQ_1 exclusive to picodvi; DMA_IRQ_2/3 free on RP2350) is documented in common-hal/microcontroller/__init__.c.

This also fixes the CIRCUITPY_AUDIOCORE=0 case, since rp2pio now owns its own handler.

Testing

Builds clean for RP2040 (raspberry_pi_pico_w) and RP2350 (raspberry_pi_pico2).

Adds manual hardware regression tests under tests/circuitpython-manual/rp2pio/ that exercise audio DMA, rp2pio background write, and rp2pio background read sharing DMA_IRQ_0. They use only pre-existing public APIs and pass identically on firmware built before and after this change (verified on hardware).

I tested using the regressions tests listed above, and also tested on Fruit Jam using a hacked-up version of the Fruit Jam OS startup animation program. I made it repeat over and over, and also added some NeoPixel manipulations. It worked. -- @dhalbert

🤖 Generated with Claude Code

…dma_0()

audio_dma.c defined the DMA_IRQ_0 handler as the fixed isr_dma_0() linker
symbol and dispatched to both audio and rp2pio from it. Per the Pico SDK
docs this is impolite: it permanently owns the vector and prevents other
code from cooperating on the IRQ at runtime. It also meant rp2pio's DMA
completion was silently broken when CIRCUITPY_AUDIOCORE=0, since the
dispatch lived inside that guard.

Convert DMA_IRQ_0 to per-subsystem shared handlers: audiocore and rp2pio
each register their own handler with irq_add_shared_handler(), add it on
the first channel they enable and remove it on the last, and acknowledge
only their own channels. picodvi's exclusive DMA_IRQ_1 handler is
unchanged. Document the DMA IRQ allocation policy (which IRQs are shared
vs. exclusive) in common-hal/microcontroller/__init__.c.

Adds manual hardware regression tests under
tests/circuitpython-manual/rp2pio/ that exercise audio DMA, rp2pio
background write, and rp2pio background read sharing DMA_IRQ_0. They use
only pre-existing public APIs and pass identically before and after this
change.

Closes adafruit#9992

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dhalbert dhalbert requested a review from FoamyGuy June 12, 2026 21:23
@dhalbert dhalbert marked this pull request as ready for review June 12, 2026 21:25

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

Looks good to me. Thanks for the fix!

@dhalbert dhalbert merged commit 4ac2721 into adafruit:main Jun 12, 2026
172 checks passed
@dhalbert dhalbert deleted the dhalbert/rp2-dma-shared-irq branch June 12, 2026 22:57
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