Skip to content

Commit 4a2489b

Browse files
committed
sdspi: fix compatibility issue in multi block read
SDSPI driver optimized polling of the response tokens by requesting two extra bytes on top of the block size (512) and CRC (2), and checking whether these bytes contained the data response token or not. In case the token was there, further polling would not need to happen, thereby reducing latency between two consecutive blocks transferred. However this caused compatibility issues when these two extra bytes were sent after reading the final block. When STOP_TRANSMISSION command was sent, these extra two bytes were treated as part of the command, causing an invalid command error. This fixes the logic by only requesting extra two bytes if the block being read is not the final block. In addition to that, more strict error checking is implemented for command response tokens.
1 parent 229f67b commit 4a2489b

File tree

1 file changed

+35
-4
lines changed

1 file changed

+35
-4
lines changed

components/driver/sdspi_host.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#define GPIO_UNUSED 0xff //!< Flag indicating that CD/WP is unused
3535
/// Size of the buffer returned by get_block_buf
3636
#define SDSPI_BLOCK_BUF_SIZE (SDSPI_MAX_DATA_LEN + 4)
37+
/// Maximum number of dummy bytes between the request and response (minimum is 1)
38+
#define SDSPI_RESPONSE_MAX_DELAY 8
3739

3840

3941
/// Structure containing run time configuration for a single SD slot
@@ -422,6 +424,30 @@ static esp_err_t start_command_default(int slot, int flags, sdspi_hw_cmd_t *cmd)
422424
.rx_buffer = cmd
423425
};
424426
esp_err_t ret = spi_device_transmit(spi_handle(slot), &t);
427+
if (cmd->cmd_index == MMC_STOP_TRANSMISSION) {
428+
/* response is a stuff byte from previous transfer, ignore it */
429+
cmd->r1 = 0xff;
430+
}
431+
int response_delay_bytes = SDSPI_RESPONSE_MAX_DELAY;
432+
while ((cmd->r1 & SD_SPI_R1_NO_RESPONSE) != 0 && response_delay_bytes-- > 0) {
433+
spi_transaction_t* t = get_transaction(slot);
434+
*t = (spi_transaction_t) {
435+
.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA,
436+
.length = 8,
437+
};
438+
t->tx_data[0] = 0xff;
439+
ret = spi_device_transmit(spi_handle(slot), t);
440+
uint8_t r1 = t->rx_data[0];
441+
release_transaction(slot);
442+
if (ret != ESP_OK) {
443+
return ret;
444+
}
445+
cmd->r1 = r1;
446+
}
447+
if (cmd->r1 & SD_SPI_R1_NO_RESPONSE) {
448+
ESP_LOGD(TAG, "%s: no response token found", __func__);
449+
return ESP_ERR_TIMEOUT;
450+
}
425451
return ret;
426452
}
427453

@@ -564,6 +590,9 @@ static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
564590
* indicating the start of the next block. Actual scanning is done by
565591
* setting pre_scan_data_ptr to point to these last 2 bytes, and setting
566592
* pre_scan_data_size = 2, then going to step 2 to receive the next block.
593+
* When the final block is being received, the number of extra bytes is 2
594+
* (only for CRC), because we don't need to wait for start token of the
595+
* next block, and some cards are getting confused by these two extra bytes.
567596
*
568597
* With this approach the delay between blocks of a multi-block transfer is
569598
* ~95 microseconds, out of which 35 microseconds are spend doing the CRC check.
@@ -575,9 +604,8 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
575604
{
576605
bool need_stop_command = rx_length > SDSPI_MAX_DATA_LEN;
577606
spi_transaction_t* t_command = get_transaction(slot);
578-
const int cmd_extra_bytes = 8;
579607
*t_command = (spi_transaction_t) {
580-
.length = (SDSPI_CMD_R1_SIZE + cmd_extra_bytes) * 8,
608+
.length = (SDSPI_CMD_R1_SIZE + SDSPI_RESPONSE_MAX_DELAY) * 8,
581609
.tx_buffer = cmd,
582610
.rx_buffer = cmd,
583611
};
@@ -588,7 +616,7 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
588616
release_transaction(slot);
589617

590618
uint8_t* cmd_u8 = (uint8_t*) cmd;
591-
size_t pre_scan_data_size = cmd_extra_bytes;
619+
size_t pre_scan_data_size = SDSPI_RESPONSE_MAX_DELAY;
592620
uint8_t* pre_scan_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;
593621

594622
/* R1 response is delayed by 1-8 bytes from the request.
@@ -640,7 +668,7 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
640668
}
641669

642670
// receive actual data
643-
const size_t receive_extra_bytes = 4;
671+
const size_t receive_extra_bytes = (rx_length > SDSPI_MAX_DATA_LEN) ? 4 : 2;
644672
memset(rx_data, 0xff, will_receive + receive_extra_bytes);
645673
spi_transaction_t* t_data = get_transaction(slot);
646674
*t_data = (spi_transaction_t) {
@@ -695,6 +723,9 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
695723
if (ret != ESP_OK) {
696724
return ret;
697725
}
726+
if (stop_cmd.r1 != 0) {
727+
ESP_LOGD(TAG, "%s: STOP_TRANSMISSION response 0x%02x", __func__, stop_cmd.r1);
728+
}
698729
spi_transaction_t* t_poll = get_transaction(slot);
699730
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
700731
release_transaction(slot);

0 commit comments

Comments
 (0)