ソースを参照

Merge pull request #400 from ZuluSCSI/f4-build-rev2023e

Enable sync for the F4 Rev 2023e build
John Morio Sakaguchi 1 年間 前
コミット
b92bd90dc9

+ 50 - 99
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.cpp

@@ -133,17 +133,14 @@ void SysTick_Handle_PreEmptively()
 // Clock has already been initialized by system_gd32f20x.c
 void platform_init()
 {
-
     SystemCoreClockUpdate();
-    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
+
     // Enable SysTick to drive millis()
+    // \todo not sure if this is needed
+    // nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
     g_millisecond_counter = 0;
     SysTick_Config(SystemCoreClock / 1000U);
-    nvic_irq_enable(SysTick_IRQn, 0x00U, 0x00U);
-    //NVIC_SetPriority(SysTick_IRQn, 0x00U);
-    //NVIC_EnableIRQ(SysTick_IRQn);
-
-    
+    NVIC_SetPriority(SysTick_IRQn, 0x00U);
 
     // Enable DWT counter to drive delay_ns()
     g_ns_to_cycles = ((uint64_t)SystemCoreClock << 32) / 1000000000;
@@ -152,11 +149,11 @@ void platform_init()
 
     // Enable debug output on SWO pin
     DBG_CTL0 |= DBG_CTL0_TRACE_IOEN;
-    //TODO figure out if this code needs to execute - TPI_ACPR == 99 at the if statement below
-    //if (TPI->ACPR == 0)
+    // if (TPI->ACPR == 0)
     {
         CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
-        TPI->ACPR = SystemCoreClock / 2000000 - 1; // 2 Mbps baudrate for SWO
+        TPI->ACPR = SystemCoreClock / 115200 - 1; // Serial speed baudrate for SWO
+        // TPI->ACPR = SystemCoreClock / 2000000 - 1; // 2 Mbps baudrate for SWO
         // TPI->ACPR = SystemCoreClock / 30000000 - 1; // 30 Mbps baudrate for SWO
         TPI->SPPR = 2;
         TPI->FFCR = 0x100; // TPIU packet framing disabled
@@ -218,31 +215,45 @@ void platform_init()
     gpio_mode_set(SCSI_TERM_EN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCSI_TERM_EN_PIN);
     gpio_output_options_set(SCSI_TERM_EN_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, SCSI_TERM_EN_PIN);
 
+#ifndef SD_USE_SDIO
+    // SD card pins using SPI
+    gpio_init(SD_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SD_CS_PIN);
+    gpio_init(SD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SD_CLK_PIN);
+    gpio_init(SD_PORT, GPIO_MODE_IPU, 0, SD_MISO_PIN);
+    gpio_init(SD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SD_MOSI_PIN);
+#else
     // SD card pins using SDIO
     gpio_mode_set(SD_SDIO_DATA_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SD_SDIO_D0 | SD_SDIO_D1 | SD_SDIO_D2 | SD_SDIO_D3);
-    gpio_output_options_set(SD_SDIO_DATA_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SD_SDIO_D0 | SD_SDIO_D1 | SD_SDIO_D2 | SD_SDIO_D3);
+    gpio_output_options_set(SD_SDIO_DATA_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SD_SDIO_D0 | SD_SDIO_D1 | SD_SDIO_D2 | SD_SDIO_D3);
     gpio_af_set(SD_SDIO_DATA_PORT, GPIO_AF_12, SD_SDIO_D0 | SD_SDIO_D1 | SD_SDIO_D2 | SD_SDIO_D3);
 
     gpio_mode_set(SD_SDIO_CLK_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SD_SDIO_CLK);
-    gpio_output_options_set(SD_SDIO_CLK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SD_SDIO_CLK);
+    gpio_output_options_set(SD_SDIO_CLK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SD_SDIO_CLK);
     gpio_af_set(SD_SDIO_CLK_PORT, GPIO_AF_12, SD_SDIO_CLK);
 
     gpio_mode_set(SD_SDIO_CMD_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SD_SDIO_CMD);
-    gpio_output_options_set(SD_SDIO_CMD_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SD_SDIO_CMD);
+    gpio_output_options_set(SD_SDIO_CMD_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SD_SDIO_CMD);
     gpio_af_set(SD_SDIO_CMD_PORT, GPIO_AF_12, SD_SDIO_CMD);
 
+#endif
+
+    // @TODO confirm dip switch 1 is not longer JTAG NJTRST
+    // Switch to SWD debug port (disable JTAG) to release PB4 as GPIO
+    //gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);   
+
     // DIP switches
     gpio_mode_set(DIP_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, DIPSW1_PIN | DIPSW2_PIN | DIPSW3_PIN);
 
+
     // LED pins
     gpio_bit_set(LED_PORT, LED_PINS);
     gpio_mode_set(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_PINS);
     gpio_output_options_set(LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, LED_PINS);
-
-    // SWO trace pin on PB3  
+ 
+    // SWO trace pin on PB3
     gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
-    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
-    gpio_af_set(GPIOB, GPIO_AF_0, GPIO_PIN_3);  
+    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, GPIO_PIN_3);
+    gpio_af_set(GPIOB, GPIO_AF_0, GPIO_PIN_3);   
 }
 
 void platform_late_init()
@@ -250,8 +261,6 @@ void platform_late_init()
     logmsg("Platform: ", g_platform_name);
     logmsg("FW Version: ", g_log_firmwareversion);
     
-    
-
     if (gpio_input_bit_get(DIP_PORT, DIPSW3_PIN))
     {
         logmsg("DIPSW3 is ON: Enabling SCSI termination");
@@ -289,57 +298,6 @@ void platform_disable_led(void)
     logmsg("Disabling status LED");
 }
 
-/*****************************************/
-/* Supply voltage monitor                */
-/*****************************************/
-
-// Use ADC to implement supply voltage monitoring for the +3.0V rail.
-// This works by sampling the Vrefint, which has
-// a voltage of 1.2 V, allowing to calculate the VDD voltage.
-static void adc_poll()
-{
-#if PLATFORM_VDD_WARNING_LIMIT_mV > 0
-    static bool initialized = false;
-    static int lowest_vdd_seen = PLATFORM_VDD_WARNING_LIMIT_mV;
-
-    if (!initialized)
-    {
-        rcu_periph_clock_enable(RCU_ADC0);
-        adc_enable(ADC0);
-        adc_calibration_enable(ADC0);
-        adc_channel_16_to_18(ADC_TEMP_VREF_CHANNEL_SWITCH, ENABLE);
-        adc_inserted_channel_config(ADC0, 0, ADC_CHANNEL_17, ADC_SAMPLETIME_144);
-        //TODO can these be safely removed
-        /*
-        adc_external_trigger_source_config(ADC0, ADC_INSERTED_CHANNEL, ADC0_1_2_EXTTRIG_INSERTED_NONE);
-        adc_external_trigger_config(ADC0, ADC_INSERTED_CHANNEL, ENABLE);
-        */
-        adc_software_trigger_enable(ADC0, ADC_INSERTED_CHANNEL);
-        initialized = true;
-    }
-
-    // Read previous result and start new one
-    int adc_value = ADC_IDATA0(ADC0);
-    adc_software_trigger_enable(ADC0, ADC_INSERTED_CHANNEL);
-
-    // adc_value = 1200mV * 4096 / Vdd
-    // => Vdd = 1200mV * 4096 / adc_value
-    // To avoid wasting time on division, compare against
-    // limit directly.
-    const int limit = (1200 * 4096) / PLATFORM_VDD_WARNING_LIMIT_mV;
-    if (adc_value > limit)
-    {
-        // Warn once, and then again if we detect even a lower drop.
-        int vdd_mV = (1200 * 4096) / adc_value;
-        if (vdd_mV < lowest_vdd_seen)
-        {
-            logmsg("WARNING: Detected supply voltage drop to ", vdd_mV, "mV. Verify power supply is adequate.");
-            lowest_vdd_seen = vdd_mV - 50; // Small hysteresis to avoid excessive warnings
-        }
-    }
-#endif
-}
-
 /*****************************************/
 /* Debug logging and watchdog            */
 /*****************************************/
@@ -347,35 +305,28 @@ static void adc_poll()
 // Send log data to USB UART if USB is connected.
 // Data is retrieved from the shared log ring buffer and
 // this function sends as much as fits in USB CDC buffer.
-//
-// This is normally called by platform_reset_watchdog() in
-// the normal polling loop. If code hangs, the watchdog_callback()
-// also starts calling this after 2 seconds.
-// This ensures that log messages get passed even if code hangs,
-// but does not unnecessarily delay normal execution.
-static void usb_log_poll()
-{
-    static uint32_t logpos = 0;
-
-    if (usb_hs_ready())
-    {
-        // Retrieve pointer to log start and determine number of bytes available.
-        uint32_t available = 0;
-        const char *data = log_get_buffer(&logpos, &available);
-        // Limit to CDC packet size
-        uint32_t len = available;
-        if (len == 0) return;
-        if (len > USB_CDC_EP_IN_WORKING_SIZE) len = USB_CDC_EP_IN_WORKING_SIZE;
-
-        // Update log position by the actual number of bytes sent
-        // If USB CDC buffer is full, this may be 0
-        usb_hs_send((uint8_t*)data, len);
-        logpos -= available - len;
-    }
-}
-
-
 
+// \todo add serial logging for the F4
+// static void usb_log_poll()
+// {
+//     static uint32_t logpos = 0;
+
+//     if (usb_serial_ready())
+//     {
+//         // Retrieve pointer to log start and determine number of bytes available.
+//         uint32_t available = 0;
+//         const char *data = log_get_buffer(&logpos, &available);
+//         // Limit to CDC packet size
+//         uint32_t len = available;
+//         if (len == 0) return;
+//         if (len > USB_CDC_DATA_PACKET_SIZE) len = USB_CDC_DATA_PACKET_SIZE;
+
+//         // Update log position by the actual number of bytes sent
+//         // If USB CDC buffer is full, this may be 0
+//         usb_serial_send((uint8_t*)data, len);
+//         logpos -= available - len;
+//     }
+// }
 
 /*****************************************/
 /* Crash handlers                        */
@@ -554,7 +505,7 @@ void platform_reset_watchdog()
 void platform_poll()
 {
     // adc_poll();
-    usb_log_poll();
+    // usb_log_poll();
 }
 
 uint8_t platform_get_buttons()

+ 2 - 2
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.h

