stmhal/sdcard: Allow to do unaligned read-from/write-to SD card.
For example, the following code now works with a file on the SD card: f = open('test', 'rb') # test must be 1024 bytes or more in size f.seek(511) f.read(513) Also works for writing. Fixes issue #1863.
This commit is contained in:
parent
5985e41afc
commit
87981fc517
@ -24,6 +24,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "py/nlr.h"
|
#include "py/nlr.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "lib/fatfs/ff.h"
|
#include "lib/fatfs/ff.h"
|
||||||
@ -192,11 +194,6 @@ void SDIO_IRQHandler(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
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
|
// check that SD card is initialised
|
||||||
if (sd_handle.Instance == NULL) {
|
if (sd_handle.Instance == NULL) {
|
||||||
return SD_ERROR;
|
return SD_ERROR;
|
||||||
@ -204,6 +201,24 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo
|
|||||||
|
|
||||||
HAL_SD_ErrorTypedef err = SD_OK;
|
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) {
|
if (query_irq() == IRQ_STATE_ENABLED) {
|
||||||
// we must disable USB irqs to prevent MSC contention with SD card
|
// we must disable USB irqs to prevent MSC contention with SD card
|
||||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
||||||
@ -225,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);
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
|
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
|
// check that SD card is initialised
|
||||||
if (sd_handle.Instance == NULL) {
|
if (sd_handle.Instance == NULL) {
|
||||||
return SD_ERROR;
|
return SD_ERROR;
|
||||||
@ -241,6 +257,24 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n
|
|||||||
|
|
||||||
HAL_SD_ErrorTypedef err = SD_OK;
|
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) {
|
if (query_irq() == IRQ_STATE_ENABLED) {
|
||||||
// we must disable USB irqs to prevent MSC contention with SD card
|
// we must disable USB irqs to prevent MSC contention with SD card
|
||||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
||||||
|
Loading…
Reference in New Issue
Block a user