Skip to content

Commit 8a6bb5b

Browse files
committed
feat(sdmmc): support multi-block read/writes
This has the potential of speeding up SD card access significantly.
1 parent 5c5eb99 commit 8a6bb5b

File tree

1 file changed

+28
-16
lines changed

1 file changed

+28
-16
lines changed

components/sdmmc/sdmmc_cmd.c

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
*/
66

77
#include <inttypes.h>
8+
#include <sys/param.h> // for MIN/MAX
89
#include "esp_private/sdmmc_common.h"
910

11+
// the maximum size in blocks of the chunks a SDMMC write/read will be split into
12+
#define MAX_NUM_BLOCKS_PER_MULTI_BLOCK_RW (16u)
13+
1014
static const char* TAG = "sdmmc_cmd";
1115

1216

@@ -462,27 +466,30 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
462466
err = sdmmc_write_sectors_dma(card, src, start_block, block_count, block_size * block_count);
463467
} else {
464468
// SDMMC peripheral needs DMA-capable buffers. Split the write into
465-
// separate single block writes, if needed, and allocate a temporary
469+
// separate (multi) block writes, if needed, and allocate a temporary
466470
// DMA-capable buffer.
471+
size_t blocks_per_write = MIN(MAX_NUM_BLOCKS_PER_MULTI_BLOCK_RW, block_count);
467472
void *tmp_buf = NULL;
468473
size_t actual_size = 0;
469474
// We don't want to force the allocation into SPIRAM, the allocator
470475
// will decide based on the buffer size and memory availability.
471-
tmp_buf = heap_caps_malloc(block_size, MALLOC_CAP_DMA);
476+
tmp_buf = heap_caps_malloc(block_size * blocks_per_write, MALLOC_CAP_DMA);
472477
if (!tmp_buf) {
473478
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
474479
return ESP_ERR_NO_MEM;
475480
}
476481
actual_size = heap_caps_get_allocated_size(tmp_buf);
477482

478483
const uint8_t* cur_src = (const uint8_t*) src;
479-
for (size_t i = 0; i < block_count; ++i) {
480-
memcpy(tmp_buf, cur_src, block_size);
481-
cur_src += block_size;
482-
err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, 1, actual_size);
484+
for (size_t i = 0; i < block_count; i += blocks_per_write) {
485+
// make sure not to write more than the remaining blocks, i.e. block_count - i
486+
blocks_per_write = MIN(blocks_per_write, (block_count - i));
487+
memcpy(tmp_buf, cur_src, block_size * blocks_per_write);
488+
cur_src += block_size * blocks_per_write;
489+
err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, blocks_per_write, actual_size);
483490
if (err != ESP_OK) {
484-
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
485-
__func__, err, start_block, i);
491+
ESP_LOGD(TAG, "%s: error 0x%x writing blocks %zu+[%zu..%zu]",
492+
__func__, err, start_block, i, i + blocks_per_write - 1);
486493
break;
487494
}
488495
}
@@ -600,27 +607,32 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
600607
err = sdmmc_read_sectors_dma(card, dst, start_block, block_count, block_size * block_count);
601608
} else {
602609
// SDMMC peripheral needs DMA-capable buffers. Split the read into
603-
// separate single block reads, if needed, and allocate a temporary
610+
// separate (multi) block reads, if needed, and allocate a temporary
604611
// DMA-capable buffer.
612+
size_t blocks_per_read = MIN(MAX_NUM_BLOCKS_PER_MULTI_BLOCK_RW, block_count);
605613
void *tmp_buf = NULL;
606614
size_t actual_size = 0;
607-
tmp_buf = heap_caps_malloc(block_size, MALLOC_CAP_DMA);
615+
// We don't want to force the allocation into SPIRAM, the allocator
616+
// will decide based on the buffer size and memory availability.
617+
tmp_buf = heap_caps_malloc(block_size * blocks_per_read, MALLOC_CAP_DMA);
608618
if (!tmp_buf) {
609619
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
610620
return ESP_ERR_NO_MEM;
611621
}
612622
actual_size = heap_caps_get_allocated_size(tmp_buf);
613623

614624
uint8_t* cur_dst = (uint8_t*) dst;
615-
for (size_t i = 0; i < block_count; ++i) {
616-
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, 1, actual_size);
625+
for (size_t i = 0; i < block_count; i += blocks_per_read) {
626+
// make sure not to read more than the remaining blocks, i.e. block_count - i
627+
blocks_per_read = MIN(blocks_per_read, (block_count - i));
628+
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, blocks_per_read, actual_size);
617629
if (err != ESP_OK) {
618-
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
619-
__func__, err, start_block, i);
630+
ESP_LOGD(TAG, "%s: error 0x%x reading blocks %zu+[%zu..%zu]",
631+
__func__, err, start_block, i, i + blocks_per_read - 1);
620632
break;
621633
}
622-
memcpy(cur_dst, tmp_buf, block_size);
623-
cur_dst += block_size;
634+
memcpy(cur_dst, tmp_buf, block_size * blocks_per_read);
635+
cur_dst += block_size * blocks_per_read;
624636
}
625637
free(tmp_buf);
626638
}

0 commit comments

Comments
 (0)