@@ -38,7 +38,6 @@ extern "C" {
 
 extern const char *g_platform_name;
 
-
 #if defined(ZULUSCSI_V1_4)
 #   define PLATFORM_NAME "ZuluSCSI v1.4"
 #   define PLATFORM_REVISION "1.4"
@@ -77,7 +76,8 @@ static inline void delay_us(unsigned long us)
 // Approximate fast delay
 static inline void delay_100ns()
 {
-    asm volatile ("nop \n nop \n nop \n nop \n nop");
+//    asm volatile ("nop \n nop \n nop \n nop \n nop");
+   asm volatile ("nop \n nop \n nop \n nop \n nop");
 }
 
 // Initialize SPI and GPIO configuration

+ 1 - 1
lib/ZuluSCSI_platform_GD32F450/greenpak.cpp

@@ -63,7 +63,7 @@ static void greenpak_gpio_init()
     uint32_t greenpak_io = GREENPAK_PLD_IO1 | GREENPAK_PLD_IO2 | GREENPAK_PLD_IO3;
     gpio_bit_reset(SCSI_OUT_PORT, greenpak_io);
     gpio_mode_set(GREENPAK_PLD_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, greenpak_io);
-    gpio_output_options_set(GREENPAK_PLD_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, greenpak_io);
+    gpio_output_options_set(GREENPAK_PLD_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, greenpak_io);
     
 }
 

+ 8 - 3
lib/ZuluSCSI_platform_GD32F450/scsiPhy.cpp

@@ -153,7 +153,7 @@ static void selectPhyMode()
     int default_mode = PHY_MODE_BEST_AVAILABLE;
 
     // Read overriding setting from configuration file
-    int wanted_mode = getSystemSettings()->deviceType;
+    int wanted_mode = g_scsi_settings.getSystem()->phyMode;
 
     // Default: software GPIO bitbang, available on all revisions
     g_scsi_phy_mode = PHY_MODE_PIO;
@@ -602,6 +602,9 @@ void SCSI_SEL_IRQ (void)
 
 static void init_irqs()
 {
+    // Enable SYSCFG clock to set EXTI lines
+    rcu_periph_clock_enable(RCU_SYSCFG);
+
     // Falling edge of RST pin
     gpio_mode_set(SCSI_RST_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SCSI_RST_PIN);
     syscfg_exti_line_config(SCSI_RST_EXTI_SOURCE_PORT, SCSI_RST_EXTI_SOURCE_PIN);
@@ -610,14 +613,16 @@ static void init_irqs()
     NVIC_EnableIRQ(SCSI_RST_IRQn);
 
     // Rising edge of BSY pin
-    gpio_mode_set(SCSI_BSY_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SCSI_BSY_PIN);
+    // \todo unsure if this should be commented out
+    // gpio_mode_set(SCSI_BSY_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SCSI_BSY_PIN);
     syscfg_exti_line_config(SCSI_BSY_EXTI_SOURCE_PORT, SCSI_BSY_EXTI_SOURCE_PIN);
     exti_init(SCSI_BSY_EXTI, EXTI_INTERRUPT, EXTI_TRIG_RISING);
     NVIC_SetPriority(SCSI_BSY_IRQn, 1);
     NVIC_EnableIRQ(SCSI_BSY_IRQn);
 
     // Falling edge of SEL pin
-    gpio_mode_set(SCSI_SEL_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SCSI_SEL_PIN);
+    // \todo unsure if this should be commented out
+    // gpio_mode_set(SCSI_SEL_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SCSI_SEL_PIN);
     syscfg_exti_line_config(SCSI_SEL_EXTI_SOURCE_PORT, SCSI_SEL_EXTI_SOURCE_PIN);
     exti_init(SCSI_SEL_EXTI, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
     NVIC_SetPriority(SCSI_SEL_IRQn, 1);

+ 8 - 68
lib/ZuluSCSI_platform_GD32F450/scsi_accel_dma.cpp

@@ -121,7 +121,7 @@ void scsi_accel_timer_dma_init()
     };
     dma_multi_data_mode_init(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB, &timer_dma_config);
     dma_channel_subperipheral_select(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB, SCSI_TIMER_DMACHB_SUB_PERIPH);
-    NVIC_SetPriority(SCSI_TIMER_DMACHB_IRQn, 2);
+    NVIC_SetPriority(SCSI_TIMER_DMACHB_IRQn, 128); // Priority = 128 to make sure this is lower priority independent of priority grouping
     NVIC_EnableIRQ(SCSI_TIMER_DMACHB_IRQn);
 
     g_scsi_dma.timer_buf = TIMER_SWEVG_UPG;
@@ -145,8 +145,9 @@ void scsi_accel_timer_dma_init()
     TIMER_CH1CV(SCSI_TIMER) = 1; // Copy data when ACK goes low
     TIMER_CH2CV(SCSI_TIMER) = 1; // REQ is low until ACK goes low
     TIMER_CH3CV(SCSI_TIMER) = 2; // Reset timer after ACK goes high & previous DMA is complete
+
     gpio_mode_set(SCSI_TIMER_IN_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SCSI_TIMER_IN_PIN);
-    gpio_af_set(SCSI_TIMER_IN_PORT, SCSI_TIMER_IN_AF, SCSI_TIMER_IN_PIN);   
+    gpio_af_set(SCSI_TIMER_IN_PORT, SCSI_TIMER_IN_AF, SCSI_TIMER_IN_PIN);    
     scsi_accel_dma_stopWrite();
 }
 
