Browse Source

Fix read error when DMA_TIMER is enabled (#28)

Occassionally there would be a race condition between interrupt
handlers, resulting in single byte error in reads.
Petteri Aimonen 3 years ago
parent
commit
d3f91d93d7
1 changed files with 16 additions and 2 deletions
  1. 16 2
      lib/AzulSCSI_platform_GD32F205/scsi_accel_dma.cpp

+ 16 - 2
lib/AzulSCSI_platform_GD32F205/scsi_accel_dma.cpp

@@ -180,6 +180,14 @@ static void refill_dmabuf()
     {
         dst[(pos++) & DMA_BUF_MASK] = g_scsi_out_byte_to_bop[*src++];
     }
+
+    if (end < g_scsi_dma.dma_fillto)
+    {
+        // Partial buffer fill, this will get refilled from interrupt if we
+        // get more data. Set next byte to an invalid parity value so that
+        // any race conditions will get caught as parity error.
+        dst[pos & DMA_BUF_MASK] = g_scsi_out_byte_to_bop[0] ^ SCSI_OUT_DBP;
+    }
 }
 
 // Start DMA transfer
@@ -319,12 +327,18 @@ extern "C" void SCSI_TIMER_DMACHB_IRQ()
                 // Refill the buffer and ensure that the first byte of the new data gets
                 // written to outputs.
                 __disable_irq();
-                uint32_t *first_data = &g_scsi_dma.dma_buf[g_scsi_dma.dma_idx & DMA_BUF_MASK];
                 refill_dmabuf();
-                GPIO_BOP(SCSI_OUT_PORT) = *first_data;
                 __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.
+            __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_CHCTL(SCSI_TIMER_DMA, SCSI_TIMER_DMACHB) &= ~DMA_CHXCTL_CHEN;