Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log a warning for slow SD cards #191

Merged
merged 1 commit into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
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