@@ -155,12 +156,6 @@ static void scsi_dma_gpio_config(bool enable)
 {
     if (enable)
     {
-        //gpio_init(SCSI_OUT_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, SCSI_OUT_REQ);
-
-        gpio_mode_set(SCSI_OUT_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, SCSI_OUT_REQ);
-        
-
-
         if (g_scsi_dma_use_greenpak)
         {
             GPIO_BC(SCSI_OUT_PORT) = GREENPAK_PLD_IO1;
@@ -168,9 +163,9 @@ static void scsi_dma_gpio_config(bool enable)
         }
         else
         {
+            gpio_mode_set(SCSI_OUT_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, SCSI_OUT_REQ);
             gpio_mode_set(SCSI_TIMER_OUT_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SCSI_TIMER_OUT_PIN);
-            // @TODO determine if the output should be set to 200MHZ instead of 50MHZ
-            gpio_output_options_set(SCSI_TIMER_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SCSI_TIMER_OUT_PIN);
+            gpio_output_options_set(SCSI_TIMER_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SCSI_TIMER_OUT_PIN);
             gpio_af_set(SCSI_TIMER_OUT_PORT, SCSI_TIMER_OUT_AF, SCSI_TIMER_OUT_PIN);
         }
     }
@@ -178,10 +173,10 @@ static void scsi_dma_gpio_config(bool enable)
     {
         GPIO_BC(SCSI_OUT_PORT) = GREENPAK_PLD_IO2;
         gpio_mode_set(SCSI_TIMER_OUT_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SCSI_TIMER_OUT_PIN);
-        gpio_output_options_set(SCSI_TIMER_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SCSI_TIMER_OUT_PIN);
+        gpio_output_options_set(SCSI_TIMER_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SCSI_TIMER_OUT_PIN);
         
         gpio_mode_set(SCSI_OUT_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCSI_OUT_REQ);
-        gpio_output_options_set(SCSI_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_REQ);
+        gpio_output_options_set(SCSI_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SCSI_OUT_REQ);
     }
 }
 
@@ -292,13 +287,9 @@ static void stop_dma()
     greenpak_stop_dma();
 
     dma_channel_disable(SCSI_TIMER_DMA, SCSI_TIMER_DMACHA);
-    // DMA_CHCTL(SCSI_TIMER_DMA, SCSI_TIMER_DMACHA) &= ~DMA_CHXCTL_CHEN;
     dma_channel_disable(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB);
-    // DMA_CHCTL(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB) &= ~DMA_CHXCTL_CHEN;
     dma_interrupt_disable(SCSI_TIMER_DMA, SCSI_TIMER_DMACHA, DMA_CHXCTL_FTFIE | DMA_CHXCTL_HTFIE);
-    // DMA_CHCTL(SCSI_TIMER_DMA, SCSI_TIMER_DMACHA) &= ~(DMA_CHXCTL_FTFIE | DMA_CHXCTL_HTFIE);
     dma_interrupt_disable(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB, DMA_CHXCTL_FTFIE);
-    //DMA_CHCTL(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB) &= ~DMA_CHXCTL_FTFIE;
 
     // Wait for ACK of the last byte
     volatile int timeout = 10000;
@@ -333,12 +324,7 @@ static void check_dma_next_buffer()
 // Convert new data from application buffer to DMA buffer
 extern "C" void SCSI_TIMER_DMACHA_IRQ()
 {
-    // dbgmsg("DMA irq A, counts: ", DMA_CHCNT(SCSI_TIMER_DMA, SCSI_TIMER_DMACHA), " ",
-    //             DMA_CHCNT(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB), " ",
-    //             TIMER_CNT(SCSI_TIMER));
-
- 
-   uint32_t intf0 = DMA_INTF0(SCSI_TIMER_DMA);
+    uint32_t intf0 = DMA_INTF0(SCSI_TIMER_DMA);
     uint32_t intf1 = DMA_INTF1(SCSI_TIMER_DMA);
 
     if (dma_interrupt_flag_get(SCSI_TIMER_DMA, SCSI_TIMER_DMACHA, DMA_FLAG_HTF))
@@ -413,15 +399,6 @@ extern "C" void SCSI_TIMER_DMACHB_IRQ()
                 __enable_irq();
             }
 
-            // Verify the first byte of the new data has been written to outputs
-            // It may have been updated after the DMA write occurred.
-/*  @TODO Is this still needed?
-            __disable_irq();
-            uint32_t first_data_idx = g_scsi_dma.dma_idx - (g_scsi_dma.bytes_dma - g_scsi_dma.scheduled_dma);
-            uint32_t first_data = g_scsi_dma.dma_buf[first_data_idx & DMA_BUF_MASK];
-            GPIO_BOP(SCSI_OUT_PORT) = first_data;
-            __enable_irq();
-*/
             // Update the total number of bytes available for DMA
             uint32_t dma_to_schedule = g_scsi_dma.bytes_app - g_scsi_dma.scheduled_dma;
             dma_channel_disable(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB);
@@ -435,43 +412,6 @@ extern "C" void SCSI_TIMER_DMACHB_IRQ()
             stop_dma();
         }
     }
-
-
-
-    // dbgmsg("DMA irq B, counts: ", DMA_CHCNT(SCSI_TIMER_DMA, SCSI_TIMER_DMACHA), " ",
-    //             DMA_CHCNT(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB), " ",
-    //             TIMER_CNT(SCSI_TIMER));
-    if (dma_interrupt_flag_get(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB, DMA_FLAG_FTF))
-    {
-        dma_interrupt_flag_clear(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB, DMA_FLAG_FTF);
-
-        if (g_scsi_dma.bytes_app > g_scsi_dma.scheduled_dma)
-        {
-            if (g_scsi_dma.dma_idx < g_scsi_dma.dma_fillto)
-            {
-                // Previous request didn't have a complete buffer worth of data.
-                // Refill the buffer and ensure that the first byte of the new data gets
-                // written to outputs.
-                __disable_irq();
-                refill_dmabuf();
-                __enable_irq();
-            }
-
-
-
-            // Update the total number of bytes available for DMA
-            uint32_t dma_to_schedule = g_scsi_dma.bytes_app - g_scsi_dma.scheduled_dma;
-            DMA_CHCTL(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB) &= ~DMA_CHXCTL_CHEN;
-            DMA_CHCNT(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB) = dma_to_schedule;
-            DMA_CHCTL(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB) |= DMA_CHXCTL_CHEN;
-            g_scsi_dma.scheduled_dma += dma_to_schedule;
-        }
-        else
-        {
-            // No more data available
-            stop_dma();
-        }
-    }
 }
 
 void scsi_accel_dma_startWrite(const uint8_t* data, uint32_t count, volatile int *resetFlag)

+ 2 - 2
lib/ZuluSCSI_platform_GD32F450/scsi_accel_greenpak.cpp

@@ -141,7 +141,7 @@ void scsi_accel_greenpak_send(const uint32_t *buf, uint32_t num_words, volatile
     // Disable external logic and set REQ pin as output
     GPIO_BC(SCSI_OUT_PORT) = GREENPAK_PLD_IO2;
     gpio_mode_set(SCSI_OUT_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE , SCSI_OUT_REQ);
-    gpio_output_options_set(SCSI_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_REQ);
+    gpio_output_options_set(SCSI_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SCSI_OUT_REQ);
 }
 
 /**********************************************/
@@ -381,7 +381,7 @@ void scsi_accel_greenpak_recv(uint32_t *buf, uint32_t num_words, volatile int *r
     // Disable external logic and set REQ pin as output
     GPIO_BC(SCSI_OUT_PORT) = GREENPAK_PLD_IO2;
     gpio_mode_set(SCSI_OUT_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCSI_OUT_REQ);
-    gpio_output_options_set(SCSI_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_REQ);
+    gpio_output_options_set(SCSI_OUT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SCSI_OUT_REQ);
     GPIO_BC(SCSI_OUT_PORT) = GREENPAK_PLD_IO3;
 }
 

+ 11 - 5
lib/ZuluSCSI_platform_GD32F450/scsi_accel_sync.cpp

@@ -111,11 +111,13 @@ void scsi_accel_sync_init()
     // };
     // dma_single_data_mode_init(SCSI_EXMC_DMA, SCSI_EXMC_DMACH, &exmc_dma_config);
     gpio_mode_set(SCSI_IN_ACK_EXMC_NWAIT_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SCSI_IN_ACK_EXMC_NWAIT_PIN);
+    gpio_output_options_set(SCSI_IN_ACK_EXMC_NWAIT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SCSI_IN_ACK_EXMC_NWAIT_PIN);
     gpio_af_set(SCSI_IN_ACK_EXMC_NWAIT_PORT, GPIO_AF_12, SCSI_IN_ACK_EXMC_NWAIT_PIN);
 
     // TIMER1 CH0 port and pin enable
     gpio_mode_set(SCSI_ACK_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SCSI_ACK_PIN);
     gpio_af_set(SCSI_ACK_PORT, GPIO_AF_1, SCSI_ACK_PIN);
+    
     // TIMER1 is used to count ACK pulses
     TIMER_CTL0(SCSI_SYNC_TIMER) = 0;
     TIMER_SMCFG(SCSI_SYNC_TIMER) = TIMER_SLAVE_MODE_EXTERNAL0 | TIMER_SMCFG_TRGSEL_CI0FE0;
