← index #8431PR #18914
Related · high · value 0.202
QUERY · ISSUE

rp2: No way to avoid conflicting claims on DMA channels

openby nickovsopened 2022-03-20updated 2023-03-04
port-rp2

At the moment there is no way on the RP2 port to write properly modular code that makes use of DMA without running the risk of two modules both trying to use the same channel. The underlying Raspberry Pi Pico C/C++ SDK provides a library function dma_claim_unused_channel() to deal with exactly this problem, but it is not exposed in the MicroPython. The lack of support for this is an impediment to writing anything other than trivial code that uses DMA.

The rp2.DMA class implemented in #7641 fixes this issue and at the same time provides a high level, Pythonic interface to the DMA hardware. It would be really helpful if this PR could be merged.

CANDIDATE · PULL REQUEST

rp2: Disable DMA IRQ before clearing handler function.

mergedby projectgusopened 2026-03-11updated 2026-03-18
bugport-rp2

Summary

WIthout this fix, soft reset will remove the IRQ handler before the finaliser for the DMA object(s) run and trigger IRQs if the channel is still active.

Closes #18765

This work was funded through GitHub Sponsors.

Testing

Ran the test case supplied with the issue and verified it crashes on RPI_PICO without this fix, and doesn't crash with the fix. I wasn't able to reproduce the problem on RPI_PICO2_W, so possibly it's RP2040-only (was reported on RP2040).

The stack trace shows the unhandled IRQ was to blame:

Program received signal SIGTRAP, Trace/breakpoint trap.
unhandled_user_irq_num_in_r0 () at /home/gus/ry/george/micropython/lib/pico-sdk/src/rp2_common/pico_crt0/crt0.S:327
327         bkpt #0
(gdb) bt
#0  unhandled_user_irq_num_in_r0 () at /home/gus/ry/george/micropython/lib/pico-sdk/src/rp2_common/pico_crt0/crt0.S:327
#1  <signal handler called>
#2  dma_channel_unclaim (channel=0) at /home/gus/ry/george/micropython/lib/pico-sdk/src/rp2_common/hardware_dma/dma.c:36
#3  0x10030f30 in rp2_dma_close (self_in=0x20005160) at /home/gus/ry/george/micropython/ports/rp2/rp2_dma.c:446
#4  0x100116fe in fun_builtin_1_call (self_in=0x1004b3c4 <rp2_dma_close_obj>, n_args=<optimized out>, n_kw=<optimized out>, 
    args=0x20041f4c) at /home/gus/ry/george/micropython/py/objfun.c:70
#5  0x1001a1c4 in mp_call_function_n_kw (fun_in=0x1004b3c4 <rp2_dma_close_obj>, n_args=1, n_kw=0, args=0x20041f4c)
    at /home/gus/ry/george/micropython/py/runtime.c:712
#6  0x1001a25a in mp_call_function_1 (fun=fun@entry=0x1004b3c4 <rp2_dma_close_obj>, arg=<optimized out>, arg@entry=0x20005160)
    at /home/gus/ry/george/micropython/py/runtime.c:690
#7  0x1001b0d6 in mp_call_function_1_protected (fun=0x1004b3c4 <rp2_dma_close_obj>, arg=0x20005160)
    at /home/gus/ry/george/micropython/py/runtime_utils.c:33
#8  0x10009428 in gc_sweep_run_finalisers () at /home/gus/ry/george/micropython/py/gc.c:606

I have not added a regression test for this as I think there's no "clean" way to trigger a soft reset inside a test, the test would need to rely on the rp2 crashing after the test was "done" which seems a bit iffy.

Trade-offs and Alternatives

As there's a finite number of channels, we could conceivably track them statically and clean them up from rp2_deinit() instead of waiting for finalisers to come and clean them up. However, I think relying on finalisers is OK now that the interrupt is disabled before we reach this point.

Generative AI

I did not use generative AI tools when creating this PR.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied