Skip to content
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions components/sdmmc/sdmmc_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
*/

#include <inttypes.h>
#include <sys/param.h> // for MIN/MAX
#include "esp_private/sdmmc_common.h"

// the maximum size in blocks of the chunks a SDMMC write/read will be split into
#define MAX_NUM_BLOCKS_PER_MULTI_BLOCK_RW (16u)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's introduce a Kconfig option to set this value, with the default being 1 to match the current heap usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the option in 3b3d530.


static const char* TAG = "sdmmc_cmd";


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

const uint8_t* cur_src = (const uint8_t*) src;
for (size_t i = 0; i < block_count; ++i) {
memcpy(tmp_buf, cur_src, block_size);
cur_src += block_size;
err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, 1, actual_size);
for (size_t i = 0; i < block_count; i += blocks_per_write) {
// make sure not to write more than the remaining blocks, i.e. block_count - i
blocks_per_write = MIN(blocks_per_write, (block_count - i));
memcpy(tmp_buf, cur_src, block_size * blocks_per_write);
cur_src += block_size * blocks_per_write;
err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, blocks_per_write, actual_size);
if (err != ESP_OK) {
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
__func__, err, start_block, i);
ESP_LOGD(TAG, "%s: error 0x%x writing blocks %zu+[%zu..%zu]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately we can't rely on %z format specifier, since it's not supported by newlib-nano (i.e. if CONFIG_NEWLIB_NANO_FORMAT is enabled.)

Same note for sdmmc_read_sectors below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted back to %d in c6581d0.

__func__, err, start_block, i, i + blocks_per_write - 1);
break;
}
}
Expand Down Expand Up @@ -600,27 +607,32 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
err = sdmmc_read_sectors_dma(card, dst, start_block, block_count, block_size * block_count);
} else {
// SDMMC peripheral needs DMA-capable buffers. Split the read into
// separate single block reads, if needed, and allocate a temporary
// separate (multi) block reads, if needed, and allocate a temporary
// DMA-capable buffer.
size_t blocks_per_read = MIN(MAX_NUM_BLOCKS_PER_MULTI_BLOCK_RW, block_count);
void *tmp_buf = NULL;
size_t actual_size = 0;
tmp_buf = heap_caps_malloc(block_size, MALLOC_CAP_DMA);
// We don't want to force the allocation into SPIRAM, the allocator
// will decide based on the buffer size and memory availability.
tmp_buf = heap_caps_malloc(block_size * blocks_per_read, MALLOC_CAP_DMA);
if (!tmp_buf) {
ESP_LOGE(TAG, "%s: not enough mem, err=0x%x", __func__, ESP_ERR_NO_MEM);
return ESP_ERR_NO_MEM;
}
actual_size = heap_caps_get_allocated_size(tmp_buf);

uint8_t* cur_dst = (uint8_t*) dst;
for (size_t i = 0; i < block_count; ++i) {
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, 1, actual_size);
for (size_t i = 0; i < block_count; i += blocks_per_read) {
// make sure not to read more than the remaining blocks, i.e. block_count - i
blocks_per_read = MIN(blocks_per_read, (block_count - i));
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, blocks_per_read, actual_size);
if (err != ESP_OK) {
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
__func__, err, start_block, i);
ESP_LOGD(TAG, "%s: error 0x%x reading blocks %zu+[%zu..%zu]",
__func__, err, start_block, i, i + blocks_per_read - 1);
break;
}
memcpy(cur_dst, tmp_buf, block_size);
cur_dst += block_size;
memcpy(cur_dst, tmp_buf, block_size * blocks_per_read);
cur_dst += block_size * blocks_per_read;
}
free(tmp_buf);
}
Expand Down