@@ -126,6 +128,12 @@ void scsi_accel_sync_init()
 
 void scsi_accel_sync_recv(uint8_t *data, uint32_t count, int* parityError, volatile int *resetFlag)
 {
+    // Set SCSI data IN pins to external memory mode
+    gpio_mode_set(SCSI_IN_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SCSI_IN_MASK);
+    gpio_output_options_set(SCSI_IN_PORT, GPIO_PUPD_NONE, GPIO_OSPEED_200MHZ, SCSI_IN_MASK);
+    gpio_af_set(SCSI_IN_PORT, GPIO_AF_12, SCSI_IN_MASK);
+
+    
     // Enable EXMC to drive REQ from EXMC_NOE pin
     EXMC_SNCTL(EXMC_BANK0_NORSRAM_REGION0) |= EXMC_SNCTL_NRBKEN;
 
@@ -136,9 +144,8 @@ void scsi_accel_sync_recv(uint8_t *data, uint32_t count, int* parityError, volat
     uint32_t oldmode_gpio_omode = GPIO_OMODE(SCSI_OUT_REQ_EXMC_NOE_PORT);
     uint32_t oldmode_gpio_af = GPIO_AFSEL0(SCSI_OUT_REQ_EXMC_NOE_PORT);
 
-    // @TODO figure out ouput speed should be set to 200MHz
     gpio_af_set(SCSI_OUT_REQ_EXMC_NOE_PORT, GPIO_AF_12, SCSI_OUT_REQ_EXMC_NOE_PIN);
-    gpio_output_options_set(SCSI_OUT_REQ_EXMC_NOE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_REQ_EXMC_NOE_PIN);
+    gpio_output_options_set(SCSI_OUT_REQ_EXMC_NOE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, SCSI_OUT_REQ_EXMC_NOE_PIN);
     gpio_mode_set(SCSI_OUT_REQ_EXMC_NOE_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SCSI_OUT_REQ_EXMC_NOE_PIN);
     
     while (count > 0)
@@ -149,11 +156,11 @@ void scsi_accel_sync_recv(uint8_t *data, uint32_t count, int* parityError, volat
         // dma_memory_address_config(SCSI_EXMC_DMA, SCSI_EXMC_DMACH, 0, (uint32_t)g_sync_dma_buf);
         // dma_transfer_number_config(SCSI_EXMC_DMA, SCSI_EXMC_DMACH, blocksize);
         // dma_channel_enable(SCSI_EXMC_DMA, SCSI_EXMC_DMACH);
-
         uint16_t *src = (uint16_t*)g_sync_dma_buf;
         uint8_t *dst = data;
         uint8_t *end = data + blocksize;
         uint32_t start = millis();
+
         while (dst < end)
         {
             // Read from EXMC and write to internal RAM
@@ -189,7 +196,6 @@ void scsi_accel_sync_recv(uint8_t *data, uint32_t count, int* parityError, volat
     GPIO_AFSEL0(SCSI_OUT_REQ_EXMC_NOE_PORT) = oldmode_gpio_af;
 
 
-
 }
 
 /********************************/
@@ -301,7 +307,7 @@ static void sync_send_100ns_15off(const uint8_t *buf, uint32_t num_bytes, volati
         "   subs  %[num_bytes], %[num_bytes], #16 \n"
         "   bmi     last_bytes_%= \n"
 
-       /* At each point make sure there is at most 15 bytes in flight */
+        /* At each point make sure there is at most 15 bytes in flight */
         "   ldr   %[data], [%[buf]], #4 \n"
         ASM_SEND_4BYTES_WAIT("26")
         ASM_DELAY2()

+ 0 - 2
lib/ZuluSCSI_platform_GD32F450/sd_card_sdio.cpp

@@ -25,8 +25,6 @@
 #include "ZuluSCSI_platform.h"
 
 #ifdef SD_USE_SDIO
-
-
 extern "C"
 {
 #include "gd32f4xx_sdio.h"

+ 274 - 0
lib/ZuluSCSI_platform_GD32F450/sd_card_spi.cpp

@@ -0,0 +1,274 @@
+// Driver and interface for accessing SD card in SPI mode
+// Used on ZuluSCSI v1.0.
+
+#include "ZuluSCSI_platform.h"
+#include "ZuluSCSI_log.h"
+#include "gd32f4xx_spi.h"
+#include "gd32f4xx_dma.h"
+#include <SdFat.h>
+
+#ifndef SD_USE_SDIO
+
+class GD32SPIDriver : public SdSpiBaseClass
+{
+public:
+    void begin(SdSpiConfig config) {
+        rcu_periph_clock_enable(RCU_SPI0);
+        rcu_periph_clock_enable(RCU_DMA0);
+
+        dma_parameter_struct rx_dma_config =
+        {
+            .periph_addr = (uint32_t)&SPI_DATA(SD_SPI),
+            .periph_width = DMA_PERIPHERAL_WIDTH_8BIT,
+            .memory_addr = 0, // Set before transfer
+            .memory_width = DMA_MEMORY_WIDTH_8BIT,
+            .number = 0, // Set before transfer
+            .priority = DMA_PRIORITY_ULTRA_HIGH,
+            .periph_inc = DMA_PERIPH_INCREASE_DISABLE,
+            .memory_inc = DMA_MEMORY_INCREASE_ENABLE,
+            .direction = DMA_PERIPHERAL_TO_MEMORY
+        };
+        dma_init(DMA0, SD_SPI_RX_DMA_CHANNEL, &rx_dma_config);
+
+        dma_parameter_struct tx_dma_config =
+        {
+            .periph_addr = (uint32_t)&SPI_DATA(SD_SPI),
+            .periph_width = DMA_PERIPHERAL_WIDTH_8BIT,
+            .memory_addr = 0, // Set before transfer
+            .memory_width = DMA_MEMORY_WIDTH_8BIT,
+            .number = 0, // Set before transfer
+            .priority = DMA_PRIORITY_HIGH,
+            .periph_inc = DMA_PERIPH_INCREASE_DISABLE,
+            .memory_inc = DMA_MEMORY_INCREASE_ENABLE,
+            .direction = DMA_MEMORY_TO_PERIPHERAL
+        };
+        dma_init(DMA0, SD_SPI_TX_DMA_CHANNEL, &tx_dma_config);
+    }
+        
+    void activate() {
+        spi_parameter_struct config = {
+            SPI_MASTER,
+            SPI_TRANSMODE_FULLDUPLEX,
+            SPI_FRAMESIZE_8BIT,
+            SPI_NSS_SOFT,
+            SPI_ENDIAN_MSB,
+            SPI_CK_PL_LOW_PH_1EDGE,
+            SPI_PSC_256
+        };
+
+        // Select closest available divider based on system frequency
+        int divider = (SystemCoreClock + m_sckfreq / 2) / m_sckfreq;
+        if (divider <= 2)
+            config.prescale = SPI_PSC_2;
+        else if (divider <= 4)
+            config.prescale = SPI_PSC_4;
+        else if (divider <= 8)
+            config.prescale = SPI_PSC_8;
+        else if (divider <= 16)
+            config.prescale = SPI_PSC_16;
+        else if (divider <= 32)
+            config.prescale = SPI_PSC_32;
+        else if (divider <= 64)
+            config.prescale = SPI_PSC_64;
+        else if (divider <= 128)
+            config.prescale = SPI_PSC_128;
+        else
+            config.prescale = SPI_PSC_256;
+
+        spi_init(SD_SPI, &config);
+        spi_enable(SD_SPI);
+    }
+    
+    void deactivate() {
+        spi_disable(SD_SPI);
+    }
+
+    void wait_idle() {
+        while (!(SPI_STAT(SD_SPI) & SPI_STAT_TBE));
+        while (SPI_STAT(SD_SPI) & SPI_STAT_TRANS);
+    }
+
+    // Single byte receive
+    uint8_t receive() {
+        // Wait for idle and clear RX buffer
+        wait_idle();
+        (void)SPI_DATA(SD_SPI);
+
+        // Send dummy byte and wait for receive
+        SPI_DATA(SD_SPI) = 0xFF;
+        while (!(SPI_STAT(SD_SPI) & SPI_STAT_RBNE));
+        return SPI_DATA(SD_SPI);
+    }
+
+    // Single byte send
+    void send(uint8_t data) {
+        SPI_DATA(SD_SPI) = data;
+        wait_idle();
+    }
+
+    // Multiple byte receive
+    uint8_t receive(uint8_t* buf, size_t count)
+    {
+        // Wait for idle and clear RX buffer
+        wait_idle();
+        (void)SPI_DATA(SD_SPI);
+
+        // Check if this is part of callback streaming request
+        bool stream = false;
+        if (m_stream_callback && buf == m_stream_buffer + m_stream_count)
+        {
+            stream = true;
+        }
+        else if (m_stream_callback)
+        {
+            dbgmsg("Stream buffer mismatch: ", (uint32_t)buf, " vs. ", (uint32_t)(m_stream_buffer + m_stream_count));
+        }
+
+        // Use DMA to stream dummy TX data and store RX data
+        uint8_t tx_data = 0xFF;
+        DMA_INTC(DMA0) = DMA_FLAG_ADD(DMA_FLAG_FTF | DMA_FLAG_ERR, SD_SPI_RX_DMA_CHANNEL);
+        DMA_INTC(DMA0) = DMA_FLAG_ADD(DMA_FLAG_FTF | DMA_FLAG_ERR, SD_SPI_TX_DMA_CHANNEL);
+        DMA_CHMADDR(DMA0, SD_SPI_RX_DMA_CHANNEL) = (uint32_t)buf;
+        DMA_CHMADDR(DMA0, SD_SPI_TX_DMA_CHANNEL) = (uint32_t)&tx_data;
+        DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) &= ~DMA_CHXCTL_MNAGA; // No memory increment for TX
+        DMA_CHCNT(DMA0, SD_SPI_RX_DMA_CHANNEL) = count;
+        DMA_CHCNT(DMA0, SD_SPI_TX_DMA_CHANNEL) = count;
+        DMA_CHCTL(DMA0, SD_SPI_RX_DMA_CHANNEL) |= DMA_CHXCTL_CHEN;
+        DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) |= DMA_CHXCTL_CHEN;
+
+        SPI_CTL1(SD_SPI) |= SPI_CTL1_DMAREN | SPI_CTL1_DMATEN;
+        
+        uint32_t start = millis();
+        while (!(DMA_INTF(DMA0) & DMA_FLAG_ADD(DMA_FLAG_FTF | DMA_FLAG_ERR, SD_SPI_RX_DMA_CHANNEL)))
+        {
+            if (millis() - start > 500)
+            {
+                logmsg("ERROR: SPI DMA receive of ", (int)count, " bytes timeouted");
+                return 1;
+            }
+
+            if (stream)
+            {
+                uint32_t complete = m_stream_count + (count - DMA_CHCNT(DMA0, SD_SPI_RX_DMA_CHANNEL));
+                m_stream_callback(complete);
+            }
+        }
+
+        if (DMA_INTF(DMA0) & DMA_FLAG_ADD(DMA_FLAG_ERR, SD_SPI_RX_DMA_CHANNEL))
+        {
+            logmsg("ERROR: SPI DMA receive set DMA_FLAG_ERR");
+        }
+
+        SPI_CTL1(SD_SPI) &= ~(SPI_CTL1_DMAREN | SPI_CTL1_DMATEN);
+        DMA_CHCTL(DMA0, SD_SPI_RX_DMA_CHANNEL) &= ~DMA_CHXCTL_CHEN;
+        DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) &= ~DMA_CHXCTL_CHEN;
+
+        if (stream)
+        {
+            m_stream_count += count;
+        }
+
+        return 0;
+    }
+
+    // Multiple byte send
+    void send(const uint8_t* buf, size_t count) {
+        // Check if this is part of callback streaming request
+        bool stream = false;
+        if (m_stream_callback && buf == m_stream_buffer + m_stream_count)
+        {
+            stream = true;
+        }
+        else if (m_stream_callback)
+        {
+            dbgmsg("Stream buffer mismatch: ", (uint32_t)buf, " vs. ", (uint32_t)(m_stream_buffer + m_stream_count));
+        }
+
+        // Use DMA to stream TX data
+        DMA_INTC(DMA0) = DMA_FLAG_ADD(DMA_FLAG_FTF | DMA_FLAG_ERR, SD_SPI_TX_DMA_CHANNEL);
+        DMA_CHMADDR(DMA0, SD_SPI_TX_DMA_CHANNEL) = (uint32_t)buf;
+        DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) |= DMA_CHXCTL_MNAGA; // Memory increment for TX
+        DMA_CHCNT(DMA0, SD_SPI_TX_DMA_CHANNEL) = count;
+        DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) |= DMA_CHXCTL_CHEN;
+
+        SPI_CTL1(SD_SPI) |= SPI_CTL1_DMATEN;
+        
+        uint32_t start = millis();
+        while (!(DMA_INTF(DMA0) & DMA_FLAG_ADD(DMA_FLAG_FTF | DMA_FLAG_ERR, SD_SPI_TX_DMA_CHANNEL)))
+        {
+            if (millis() - start > 500)
+            {
+                logmsg("ERROR: SPI DMA transmit of ", (int)count, " bytes timeouted");
+                return;
+            }
+
+            if (stream)
+            {
+                uint32_t complete = m_stream_count + (count - DMA_CHCNT(DMA0, SD_SPI_TX_DMA_CHANNEL));
+                m_stream_callback(complete);
+            }
+        }
+
+        if (DMA_INTF(DMA0) & DMA_FLAG_ADD(DMA_FLAG_ERR, SD_SPI_TX_DMA_CHANNEL))
+        {
+            logmsg("ERROR: SPI DMA transmit set DMA_FLAG_ERR");
+        }
+
+        wait_idle();
+
+        SPI_CTL1(SD_SPI) &= ~(SPI_CTL1_DMAREN | SPI_CTL1_DMATEN);
+        DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) &= ~DMA_CHXCTL_CHEN;
+
+        if (stream)
+        {
+            m_stream_count += count;
+        }
+    }
+
+    void setSckSpeed(uint32_t maxSck) {
+        m_sckfreq = maxSck;
+    }
+
+    void set_sd_callback(sd_callback_t func, const uint8_t *buffer)
+    {
+        m_stream_buffer = buffer;
+        m_stream_count = 0;
+        m_stream_callback = func;
+    }
+
+private:
+    uint32_t m_sckfreq;
+    const uint8_t *m_stream_buffer;
+    uint32_t m_stream_count;
+    sd_callback_t m_stream_callback;
+};
+
+void sdCsInit(SdCsPin_t pin)
+{
+}
+
+void sdCsWrite(SdCsPin_t pin, bool level)
+{
+    if (level)
+        GPIO_BOP(SD_PORT) = SD_CS_PIN;
+    else
+        GPIO_BC(SD_PORT) = SD_CS_PIN;
+}
+
+GD32SPIDriver g_sd_spi_port;
+SdSpiConfig g_sd_spi_config(0, DEDICATED_SPI, SD_SCK_MHZ(30), &g_sd_spi_port);
+
+void platform_set_sd_callback(sd_callback_t func, const uint8_t *buffer)
+{
+    g_sd_spi_port.set_sd_callback(func, buffer);    
+}
+
+// Check if a DMA request for SD card read has completed.
+// This is used to optimize the timing of data transfers on SCSI bus.
+bool check_sd_read_done()
+{
+    return (DMA_CHCTL(DMA0, SD_SPI_RX_DMA_CHANNEL) & DMA_CHXCTL_CHEN)
+        && (DMA_INTF(DMA0) & DMA_FLAG_ADD(DMA_FLAG_FTF, SD_SPI_RX_DMA_CHANNEL));
+}
+
+#endif

