diff options
Diffstat (limited to 'stmhal/sdcard.c')
-rw-r--r-- | stmhal/sdcard.c | 85 |
1 files changed, 53 insertions, 32 deletions
diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c index 59fe3fac82..32c9df60a2 100644 --- a/stmhal/sdcard.c +++ b/stmhal/sdcard.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#include <string.h> + #include "py/nlr.h" #include "py/runtime.h" #include "lib/fatfs/ff.h" @@ -63,6 +65,11 @@ #define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV +#elif defined(MCU_SERIES_L4) + +// The L4 series is not supported +#error Unsupported Processor + #endif // TODO: Since SDIO is fundamentally half-duplex, we really only need to @@ -77,22 +84,6 @@ static SD_HandleTypeDef sd_handle; static DMA_HandleTypeDef sd_rx_dma, sd_tx_dma; -// Parameters to dma_init() for SDIO tx and rx. -static const DMA_InitTypeDef dma_init_struct_sdio = { - .Channel = 0, - .Direction = 0, - .PeriphInc = DMA_PINC_DISABLE, - .MemInc = DMA_MINC_ENABLE, - .PeriphDataAlignment = DMA_PDATAALIGN_WORD, - .MemDataAlignment = DMA_MDATAALIGN_WORD, - .Mode = DMA_PFCTRL, - .Priority = DMA_PRIORITY_VERY_HIGH, - .FIFOMode = DMA_FIFOMODE_ENABLE, - .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, - .MemBurst = DMA_MBURST_INC4, - .PeriphBurst = DMA_PBURST_INC4, -}; - void sdcard_init(void) { GPIO_InitTypeDef GPIO_Init_Structure; @@ -203,11 +194,6 @@ void SDIO_IRQHandler(void) { } mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { - // check that dest pointer is aligned on a 4-byte boundary - if (((uint32_t)dest & 3) != 0) { - return SD_ERROR; - } - // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; @@ -215,12 +201,29 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo HAL_SD_ErrorTypedef err = SD_OK; + // check that dest pointer is aligned on a 4-byte boundary + uint8_t *orig_dest = NULL; + uint32_t saved_word; + if (((uint32_t)dest & 3) != 0) { + // Pointer is not aligned so it needs fixing. + // We could allocate a temporary block of RAM (as sdcard_write_blocks + // does) but instead we are going to use the dest buffer inplace. We + // are going to align the pointer, save the initial word at the aligned + // location, read into the aligned memory, move the memory back to the + // unaligned location, then restore the initial bytes at the aligned + // location. We should have no trouble doing this as those initial + // bytes at the aligned location should be able to be changed for the + // duration of this function call. + orig_dest = dest; + dest = (uint8_t*)((uint32_t)dest & ~3); + saved_word = *(uint32_t*)dest; + } + if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - dma_init(&sd_rx_dma, DMA_STREAM_SDIO_RX, &dma_init_struct_sdio, - DMA_CHANNEL_SDIO_RX, DMA_PERIPH_TO_MEMORY, &sd_handle); + dma_init(&sd_rx_dma, &dma_SDIO_0_RX, &sd_handle); sd_handle.hdmarx = &sd_rx_dma; err = HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); @@ -229,7 +232,7 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo err = HAL_SD_CheckReadOperation(&sd_handle, 100000000); } - dma_deinit(sd_handle.hdmarx); + dma_deinit(&dma_SDIO_0_RX); sd_handle.hdmarx = NULL; restore_irq_pri(basepri); @@ -237,15 +240,16 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); } + if (orig_dest != NULL) { + // move the read data to the non-aligned position, and restore the initial bytes + memmove(orig_dest, dest, num_blocks * SDCARD_BLOCK_SIZE); + memcpy(dest, &saved_word, orig_dest - dest); + } + return err; } mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { - // check that src pointer is aligned on a 4-byte boundary - if (((uint32_t)src & 3) != 0) { - return SD_ERROR; - } - // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; @@ -253,12 +257,29 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n HAL_SD_ErrorTypedef err = SD_OK; + // check that src pointer is aligned on a 4-byte boundary + if (((uint32_t)src & 3) != 0) { + // pointer is not aligned, so allocate a temporary block to do the write + uint8_t *src_aligned = m_new_maybe(uint8_t, SDCARD_BLOCK_SIZE); + if (src_aligned == NULL) { + return SD_ERROR; + } + for (size_t i = 0; i < num_blocks; ++i) { + memcpy(src_aligned, src + i * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE); + err = sdcard_write_blocks(src_aligned, block_num + i, 1); + if (err != SD_OK) { + break; + } + } + m_del(uint8_t, src_aligned, SDCARD_BLOCK_SIZE); + return err; + } + if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - dma_init(&sd_tx_dma, DMA_STREAM_SDIO_TX, &dma_init_struct_sdio, - DMA_CHANNEL_SDIO_TX, DMA_MEMORY_TO_PERIPH, &sd_handle); + dma_init(&sd_tx_dma, &dma_SDIO_0_TX, &sd_handle); sd_handle.hdmatx = &sd_tx_dma; err = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks); @@ -266,7 +287,7 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckWriteOperation(&sd_handle, 100000000); } - dma_deinit(sd_handle.hdmatx); + dma_deinit(&dma_SDIO_0_TX); sd_handle.hdmatx = NULL; restore_irq_pri(basepri); |