Skip to content

cyw43: dma_channel_abort interacting weirdly with chained DMA #2206

@Gadgetoid

Description

@Gadgetoid

I've been chasing an issue with wireless in our MicroPython builds, and after confirming that it's related to our DMA/PIO drivers for LED matrix displays came up with a reproduction: micropython/micropython#16627

This reproduction reliably shows that setting up chained DMA (yes it's in MicroPython but my original code was a C module) upsets the cyw43 driver. This only happens on Pico 2 W/RP2350 (possibly related to DMA errata E5?) and the same (original C) code has worked on RP2040 since the original Pico W launched.

@MichaelBell rolled with this and found that adding asm volatile (" nop\n nop\n nop " ); after calls to dma_channel_abort in cyw43_bus_pio_spi.c would somehow fix this, coming up with the following patch:

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 bcc7284..1c6bd84 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
@@ -260,6 +260,7 @@ int cyw43_spi_transfer(cyw43_int_t *self, const uint8_t *tx, size_t tx_length, u
         pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_jmp(bus_data->pio_offset));
         dma_channel_abort(bus_data->dma_out);
         dma_channel_abort(bus_data->dma_in);
+        asm volatile (" nop\n nop\n nop " );
 
         dma_channel_config out_config = dma_channel_get_default_config(bus_data->dma_out);
         channel_config_set_bswap(&out_config, true);
@@ -301,6 +302,7 @@ int cyw43_spi_transfer(cyw43_int_t *self, const uint8_t *tx, size_t tx_length, u
         pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_out(pio_y, 32));
         pio_sm_exec(bus_data->pio, bus_data->pio_sm, pio_encode_jmp(bus_data->pio_offset));
         dma_channel_abort(bus_data->dma_out);
+        asm volatile (" nop\n nop\n nop " );
 
         dma_channel_config out_config = dma_channel_get_default_config(bus_data->dma_out);
         channel_config_set_bswap(&out_config, true);

We don't have a good sense for exactly what is happening, and it seems to vary between compilers (breaks as expected with GCC 14.2.1), but it's clear that it's a uniquely RP2350 problem and that a mitigation should be possible in Pico SDK.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions