Explorar o código

Merge pull request #197 from BlueSCSI/SDIODelayConfig

Configurable SDIO Clocking
Eric Helgeson hai 1 ano
pai
achega
1bf6c57728

+ 1 - 0
lib/BlueSCSI_platform_RP2040/BlueSCSI_platform.h

@@ -93,6 +93,7 @@ bool is202309a();
 // This can be used to implement simultaneous transfer to SCSI bus.
 typedef void (*sd_callback_t)(uint32_t bytes_complete);
 void platform_set_sd_callback(sd_callback_t func, const uint8_t *buffer);
+void add_extra_sdio_delay(uint16_t additional_delay);
 
 // Reprogram firmware in main program area.
 #ifndef RP2040_DISABLE_BOOTLOADER

+ 41 - 0
lib/BlueSCSI_platform_RP2040/rp2040_sdio.cpp

@@ -24,6 +24,12 @@
 #define SDIO_DMA_CH 4
 #define SDIO_DMA_CHB 5
 
+#define PIO_INSTR_MASK_REMOVE_DELAY 0xF8FF
+#define PIO_INSTR_MASK_GET_DELAY 0x700
+
+#define PIO_INSTR_JMP_MASK 0xE000
+#define PIO_INSTR_JMP_ADDR 0x1F
+
 // Maximum number of 512 byte blocks to transfer in one request
 #define SDIO_MAX_BLOCKS 256
 
@@ -931,3 +937,38 @@ void rp2040_sdio_init(int clock_divider)
     irq_set_enabled(DMA_IRQ_1, true);
 #endif
 }
+
+void rp2040_sdio_update_delays(pio_program program, uint32_t offset, uint16_t additional_delay) {
+    //log("Offset:", offset);
+    uint16_t instr_to_rewrite;
+    uint16_t existing_delay;
+    for (int i = 0; i < program.length; i++) {
+        instr_to_rewrite = program.instructions[i];
+        //log("Old Instr:", i, ":", (uint32_t)instr_to_rewrite);
+        if (instr_to_rewrite & PIO_INSTR_MASK_GET_DELAY) {  // If there's a delay, increment it.  Otherwise, leave it alone.
+            existing_delay = (instr_to_rewrite & PIO_INSTR_MASK_GET_DELAY) >> 8;
+            existing_delay += additional_delay;
+            instr_to_rewrite = (instr_to_rewrite & PIO_INSTR_MASK_REMOVE_DELAY) | (existing_delay << 8);
+
+            // Canonicalize JMP addresses
+            if ((instr_to_rewrite & PIO_INSTR_JMP_MASK) == 0) {  // Highest three bits are zero on a JMP
+                uint32_t jmp_address = instr_to_rewrite & PIO_INSTR_JMP_ADDR;
+                jmp_address += offset;
+                instr_to_rewrite = (instr_to_rewrite & (~ PIO_INSTR_JMP_ADDR)) | jmp_address;
+            }
+
+            //log("New Instr:", i, ":", (uint32_t)instr_to_rewrite);
+            SDIO_PIO->instr_mem[offset + i] = instr_to_rewrite;
+        }
+    }
+}
+
+void rp2040_sdio_delay_increment(uint16_t additional_delay) {
+    /*
+    Rewrite in-place every SDIO instruction for all the SDIO programs.
+    These additional delay cycles effectively decrease the SDIO clock rate, which can be helpful in electrically noisy environments.
+    */
+    rp2040_sdio_update_delays(cmd_rsp_program, g_sdio.pio_cmd_rsp_clk_offset, additional_delay);
+    rp2040_sdio_update_delays(rd_data_w_clock_program, g_sdio.pio_data_rx_offset, additional_delay);
+    rp2040_sdio_update_delays(sdio_tx_w_clock_program, g_sdio.pio_data_tx_offset, additional_delay);
+}

+ 3 - 0
lib/BlueSCSI_platform_RP2040/rp2040_sdio.h

@@ -58,3 +58,6 @@ sdio_status_t receive_status_register(uint8_t* sds);
 
 // (Re)initialize the SDIO interface
 void rp2040_sdio_init(int clock_divider = 1);
+
+// Adds extra clock delay as specified in additional_delay
+void rp2040_sdio_delay_increment(uint16_t additional_delay);

+ 4 - 0
lib/BlueSCSI_platform_RP2040/sd_card_sdio.cpp

@@ -45,6 +45,10 @@ void platform_set_sd_callback(sd_callback_t func, const uint8_t *buffer)
     m_stream_count_start = 0;
 }
 
+void add_extra_sdio_delay(uint16_t additional_delay) {
+    rp2040_sdio_delay_increment(additional_delay);
+}
+
 static sd_callback_t get_stream_callback(const uint8_t *buf, uint32_t count, const char *accesstype, uint32_t sector)
 {
     m_stream_count_start = m_stream_count;

+ 1 - 1
platformio.ini

@@ -12,7 +12,7 @@ default_envs = BlueSCSI_Pico
 
 ; BlueSCSI RP2040 hardware platform, based on the Raspberry Pi foundation RP2040 microcontroller
 [env:BlueSCSI_Pico]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#196d31bbafaf60b84751b1a415d8dca2365debdf
 platform_packages = platformio/toolchain-gccarmnoneeabi@1.120301.0
     framework-arduinopico@https://github.com/BlueSCSI/arduino-pico-internal.git#e139b9c7816602597f473b3231032cca5d71a48a
 framework = arduino

+ 19 - 0
src/BlueSCSI.cpp

@@ -555,6 +555,22 @@ static void reinitSCSI()
   }
 }
 
+void check_and_apply_sdio_delay() {
+  long add_sdio_delay = ini_getl("SDIO", "AddClockDelay", 0, CONFIGFILE);
+  if (add_sdio_delay) {
+    if (add_sdio_delay < 0) {
+      log("---- WARNING: Negative numbers are not valid for AddClockDelay. Setting value to 0");
+      return;
+    }
+    if (add_sdio_delay > 2) {
+      add_sdio_delay = 2;
+      log("---- WARNING: Max value 2 exceeded for AddClockDelay. Setting value to 2.");
+    }
+    log("INFO: Injecting ", (uint16_t)add_sdio_delay, " additional wait state(s) on SDIO");
+    add_extra_sdio_delay((uint16_t) add_sdio_delay);
+  }
+}
+
 extern "C" void bluescsi_setup(void)
 {
   pio_clear_instruction_memory(pio0);
@@ -599,6 +615,7 @@ extern "C" void bluescsi_setup(void)
     {
       log("SD card without filesystem!");
     }
+    check_and_apply_sdio_delay();
 
     print_sd_info();
   
@@ -736,10 +753,12 @@ extern "C" void bluescsi_main_loop(void)
       if (g_sdcard_present)
       {
         log("SD card reinit succeeded");
+        check_and_apply_sdio_delay();
         print_sd_info();
 
         reinitSCSI();
         init_logfile();
+        LED_OFF();
       }
       else if (!g_romdrive_active)
       {