// convert cmdinfo to hardware register value
sdmmc_hw_cmd_t hw_cmd = make_hw_cmd(cmdinfo);
if (cmdinfo->data) {
- if (cmdinfo->datalen < 4 || cmdinfo->blklen % 4 != 0) {
- ESP_LOGD(TAG, "%s: invalid size: total=%d block=%d",
- __func__, cmdinfo->datalen, cmdinfo->blklen);
+ // Length should be either <4 or >=4 and =0 (mod 4).
+ if (cmdinfo->datalen >= 4 && cmdinfo->datalen % 4 != 0) {
+ ESP_LOGD(TAG, "%s: invalid size: total=%d",
+ __func__, cmdinfo->datalen);
ret = ESP_ERR_INVALID_SIZE;
goto out;
}
desc->owned_by_idmac = 1;
desc->buffer1_ptr = s_cur_transfer.ptr;
desc->next_desc_ptr = (last) ? NULL : &s_dma_desc[(next + 1) % SDMMC_DMA_DESC_CNT];
- desc->buffer1_size = size_to_fill;
+ assert(size_to_fill < 4 || size_to_fill % 4 == 0);
+ desc->buffer1_size = (size_to_fill + 3) & (~3);
s_cur_transfer.size_remaining -= size_to_fill;
s_cur_transfer.ptr += size_to_fill;
esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function,
uint32_t addr, void* dst, size_t size)
{
- return sdmmc_io_rw_extended(card, function, addr,
- SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT,
- dst, size);
+ /* host quirk: SDIO transfer with length not divisible by 4 bytes
+ * has to be split into two transfers: one with aligned length,
+ * the other one for the remaining 1-3 bytes.
+ */
+ uint8_t *pc_dst = dst;
+ while (size > 0) {
+ size_t size_aligned = size & (~3);
+ size_t will_transfer = size_aligned > 0 ? size_aligned : size;
+
+ esp_err_t err = sdmmc_io_rw_extended(card, function, addr,
+ SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT,
+ pc_dst, will_transfer);
+ if (err != ESP_OK) {
+ return err;
+ }
+ pc_dst += will_transfer;
+ size -= will_transfer;
+ addr += will_transfer;
+ }
+ return ESP_OK;
}
esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function,
uint32_t addr, const void* src, size_t size)
{
- return sdmmc_io_rw_extended(card, function, addr,
- SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT,
- (void*) src, size);
+ /* same host quirk as in sdmmc_io_read_bytes */
+ const uint8_t *pc_src = (const uint8_t*) src;
+
+ while (size > 0) {
+ size_t size_aligned = size & (~3);
+ size_t will_transfer = size_aligned > 0 ? size_aligned : size;
+
+ esp_err_t err = sdmmc_io_rw_extended(card, function, addr,
+ SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT,
+ (void*) pc_src, will_transfer);
+ if (err != ESP_OK) {
+ return err;
+ }
+ pc_src += will_transfer;
+ size -= will_transfer;
+ addr += will_transfer;
+ }
+ return ESP_OK;
}
esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
uint32_t addr, void* dst, size_t size)
{
+ if (size % 4 != 0) {
+ return ESP_ERR_INVALID_SIZE;
+ }
return sdmmc_io_rw_extended(card, function, addr,
SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE,
dst, size);
esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function,
uint32_t addr, const void* src, size_t size)
{
+ if (size % 4 != 0) {
+ return ESP_ERR_INVALID_SIZE;
+ }
return sdmmc_io_rw_extended(card, function, addr,
SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE,
(void*) src, size);
TEST_ASSERT_EQUAL_UINT8(test_byte_2, val);
}
-static void test_cmd53_read_write_multiple_bytes(sdmmc_card_t* card)
+static void test_cmd53_read_write_multiple_bytes(sdmmc_card_t* card, size_t n_bytes)
{
printf("Write multiple bytes using CMD53\n");
const size_t scratch_area_reg = SLCHOST_CONF_W0 - DR_REG_SLCHOST_BASE;
uint8_t* src = heap_caps_malloc(512, MALLOC_CAP_DMA);
uint32_t* src_32 = (uint32_t*) src;
- const size_t n_words = 6;
- srand(0);
- for (size_t i = 0; i < n_words; ++i) {
+
+ for (size_t i = 0; i < (n_bytes + 3) / 4; ++i) {
src_32[i] = rand();
}
- size_t len = n_words * sizeof(uint32_t);
- TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, scratch_area_reg, src, len));
- ESP_LOG_BUFFER_HEX(TAG, src, len);
+ TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, scratch_area_reg, src, n_bytes));
+ ESP_LOG_BUFFER_HEX(TAG, src, n_bytes);
printf("Read back using CMD52\n");
uint8_t* dst = heap_caps_malloc(512, MALLOC_CAP_DMA);
- for (size_t i = 0; i < len; ++i) {
+ for (size_t i = 0; i < n_bytes; ++i) {
TEST_ESP_OK(sdmmc_io_read_byte(card, 1, scratch_area_reg + i, &dst[i]));
}
- ESP_LOG_BUFFER_HEX(TAG, dst, len);
- TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, len);
+ ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes);
printf("Read back using CMD53\n");
- TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, scratch_area_reg, dst, len));
- ESP_LOG_BUFFER_HEX(TAG, dst, len);
- TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, len);
+ TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, scratch_area_reg, dst, n_bytes));
+ ESP_LOG_BUFFER_HEX(TAG, dst, n_bytes);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(src, dst, n_bytes);
free(src);
free(dst);
/* Set up standard SDIO registers */
sdio_slave_common_init(card);
- for (int repeat = 0; repeat < 10; ++repeat) {
+ srand(0);
+ for (int repeat = 0; repeat < 4; ++repeat) {
test_cmd52_read_write_single_byte(card);
- test_cmd53_read_write_multiple_bytes(card);
+ test_cmd53_read_write_multiple_bytes(card, 1);
+ test_cmd53_read_write_multiple_bytes(card, 2);
+ test_cmd53_read_write_multiple_bytes(card, 3);
+ test_cmd53_read_write_multiple_bytes(card, 4);
+ test_cmd53_read_write_multiple_bytes(card, 5);
+ test_cmd53_read_write_multiple_bytes(card, 23);
+ test_cmd53_read_write_multiple_bytes(card, 24);
}
sdio_slave_set_blocksize(card, 0, 512);