mirror of
https://github.com/apache/nuttx.git
synced 2026-10-10 15:50:23 +00:00
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 <marco.casaroli@gmail.com>
This commit is contained in:
parent
67bf46e3b0
commit
446a7d6934
1 changed files with 14 additions and 5 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue