From 6a221e023d6e594601512aa111f2e4aa6f740eb1 Mon Sep 17 00:00:00 2001 From: Peter Harper <77111776+peterharperuk@users.noreply.github.com> Date: Fri, 2 Jun 2023 18:52:39 +0100 Subject: [PATCH] Add dma_channel_cleanup method and use it to cleanup after pico_cyw43_driver is closed (#1372) --- src/rp2_common/hardware_dma/dma.c | 12 ++++++++++++ .../hardware_dma/include/hardware/dma.h | 19 +++++++++++++++++++ .../pico_cyw43_driver/cyw43_bus_pio_spi.c | 2 ++ 3 files changed, 33 insertions(+) diff --git a/src/rp2_common/hardware_dma/dma.c b/src/rp2_common/hardware_dma/dma.c index 5fec2107..f306def8 100644 --- a/src/rp2_common/hardware_dma/dma.c +++ b/src/rp2_common/hardware_dma/dma.c @@ -70,6 +70,18 @@ bool dma_timer_is_claimed(uint timer) { return hw_is_claimed(&_timer_claimed, timer); } +void dma_channel_cleanup(uint channel) { + check_dma_channel_param(channel); + // Disable CHAIN_TO, and disable channel, so that it ignores any further triggers + hw_write_masked( &dma_hw->ch[channel].al1_ctrl, (channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB) | (0u << DMA_CH0_CTRL_TRIG_EN_LSB), DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS | DMA_CH0_CTRL_TRIG_EN_BITS ); + // disable IRQs first as abort can cause spurious IRQs + dma_channel_set_irq0_enabled(channel, false); + dma_channel_set_irq1_enabled(channel, false); + dma_channel_abort(channel); + // finally clear the IRQ status, which may have been set during abort + dma_hw->intr = 1u << channel; +} + #ifndef NDEBUG void print_dma_ctrl(dma_channel_hw_t *channel) { diff --git a/src/rp2_common/hardware_dma/include/hardware/dma.h b/src/rp2_common/hardware_dma/include/hardware/dma.h index fc341550..65c357e9 100644 --- a/src/rp2_common/hardware_dma/include/hardware/dma.h +++ b/src/rp2_common/hardware_dma/include/hardware/dma.h @@ -891,6 +891,25 @@ static inline uint dma_get_timer_dreq(uint timer_num) { return DREQ_DMA_TIMER0 + timer_num; } +/*! \brief Performs DMA channel cleanup after use + * \ingroup hardware_dma + * + * This can be used to cleanup dma channels when they're no longer needed, such that they are in a clean state for reuse. + * IRQ's for the channel are disabled, any in flight-transfer is aborted and any outstanding interrupts are cleared. + * The channel is then clear to be reused for other purposes. + * + * \code + * if (dma_channel >= 0) { + * dma_channel_cleanup(dma_channel); + * dma_channel_unclaim(dma_channel); + * dma_channel = -1; + * } + * \endcode + * + * \param channel DMA channel + */ +void dma_channel_cleanup(uint channel); + #ifndef NDEBUG void print_dma_ctrl(dma_channel_hw_t *channel); #endif diff --git a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c index 809635d3..5afe85e6 100644 --- a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c +++ b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c @@ -163,10 +163,12 @@ void cyw43_spi_deinit(cyw43_int_t *self) { pio_sm_unclaim(bus_data->pio, bus_data->pio_sm); } if (bus_data->dma_out >= 0) { + dma_channel_cleanup(bus_data->dma_out); dma_channel_unclaim(bus_data->dma_out); bus_data->dma_out = -1; } if (bus_data->dma_in >= 0) { + dma_channel_cleanup(bus_data->dma_in); dma_channel_unclaim(bus_data->dma_in); bus_data->dma_in = -1; }