diff --git a/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h b/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h index 9c014738c59..4e7120bcd8c 100644 --- a/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h +++ b/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h @@ -47,7 +47,7 @@ extern "C" { .get_real_freq = &sdmmc_host_get_real_freq, \ .input_delay_phase = SDMMC_DELAY_PHASE_0, \ .set_input_delay = &sdmmc_host_set_input_delay, \ - .unaligned_multi_block_rw_max_chunk_size = 0, \ + .unaligned_multi_block_rw_max_chunk_size = 16, \ .dma_aligned_buffer = NULL, \ .pwr_ctrl_handle = NULL, \ .get_dma_info = NULL, \ diff --git a/components/esp_driver_sdspi/include/driver/sdspi_host.h b/components/esp_driver_sdspi/include/driver/sdspi_host.h index 2d522e45fc6..f049d4bb32d 100644 --- a/components/esp_driver_sdspi/include/driver/sdspi_host.h +++ b/components/esp_driver_sdspi/include/driver/sdspi_host.h @@ -60,7 +60,7 @@ typedef int sdspi_dev_handle_t; .get_real_freq = &sdspi_host_get_real_freq, \ .input_delay_phase = SDMMC_DELAY_PHASE_0, \ .set_input_delay = NULL, \ - .unaligned_multi_block_rw_max_chunk_size = 0, \ + .unaligned_multi_block_rw_max_chunk_size = 16, \ .dma_aligned_buffer = NULL, \ .pwr_ctrl_handle = NULL, \ .get_dma_info = NULL, \ diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index 61c7e91bc0e..3b652ee3932 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -23,6 +23,27 @@ static inline size_t get_chunk_size(const sdmmc_card_t *card) return (chunk_size != 0) ? chunk_size : 1; } +static esp_err_t allocate_dma_buf(size_t* actual_size, size_t block_size, void **buf) +{ + if (actual_size == NULL || buf == NULL) { + return ESP_ERR_INVALID_ARG; + } + + size_t size = *actual_size; + do { + if (*actual_size < block_size) { + ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM); + return ESP_ERR_NO_MEM; + } + *buf = heap_caps_malloc(*actual_size, MALLOC_CAP_DMA); + if (!*buf) { + *actual_size /= 2; + ESP_LOGD(TAG, "%s: required space for buffer of size %d not available, trying again with size %zu", __func__, size, *actual_size); + } + } while (!*buf); + return ESP_OK; +} + esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd) { if (card->host.command_timeout_ms != 0) { @@ -489,11 +510,12 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src, // Allocate a temporary DMA-capable buffer. // We don't want to force the allocation into SPIRAM, the allocator // will decide based on the buffer size and memory availability. - buf = heap_caps_malloc(actual_size, MALLOC_CAP_DMA); - if (!buf) { - ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM); - return ESP_ERR_NO_MEM; + // We start with the largest buffer possible to minimize the number of read iterations, but if that fails, we try smaller sizes down to a single block. + err = allocate_dma_buf(&actual_size, block_size, &buf); + if (err != ESP_OK) { + return err; } + blocks_per_write = actual_size / block_size; } else { // Check that the provided dma_aligned_buffer is large enough actual_size = heap_caps_get_allocated_size(buf); @@ -649,11 +671,12 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst, // Allocate a temporary DMA-capable buffer. // We don't want to force the allocation into SPIRAM, the allocator // will decide based on the buffer size and memory availability. - buf = heap_caps_malloc(actual_size, MALLOC_CAP_DMA); - if (!buf) { - ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM); - return ESP_ERR_NO_MEM; + // We start with the largest buffer possible to minimize the number of read iterations, but if that fails, we try smaller sizes down to a single block. + err = allocate_dma_buf(&actual_size, block_size, &buf); + if (err != ESP_OK) { + return err; } + blocks_per_read = actual_size / block_size; } else { // Check that the provided dma_aligned_buffer is large enough actual_size = heap_caps_get_allocated_size(buf);