summaryrefslogtreecommitdiffstatshomepage
path: root/stmhal/sdcard.c
diff options
context:
space:
mode:
Diffstat (limited to 'stmhal/sdcard.c')
-rw-r--r--stmhal/sdcard.c85
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);