This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 446a7d6934730dfe261b9f1ae359de603008593b
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Aug 10 15:33:22 2026 +0200

    arch/arm/rp23xx: Clear the DMA callback before invoking it.
    
    The completion handler did:
    
        dmach->callback(...);
        dmach->callback = NULL;     /* after the call */
    
    so a callback that registers itself again -- which is the only way for a
    driver to keep a channel running continuously -- has that registration
    wiped the moment it returns.  The channel transfers one more block and
    then goes deaf, with no error raised anywhere and nothing in the
    registers to say why.  A PWM audio driver hit this and worked around it
    by restarting from a thread instead, which put a millisecond of silence
    into every buffer boundary.
    
    Lift the callback and its argument out first and clear them before the
    call.  One-shot behaviour is unchanged for every existing user, since
    none of them re-register from inside the call; the difference is only
    that one which does now survives.
    
    Tested on a Pimoroni Pico Plus 2 W (pimoroni-pico-plus-2-w:nsh) with a
    local test: a memory-to-memory transfer whose callback starts the next
    one, 100 times.  Master gives 1 completion of 100; this change gives 100.
    The existing users (SPI, I2S, CYW43439, WS2812) do not start a transfer
    from inside the callback, so they do not change.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 arch/arm/src/rp23xx/rp23xx_dmac.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/arch/arm/src/rp23xx/rp23xx_dmac.c 
b/arch/arm/src/rp23xx/rp23xx_dmac.c
index 942fbbecc25..6936f6d8b28 100644
--- a/arch/arm/src/rp23xx/rp23xx_dmac.c
+++ b/arch/arm/src/rp23xx/rp23xx_dmac.c
@@ -103,6 +103,8 @@ static struct dma_channel_s g_dmach[RP23XX_DMA_NCHANNELS];
 static int rp23xx_dmac_interrupt(int irq, void *context, void *arg)
 {
   struct dma_channel_s *dmach;
+  dma_callback_t callback;
+  void *cbarg;
   int result = OK;
   unsigned int ch;
   uint32_t stat;
@@ -130,15 +132,22 @@ static int rp23xx_dmac_interrupt(int irq, void *context, 
void *arg)
 
       dmach = &g_dmach[ch];
 
+      /* Clear the registration before the call, so that the callback can
+       * register itself again.
+       */
+
+      callback = dmach->callback;
+      cbarg    = dmach->arg;
+
+      dmach->callback = NULL;
+      dmach->arg      = NULL;
+
       /* Call the DMA completion callback */
 
-      if (dmach->callback)
+      if (callback)
         {
-          dmach->callback((DMA_HANDLE)dmach, result, dmach->arg);
-          dmach->callback = NULL;
+          callback((DMA_HANDLE)dmach, result, cbarg);
         }
-
-      dmach->arg = NULL;
     }
 
   return OK;

Reply via email to