Browse Source

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 <damien@micropython.org>
pull/7290/head
Damien George 4 years ago
parent
commit
a96afae90f
  1. 2
      ports/stm32/dma.c
  2. 35
      ports/stm32/sdio.c

2
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,

35
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;

Loading…
Cancel
Save