Browse Source

Use DMA for SPI receive

Petteri Aimonen 3 years ago
parent
commit
807410a1e9
1 changed files with 66 additions and 7 deletions
  1. 66 7
      lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.cpp

+ 66 - 7
lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.cpp

@@ -1,5 +1,6 @@
 #include "AzulSCSI_platform.h"
 #include "gd32f20x_spi.h"
+#include "gd32f20x_dma.h"
 #include "AzulSCSI_log.h"
 #include "AzulSCSI_config.h"
 #include <SdFat.h>
@@ -294,11 +295,43 @@ extern volatile bool g_busreset;
   }
 
 #define SD_SPI SPI0
+#define SD_SPI_RX_DMA_CHANNEL DMA_CH1
+#define SD_SPI_TX_DMA_CHANNEL DMA_CH2
+
 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() {
@@ -363,18 +396,44 @@ public:
         if (buf == m_stream_buffer + m_stream_status)
         {
             // Stream data directly to SCSI bus
-            return stream_receive(count);
+            return stream_receive(buf, count);
         }
         
-        // Store data to buffer
-        for (size_t i = 0; i < count; i++)
+        // Stream to memory
+        
+        // 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)))
         {
-            while (!(SPI_STAT(SD_SPI) & SPI_STAT_TBE));
-            SPI_DATA(SD_SPI) = 0xFF;
-            while (!(SPI_STAT(SD_SPI) & SPI_STAT_RBNE));
-            buf[i] = SPI_DATA(SD_SPI);
+            if (millis() - start > 500)
+            {
+                azlog("ERROR: SPI DMA receive of ", (int)count, " bytes timeouted");
+                return 1;
+            }
         }
 
+        if (DMA_INTF(DMA0) & DMA_FLAG_ADD(DMA_FLAG_ERR, SD_SPI_RX_DMA_CHANNEL))
+        {
+            azlog("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;
+
         return 0;
     }