Skip to content

Commit

Permalink
Log a warning for slow SD cards
Browse files Browse the repository at this point in the history
  • Loading branch information
androda committed Sep 19, 2024
1 parent 61cd43a commit 416dc80
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 11 deletions.
43 changes: 38 additions & 5 deletions lib/BlueSCSI_platform_RP2040/rp2040_sdio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,39 @@ void cycleSdClock() {
pio_sm_exec(SDIO_PIO, SDIO_CMD_SM, pio_encode_nop() | pio_encode_sideset_opt(1, 0) | pio_encode_delay(1));
}

/*******************************************************
* Status Register Receiver
*******************************************************/
sdio_status_t receive_status_register(uint8_t* sds) {
rp2040_sdio_rx_start(sds, 1, 64);

// Wait for the DMA operation to complete, or fail if it took too long
waitagain:
while (dma_channel_is_busy(SDIO_DMA_CHB) || dma_channel_is_busy(SDIO_DMA_CH))
{
if ((uint32_t)(millis() - g_sdio.transfer_start_time) > 2)
{
// Reset the state machine program
dma_channel_abort(SDIO_DMA_CHB);
pio_sm_set_enabled(SDIO_PIO, SDIO_CMD_SM, false);
pio_sm_clear_fifos(SDIO_PIO, SDIO_CMD_SM);
return SDIO_ERR_RESPONSE_TIMEOUT;
}
}

// Assert that both DMA channels are complete
if(dma_channel_is_busy(SDIO_DMA_CHB) || dma_channel_is_busy(SDIO_DMA_CH)) {
// Wait failure, go back.
goto waitagain;
}

pio_sm_set_enabled(SDIO_PIO, SDIO_DATA_SM, false);
g_sdio.transfer_state = SDIO_IDLE;

return SDIO_OK;
}


