From a96afae90f6e5d693173382561d06e583b0b5fa5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 14 May 2021 14:10:37 +1000 Subject: [PATCH] stm32/sdio: Fix case of SDIO DMA turning off mid transfer. The DMA driver will turn off DMA if it hasn't been used for an amount of time (to save power). The SDIO driver for cyw43 WLAN was not informing the DMA driver that it was using DMA and there was a chance that the DMA would turn off in the middle of an SDIO DMA transfer. The symptoms of this would be printing of SDIO error messages and a failure to communicate with the cyw43 WLAN module. This commit fixes this issue by changing the SDIO driver to use the dma_nohal_XXX API to initialise and start the DMA. Signed-off-by: Damien George --- ports/stm32/dma.c | 2 +- ports/stm32/sdio.c | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 4320315ba4..d4b41771b0 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -40,7 +40,7 @@ #define DMA_IDLE_TICK_MAX (8) // 8*8 = 64 msec #define DMA_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & DMA_SYSTICK_MASK) == 0) -#define ENABLE_SDIO (MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD) +#define ENABLE_SDIO (MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD || MICROPY_PY_NETWORK_CYW43) typedef enum { dma_id_not_defined=-1, diff --git a/ports/stm32/sdio.c b/ports/stm32/sdio.c index dfd4092577..0291e3e81d 100644 --- a/ports/stm32/sdio.c +++ b/ports/stm32/sdio.c @@ -28,6 +28,7 @@ #include "py/mperrno.h" #include "py/mphal.h" +#include "dma.h" #include "pin.h" #include "pin_static_af.h" #include "pendsv.h" @@ -382,27 +383,21 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le } #if defined(STM32F7) - DMA2->LIFCR = 0x3f << 22; - DMA2_Stream3->FCR = 0x07; // ? - DMA2_Stream3->PAR = (uint32_t)&SDMMC->FIFO; if ((uint32_t)buf & 3) { printf("sdio_transfer_cmd53: buf=%p is not aligned for DMA\n", buf); return -MP_EINVAL; } - DMA2_Stream3->M0AR = (uint32_t)buf; - DMA2_Stream3->NDTR = ((len + block_size - 1) & ~(block_size - 1)) / 4; - DMA2_Stream3->CR = 4 << 25 // channel 4 - | 1 << 23 // MBURST INCR4 - | 1 << 21 // PBURST INCR4 - | 3 << 16 // PL very high - | 2 << 13 // MSIZE word - | 2 << 11 // PSIZE word - | 1 << 10 // MINC enabled - | 0 << 9 // PINC disabled - | write << 6 // DIR mem-to-periph - | 1 << 5 // PFCTRL periph is flow controller - | 1 << 0 // EN + uint32_t dma_config = + 2 << DMA_SxCR_MSIZE_Pos // MSIZE word + | 2 << DMA_SxCR_PSIZE_Pos // PSIZE word + | write << DMA_SxCR_DIR_Pos // DIR mem-to-periph + | 1 << DMA_SxCR_PFCTRL_Pos // PFCTRL periph is flow controller ; + uint32_t dma_src = (uint32_t)buf; + uint32_t dma_dest = (uint32_t)&SDMMC->FIFO; + uint32_t dma_len = ((len + block_size - 1) & ~(block_size - 1)) / 4; + dma_nohal_init(&dma_SDIO_0, dma_config); + dma_nohal_start(&dma_SDIO_0, dma_src, dma_dest, dma_len); #else SDMMC->IDMABASE0 = (uint32_t)buf; SDMMC->IDMACTRL = SDMMC_IDMA_IDMAEN; @@ -456,6 +451,9 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le #else printf("sdio_transfer_cmd53: timeout wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC->STA, (uint)SDMMC->DCOUNT, (uint)SDMMC->DCTRL, (uint)SDMMC->IDMACTRL); #endif + if (sdmmc_dma) { + dma_nohal_deinit(&dma_SDIO_0); + } return -MP_ETIMEDOUT; } } @@ -468,6 +466,9 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le #else printf("sdio_transfer_cmd53: error=%08lx wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", sdmmc_error, write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC->STA, (uint)SDMMC->DCOUNT, (uint)SDMMC->DCTRL, (uint)SDMMC->IDMACTRL); #endif + if (sdmmc_dma) { + dma_nohal_deinit(&dma_SDIO_0); + } return -(0x1000000 | sdmmc_error); } @@ -476,6 +477,8 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le printf("sdio_transfer_cmd53: didn't transfer correct length: cur=%p top=%p\n", sdmmc_buf_cur, sdmmc_buf_top); return -MP_EIO; } + } else { + dma_nohal_deinit(&dma_SDIO_0); } return 0;