Skip to content

Commit 87981fc

Browse files
committed
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 adafruit#1863.
1 parent 5985e41 commit 87981fc

1 file changed

Lines changed: 44 additions & 10 deletions

File tree

stmhal/sdcard.c

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <string.h>
28+
2729
#include "py/nlr.h"
2830
#include "py/runtime.h"
2931
#include "lib/fatfs/ff.h"
@@ -192,18 +194,31 @@ void SDIO_IRQHandler(void) {
192194
}
193195

194196
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
195-
// check that dest pointer is aligned on a 4-byte boundary
196-
if (((uint32_t)dest & 3) != 0) {
197-
return SD_ERROR;
198-
}
199-
200197
// check that SD card is initialised
201198
if (sd_handle.Instance == NULL) {
202199
return SD_ERROR;
203200
}
204201

205202
HAL_SD_ErrorTypedef err = SD_OK;
206203

204+
// check that dest pointer is aligned on a 4-byte boundary
205+
uint8_t *orig_dest = NULL;
206+
uint32_t saved_word;
207+
if (((uint32_t)dest & 3) != 0) {
208+
// Pointer is not aligned so it needs fixing.
209+
// We could allocate a temporary block of RAM (as sdcard_write_blocks
210+
// does) but instead we are going to use the dest buffer inplace. We
211+
// are going to align the pointer, save the initial word at the aligned
212+
// location, read into the aligned memory, move the memory back to the
213+
// unaligned location, then restore the initial bytes at the aligned
214+
// location. We should have no trouble doing this as those initial
215+
// bytes at the aligned location should be able to be changed for the
216+
// duration of this function call.
217+
orig_dest = dest;
218+
dest = (uint8_t*)((uint32_t)dest & ~3);
219+
saved_word = *(uint32_t*)dest;
220+
}
221+
207222
if (query_irq() == IRQ_STATE_ENABLED) {
208223
// we must disable USB irqs to prevent MSC contention with SD card
209224
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
@@ -225,22 +240,41 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo
225240
err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks);
226241
}
227242

243+
if (orig_dest != NULL) {
244+
// move the read data to the non-aligned position, and restore the initial bytes
245+
memmove(orig_dest, dest, num_blocks * SDCARD_BLOCK_SIZE);
246+
memcpy(dest, &saved_word, orig_dest - dest);
247+
}
248+
228249
return err;
229250
}
230251

231252
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
232-
// check that src pointer is aligned on a 4-byte boundary
233-
if (((uint32_t)src & 3) != 0) {
234-
return SD_ERROR;
235-
}
236-
237253
// check that SD card is initialised
238254
if (sd_handle.Instance == NULL) {
239255
return SD_ERROR;
240256
}
241257

242258
HAL_SD_ErrorTypedef err = SD_OK;
243259

260+
// check that src pointer is aligned on a 4-byte boundary
261+
if (((uint32_t)src & 3) != 0) {
262+
// pointer is not aligned, so allocate a temporary block to do the write
263+
uint8_t *src_aligned = m_new_maybe(uint8_t, SDCARD_BLOCK_SIZE);
264+
if (src_aligned == NULL) {
265+
return SD_ERROR;
266+
}
267+
for (size_t i = 0; i < num_blocks; ++i) {
268+
memcpy(src_aligned, src + i * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE);
269+
err = sdcard_write_blocks(src_aligned, block_num + i, 1);
270+
if (err != SD_OK) {
271+
break;
272+
}
273+
}
274+
m_del(uint8_t, src_aligned, SDCARD_BLOCK_SIZE);
275+
return err;
276+
}
277+
244278
if (query_irq() == IRQ_STATE_ENABLED) {
245279
// we must disable USB irqs to prevent MSC contention with SD card
246280
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);

0 commit comments

Comments
 (0)