瀏覽代碼

Report SD card speed class warning for RP2040s

This code has been adapted from https://github.com/BlueSCSI/BlueSCSI-v2/pull/191
It uses an updated SDFat library to report a warning if the SD card's
speed class is below 10.

Co-authored-by: androda <3105206+androda@users.noreply.github.com>
Morio 1 年之前
父節點
當前提交
28f68ac033

+ 19 - 0
lib/ZuluSCSI_platform_RP2040/sd_card_sdio.cpp

@@ -35,11 +35,13 @@ static uint32_t g_sdio_ocr; // Operating condition register from card
 static uint32_t g_sdio_rca; // Relative card address
 static cid_t g_sdio_cid;
 static csd_t g_sdio_csd;
+static sds_t g_sdio_sds;
 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;
 
+
 #define checkReturnOk(call) ((g_sdio_error = (call)) == SDIO_OK ? true : logSDError(__LINE__))
 static bool logSDError(int line)
 {
@@ -170,6 +172,17 @@ bool SdioCard::begin(SdioConfig sdioConfig)
         return false;
     }
 
+    // Read SD Status field
+    memset(&g_sdio_sds, 0, sizeof(sds_t));
+    uint8_t* stat_pointer = (uint8_t*) &g_sdio_sds;
+    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)))
+    {
+        dbgmsg("SDIO failed to get SD Status");
+        return false;
+    }
+
     // Increase to 25 MHz clock rate
     rp2040_sdio_init(1);
 
@@ -213,6 +226,12 @@ bool SdioCard::readCSD(csd_t* csd)
     return true;
 }
 
+bool SdioCard::readSDS(sds_t* sds)
+{
+    *sds = g_sdio_sds;
+    return true;
+}
+
 bool SdioCard::readOCR(uint32_t* ocr)
 {
     // SDIO mode does not have CMD58, but main program uses this to

+ 34 - 5
lib/ZuluSCSI_platform_RP2040/sdio.cpp

@@ -154,6 +154,35 @@ uint64_t sdio_crc16_4bit_checksum(uint32_t *data, uint32_t num_words)
     return crc;
 }
 
+/*******************************************************
+ * 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
  *******************************************************/
@@ -374,7 +403,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);
@@ -387,12 +416,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;
@@ -424,7 +453,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.

+ 5 - 2
lib/ZuluSCSI_platform_RP2040/sdio.h

@@ -53,8 +53,8 @@ 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);
+// Transfer block size is always 512 bytes except for certain special commands
+sdio_status_t rp2040_sdio_rx_start(uint8_t *buffer, uint32_t num_blocks, uint32_t num_size = SDIO_BLOCK_SIZE);
 
 // Check if reception is complete
 // Returns SDIO_BUSY while transferring, SDIO_OK when done and error on failure.
@@ -69,5 +69,8 @@ sdio_status_t rp2040_sdio_tx_poll(uint32_t *bytes_complete = nullptr);
 // Force everything to idle state
 sdio_status_t rp2040_sdio_stop();
 
+// 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);

+ 5 - 4
platformio.ini

@@ -88,7 +88,7 @@ build_flags =
 
 ; ZuluSCSI RP2040 hardware platform, based on the Raspberry Pi foundation RP2040 microcontroller
 [env:ZuluSCSI_RP2040]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c
 platform_packages =
     framework-arduinopico@https://github.com/rabbitholecomputing/arduino-pico.git#v3.6.0-DaynaPORT
 board_build.core = earlephilhower
@@ -104,7 +104,7 @@ extra_scripts =
 board_build.ldscript = ${BUILD_DIR}/rp2040.ld
 ldscript_bootloader = lib/ZuluSCSI_platform_RP2040/rp2040_btldr.ld
 lib_deps =
-    SdFat=https://github.com/rabbitholecomputing/SdFat#2.2.0-gpt
+    SdFat=https://github.com/rabbitholecomputing/SdFat#feature/merge-upstream
     minIni
     ZuluSCSI_platform_RP2040
     SCSI2SD
@@ -131,6 +131,7 @@ build_flags =
 	-DCYW43_LWIP=0
 	-DCYW43_USE_OTP_MAC=0
     -DPLATFORM_MASS_STORAGE
+    -DFILE_COPY_CONSTRUCTOR_SELECT=FILE_COPY_CONSTRUCTOR_PUBLIC
 
 ; ZuluSCSI RP2040 hardware platform, as above, but with audio output support enabled
 [env:ZuluSCSI_RP2040_Audio]
@@ -163,7 +164,7 @@ build_flags =
 ; Build for the ZuluSCSI Pico carrier board with a Pico-W
 ; for SCSI DaynaPORT emulation
 [env:ZuluSCSI_Pico_DaynaPORT]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c
 platform_packages =
     framework-arduinopico@https://github.com/rabbitholecomputing/arduino-pico.git#v3.6.0-DaynaPORT
 framework = arduino
@@ -192,7 +193,7 @@ debug_build_flags =
     -DPLATFORM_MASS_STORAGE
 
 lib_deps =
-    SdFat=https://github.com/rabbitholecomputing/SdFat#2.2.0-gpt
+    SdFat=https://github.com/rabbitholecomputing/SdFat#feature/merge-upstream
     minIni
     ZuluSCSI_platform_RP2040
     SCSI2SD

+ 10 - 1
src/ZuluSCSI_disk.cpp

@@ -44,6 +44,10 @@
 #include <assert.h>
 #include <SdFat.h>
 
+#ifndef SD_SPEED_CLASS_WARN_BELOW
+#define SD_SPEED_CLASS_WARN_BELOW 10
+#endif
+
 extern "C" {
 #include <scsi2sd_time.h>
 #include <sd.h>
@@ -1049,6 +1053,12 @@ void s2s_configInit(S2S_BoardCfg* config)
     // Get default values from system preset, if any
     ini_gets("SCSI", "System", "", tmp, sizeof(tmp), CONFIGFILE);
     scsi_system_settings_t *sysCfg = g_scsi_settings.initSystem(tmp);
+    sds_t sds = {0};
+    SD.card()->readSDS(&sds);
+    if ( sds.speedClass() < SD_SPEED_CLASS_WARN_BELOW)
+    {
+		logmsg("WARNING: Your SD Card Speed Class is ", (int)sds.speedClass(), ". Class ", (int) SD_SPEED_CLASS_WARN_BELOW," or better is recommended for best performance.");
+    }
 
     if (g_scsi_settings.getSystemPreset() != SYS_PRESET_NONE)
     {
@@ -1066,7 +1076,6 @@ void s2s_configInit(S2S_BoardCfg* config)
     config->selectionDelay = sysCfg->selectionDelay;
     config->flags6 = 0;
     config->scsiSpeed = PLATFORM_MAX_SCSI_SPEED;
-
     int maxSyncSpeed = sysCfg->maxSyncSpeed;
     if (maxSyncSpeed < 5 && config->scsiSpeed > S2S_CFG_SPEED_ASYNC_50)
         config->scsiSpeed = S2S_CFG_SPEED_ASYNC_50;