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; } HAL_SD_ErrorTypedef err = SD_OK; if (query_irq() == IRQ_STATE_ENABLED) { dma_init(&sd_rx_dma, DMA_STREAM_SDIO_RX, &dma_init_struct_sdio, DMA_CHANNEL_SDIO_RX, DMA_PERIPH_TO_MEMORY, &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); if (err == SD_OK) { // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckReadOperation(&sd_handle, 100000000); } dma_deinit(sd_handle.hdmarx); sd_handle.hdmarx = NULL; } else { err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); } return err; }
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; } 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, &SDMMC_RX_DMA, &sd_handle); sd_handle.hdmarx = &sd_rx_dma; // make sure cache is flushed and invalidated so when DMA updates the RAM // from reading the peripheral the CPU then reads the new data MP_HAL_CLEANINVALIDATE_DCACHE(dest, num_blocks * SDCARD_BLOCK_SIZE); err = HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); if (err == SD_OK) { // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckReadOperation(&sd_handle, 100000000); } dma_deinit(&SDMMC_RX_DMA); sd_handle.hdmarx = NULL; restore_irq_pri(basepri); } else { 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_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; } // We must disable IRQs because the SDIO peripheral has a small FIFO // buffer and we can't let it fill up in the middle of a read. // This will not be needed when SD uses DMA for transfer. mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); HAL_SD_ErrorTypedef err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); MICROPY_END_ATOMIC_SECTION(atomic_state); return err; }