瀏覽代碼

Merge pull request #191 from BlueSCSI/SDSpeedClassWarn

Log a warning for slow SD cards
Eric Helgeson 1 年之前
父節點
當前提交
bb095170ed

+ 38 - 5
lib/BlueSCSI_platform_RP2040/rp2040_sdio.cpp

@@ -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
  *******************************************************/
@@ -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);
@@ -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;
@@ -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.

+ 7 - 2
lib/BlueSCSI_platform_RP2040/rp2040_sdio.h

@@ -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.
@@ -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);

+ 16 - 3
lib/BlueSCSI_platform_RP2040/sd_card_sdio.cpp

@@ -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)
@@ -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);
 
@@ -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;
@@ -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;

+ 1 - 1
platformio.ini

@@ -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

+ 6 - 0
src/BlueSCSI_disk.cpp

@@ -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>
@@ -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)