fix(sdmmc): Multi-block read/writes support refactor + tests and documentation added

This commit is contained in:
Adam Múdry
2026-02-10 12:31:47 +01:00
parent 6c24854436
commit 653cea9c94
17 changed files with 248 additions and 53 deletions
@@ -293,6 +293,50 @@ menu "Performance Benchmark Example Configuration"
help
Please read the schematic first and input your LDO ID.
choice
prompt "The maximum size of the chunks a SDMMC read/write to/from an unaligned buffer will be split into"
default SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_32
help
The maximum size in blocks of the chunks a SDMMC read/write with an unaligned buffer will be split
into.
The SDMMC driver requires aligned buffers for DMA access. If unaligned buffers are passed and the
host's dma_aligned_buffer is NULL, an aligned temporary buffer must be allocated for the actual
transfer.
This option defines the maximum size for the temporary buffer, which equals this option's value
multiplied with the block size (typically 512 bytes). A value of 16 therefore leads to up to 8192
bytes being allocated on the heap for each transfer. The allocated buffer will never be larger than
the number of bytes to transfer in total.
It also decides whether single (value == 1) or multi block read/write (value > 1) commands are used.
With the default value of 1, single-block read/write commands will be used with the allocated buffer
size matching the block size.
You should keep this option at 1 if your card or configuration doesn't support the read or write
multiple blocks commands (CMD18 & CMD25).
config SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_1
bool "1"
config SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_2
bool "2"
config SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_4
bool "4"
config SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_8
bool "8"
config SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_16
bool "16"
config SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_32
bool "32"
endchoice
config EXAMPLE_SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE
int
default 1 if SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_1
default 2 if SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_2
default 4 if SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_4
default 8 if SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_8
default 16 if SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_16
default 32 if SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE_32
default 1
endmenu # "SD card test config"
endmenu # "Performance Monitor Example Configuration"
@@ -60,6 +60,10 @@ void init_sd_config(sdmmc_host_t *out_host, sdspi_device_config_t *out_slot_conf
ESP_LOGI(TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.max_freq_khz = freq_khz;
// Set the chunk size for unaligned multi-block read/write operations to N blocks.
// This is to improve performance when the buffer is not aligned or the size is not a multiple of the SD card's block size.
// I.e. performance uplift for "write/read more/less than..." test cases - e.g. an equivalent situation to appending to a file.
host.unaligned_multi_block_rw_max_chunk_size = CONFIG_EXAMPLE_SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE;
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
@@ -101,6 +105,10 @@ void init_sd_config(sdmmc_host_t *out_host, sdspi_device_config_t *out_slot_conf
ESP_LOGI(TAG, "Using SPI peripheral");
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.max_freq_khz = freq_khz;
// Set the chunk size for unaligned multi-block read/write operations to N blocks.
// This is to improve performance when the buffer is not aligned or the size is not a multiple of the SD card's block size.
// I.e. performance uplift for "write/read more/less than..." test cases - e.g. an equivalent situation to appending to a file.
host.unaligned_multi_block_rw_max_chunk_size = CONFIG_EXAMPLE_SD_UNALIGNED_MULTI_BLOCK_RW_MAX_CHUNK_SIZE;
spi_bus_config_t bus_cfg = {
.mosi_io_num = CONFIG_EXAMPLE_PIN_MOSI,
@@ -162,6 +162,7 @@ void app_main(void)
// For setting a specific frequency, use host.max_freq_khz (range 400kHz - 40MHz for SDMMC)
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.unaligned_multi_block_rw_max_chunk_size = 8;
#if CONFIG_EXAMPLE_SDMMC_SPEED_HS
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
#elif CONFIG_EXAMPLE_SDMMC_SPEED_UHS_I_SDR50
@@ -122,6 +122,7 @@ void app_main(void)
// For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI)
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.unaligned_multi_block_rw_max_chunk_size = 8;
// For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply.
// When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card