/*******************************************************
* Basic SDIO command execution
*******************************************************/
Expand Down Expand Up @@ -437,7 +470,7 @@ sdio_status_t rp2040_sdio_command_R3(uint8_t command, uint32_t arg, uint32_t *re
* Data reception from SD card
*******************************************************/

sdio_status_t rp2040_sdio_rx_start(uint8_t *buffer, uint32_t num_blocks)
sdio_status_t rp2040_sdio_rx_start(uint8_t *buffer, uint32_t num_blocks, uint32_t block_size)
{
// Buffer must be aligned
assert(((uint32_t)buffer & 3) == 0 && num_blocks <= SDIO_MAX_BLOCKS);
Expand All @@ -450,12 +483,12 @@ sdio_status_t rp2040_sdio_rx_start(uint8_t *buffer, uint32_t num_blocks)
g_sdio.blocks_checksumed = 0;
g_sdio.checksum_errors = 0;

// Create DMA block descriptors to store each block of 512 bytes of data to buffer
// Create DMA block descriptors to store each block of block_size bytes of data to buffer
// and then 8 bytes to g_sdio.received_checksums.
for (int i = 0; i < num_blocks; i++)
{
g_sdio.dma_blocks[i * 2].write_addr = buffer + i * SDIO_BLOCK_SIZE;
g_sdio.dma_blocks[i * 2].transfer_count = SDIO_BLOCK_SIZE / sizeof(uint32_t);
g_sdio.dma_blocks[i * 2].write_addr = buffer + (i * block_size);
g_sdio.dma_blocks[i * 2].transfer_count = block_size / sizeof(uint32_t);

g_sdio.dma_blocks[i * 2 + 1].write_addr = &g_sdio.received_checksums[i];
g_sdio.dma_blocks[i * 2 + 1].transfer_count = 2;
Expand Down Expand Up @@ -488,7 +521,7 @@ sdio_status_t rp2040_sdio_rx_start(uint8_t *buffer, uint32_t num_blocks)
pio_sm_set_consecutive_pindirs(SDIO_PIO, SDIO_DATA_SM, SDIO_D0, 4, false);

// Write number of nibbles to receive to Y register
pio_sm_put(SDIO_PIO, SDIO_DATA_SM, SDIO_BLOCK_SIZE * 2 + 16 - 1);
pio_sm_put(SDIO_PIO, SDIO_DATA_SM, (block_size * 2) + 16 - 1);
pio_sm_exec(SDIO_PIO, SDIO_DATA_SM, pio_encode_out(pio_y, 32));

// Enable RX FIFO join because we don't need the TX FIFO during transfer.
Expand Down
9 changes: 7 additions & 2 deletions lib/BlueSCSI_platform_RP2040/rp2040_sdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ sdio_status_t rp2040_sdio_command_R2(uint8_t command, uint32_t arg, uint8_t *res
sdio_status_t rp2040_sdio_command_R3(uint8_t command, uint32_t arg, uint32_t *response);

// Start transferring data from SD card to memory buffer
// Transfer block size is always 512 bytes.
sdio_status_t rp2040_sdio_rx_start(uint8_t *buffer, uint32_t num_blocks);
// num_blocks is the count of data blocks to transfer
// block_size is the number of *bytes* to transfer in each block (must be evenly divisible by 4)
// A CRC is expected after every data block
sdio_status_t rp2040_sdio_rx_start(uint8_t *buffer, uint32_t num_blocks, uint32_t block_size);

// Check if reception is complete
// Returns SDIO_BUSY while transferring, SDIO_OK when done and error on failure.
Expand All @@ -51,5 +53,8 @@ sdio_status_t rp2040_sdio_stop();
// Performs one full CLK line cycle
void cycleSdClock();

// Receives the SD Status register. Does not return until the register has been received.
sdio_status_t receive_status_register(uint8_t* sds);

// (Re)initialize the SDIO interface
void rp2040_sdio_init(int clock_divider = 1);
19 changes: 16 additions & 3 deletions lib/BlueSCSI_platform_RP2040/sd_card_sdio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ static int g_sdio_error_line;
static sdio_status_t g_sdio_error;
static uint32_t g_sdio_dma_buf[128];
static uint32_t g_sdio_sector_count;
static uint8_t cardType;
uint8_t sdSpeedClass;

#define checkReturnOk(call) ((g_sdio_error = (call)) == SDIO_OK ? true : logSDError(__LINE__))
static bool logSDError(int line)
Expand Down Expand Up @@ -149,6 +149,19 @@ bool SdioCard::begin(SdioConfig sdioConfig)
return false;
}

// Read SD Status field
sds_t sd_stat;
memset(&sd_stat, 0, sizeof(sds_t));
uint8_t* stat_pointer = (uint8_t*) &sd_stat;
if (!checkReturnOk(rp2040_sdio_command_R1(CMD55, g_sdio_rca, &reply)) ||
!checkReturnOk(rp2040_sdio_command_R1(ACMD13, 0, &reply)) ||
!checkReturnOk(receive_status_register(stat_pointer)))
{
debuglog("SDIO failed to get SD Status");
return false;
}
sdSpeedClass = sd_stat.speedClass();

// Increase to 25 MHz clock rate
rp2040_sdio_init(1);

Expand Down Expand Up @@ -428,7 +441,7 @@ bool SdioCard::readSector(uint32_t sector, uint8_t* dst)
if (
!checkReturnOk(rp2040_sdio_command_R1(16, 512, &reply)) || // SET_BLOCKLEN
!checkReturnOk(rp2040_sdio_command_R1(CMD17, address, &reply)) || // READ_SINGLE_BLOCK
!checkReturnOk(rp2040_sdio_rx_start(dst, 1)) // Prepare for reception
!checkReturnOk(rp2040_sdio_rx_start(dst, 1, SDIO_BLOCK_SIZE)) // Prepare for reception
)
{
return false;
Expand Down Expand Up @@ -481,7 +494,7 @@ bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n)
if (
!checkReturnOk(rp2040_sdio_command_R1(16, 512, &reply)) || // SET_BLOCKLEN
!checkReturnOk(rp2040_sdio_command_R1(CMD18, address, &reply)) || // READ_MULTIPLE_BLOCK
!checkReturnOk(rp2040_sdio_rx_start(dst, n)) // Prepare for reception
!checkReturnOk(rp2040_sdio_rx_start(dst, n, SDIO_BLOCK_SIZE)) // Prepare for reception
)
{
return false;
Expand Down
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ debug_tool = cmsis-dap ; new picoprobe.uf2's emulate cmsis-dap
; extra_scripts = src/build_bootloader.py
; ldscript_bootloader = lib/BlueSCSI_platform_RP2040/rp2040_btldr.ld
lib_deps =
SdFat=https://github.com/BlueSCSI/SdFat#2.2.0-gpt
SdFat=https://github.com/BlueSCSI/SdFat#3447b2eabb6c4d1e22c421b34d077bffecb7f81b
minIni
BlueSCSI_platform_RP2040
SCSI2SD
Expand Down
6 changes: 6 additions & 0 deletions src/BlueSCSI_disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include <assert.h>
#include <SdFat.h>

extern uint8_t sdSpeedClass;
#define SD_SPEED_CLASS_WARN_BELOW 10

extern "C" {
#include <scsi2sd_time.h>
#include <sd.h>
Expand Down Expand Up @@ -1026,6 +1029,9 @@ void s2s_configInit(S2S_BoardCfg* config)
config->scsiSpeed = PLATFORM_MAX_SCSI_SPEED;

int maxSyncSpeed = ini_getl("SCSI", "MaxSyncSpeed", defaults.maxSyncSpeed, CONFIGFILE);
if (sdSpeedClass < SD_SPEED_CLASS_WARN_BELOW) {
log_f("---- WARNING: Your SD Card Speed Class is %d. Class 10 or better is recommended for best performance.", sdSpeedClass);
}
if (maxSyncSpeed < 5 && config->scsiSpeed > S2S_CFG_SPEED_ASYNC_50)
config->scsiSpeed = S2S_CFG_SPEED_ASYNC_50;
else if (maxSyncSpeed < 10 && config->scsiSpeed > S2S_CFG_SPEED_SYNC_5)
Expand Down

0 comments on commit 416dc80

Please sign in to comment.