+ 7 - 4
platformio.ini

@@ -246,14 +246,17 @@ build_flags =
 	-DCYW43_LWIP=0
 	-DCYW43_USE_OTP_MAC=0
     -DPLATFORM_MASS_STORAGE
-    
-; ZuluSCSI F4 hardware platform with GD32F450ZET6 CPU.
-[env:ZuluSCSIv1_4]
+
+; ZuluSCSI VF4 hardware platform with GD32F450ZET6 CPU.
+[env:ZULUSCSIv1_4]
 platform = https://github.com/CommunityGD32Cores/platform-gd32.git
 board = genericGD32F450ZE
 board_build.mcu = gd32f450zet6
 board_build.core = gd32
 board_build.ldscript = lib/ZuluSCSI_platform_GD32F450/zuluscsi_gd32f450.ld
+lib_ignore = 
+    ZuluSCSI_platform_GD32F205
+    ZuluSCSI_platform_RP2040
 ldscript_bootloader = lib/ZuluSCSI_platform_GD32F450/zuluscsi_gd32f450_btldr.ld
 framework = spl
 lib_compat_mode = off
@@ -269,7 +272,7 @@ platform_packages =
     toolchain-gccarmnoneeabi@1.90201.191206
     framework-spl-gd32@https://github.com/CommunityGD32Cores/gd32-pio-spl-package.git
 extra_scripts = src/build_bootloader.py
-debug_tool = cmsis-dap
+debug_tool = stlink
 debug_build_flags = -Os -ggdb -g3
 build_flags = 
      -Os -Wall -Wno-sign-compare -ggdb -g3 -Isrc