summaryrefslogtreecommitdiffstatshomepage
path: root/stmhal/sdcard.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2016-05-13 14:45:40 +0100
committerDamien George <damien.p.george@gmail.com>2016-05-13 14:45:40 +0100
commit87981fc517ff1fafd1513af3e26df39bf57e6978 (patch)
tree43a6518bb0e1e6e522d350e1767ab3a83316e481 /stmhal/sdcard.c
parent5985e41afca9d440dd932ab512c23dbc1e002499 (diff)
downloadmicropython-87981fc517ff1fafd1513af3e26df39bf57e6978.tar.gz
micropython-87981fc517ff1fafd1513af3e26df39bf57e6978.zip
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.
Diffstat (limited to 'stmhal/sdcard.c')
-rw-r--r--stmhal/sdcard.c54
1 files changed, 44 insertions, 10 deletions
diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c
index ae98c328af..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"
@@ -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) {
- // 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;
@@ -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;
+ // 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);
@@ -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);
}
+ 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;
@@ -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;
+ // 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);