فهرست منبع

Avoid SysTick interrupts during transfers (#70)

SysTick interrupts caused short 0.7 us pauses during PIO reads
and all writes. The pauses are probably short enough not to disturb
most hosts. This commit avoids the pauses by executing the SysTick
interrupt before the sector transfer if needed.

If host transfer rate is below 500kB/s, the SysTick interrupt will
still happen every 1 ms during the sector. But in that case the
SCSI cycle time is more than 2 us anyway, so the pause is insignificant.
Petteri Aimonen 3 سال پیش
والد
کامیت
d2ec620924

+ 24 - 0
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp

@@ -78,6 +78,30 @@ void SysTick_Handler(void)
         "b SysTick_Handler_inner": : : "r0");
 }
 
+// This function is called by scsiPhy.cpp.
+// It resets the systick counter to give 1 millisecond of uninterrupted transfer time.
+// The total number of skips is kept track of to keep the correct time on average.
+void SysTick_Handle_PreEmptively()
+{
+    static int skipped_clocks = 0;
+
+    __disable_irq();
+    uint32_t loadval = SysTick->LOAD;
+    skipped_clocks += loadval - SysTick->VAL;
+    SysTick->VAL = 0;
+
+    if (skipped_clocks > loadval)
+    {
+        // We have skipped enough ticks that it is time to fake a call
+        // to SysTick interrupt handler.
+        skipped_clocks -= loadval;
+        uint32_t stack_frame[8] = {0};
+        stack_frame[6] = (uint32_t)__builtin_return_address(0);
+        SysTick_Handler_inner(stack_frame);
+    }
+    __enable_irq();
+}
+
 /***************/
 /* GPIO init   */
 /***************/

+ 5 - 0
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h

@@ -73,6 +73,11 @@ void azplatform_emergency_log_save();
 typedef void (*sd_callback_t)(uint32_t bytes_complete);
 void azplatform_set_sd_callback(sd_callback_t func, const uint8_t *buffer);
 
+// This function is called by scsiPhy.cpp.
+// It resets the systick counter to give 1 millisecond of uninterrupted transfer time.
+// The total number of skips is kept track of to keep the correct time on average.
+void SysTick_Handle_PreEmptively();
+
 // Reprogram firmware in main program area.
 #define AZPLATFORM_BOOTLOADER_SIZE 32768
 #define AZPLATFORM_FLASH_TOTAL_SIZE (256 * 1024)

+ 5 - 0
lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp

@@ -433,6 +433,9 @@ extern "C" bool scsiIsWriteFinished(const uint8_t *data)
         if (max_count % bytesPerSector != 0) max_count -= (max_count % bytesPerSector);
         if (max_count < bytesPerSector) max_count = bytesPerSector;
         
+        // Avoid SysTick interrupt pauses during the transfer
+        SysTick_Handle_PreEmptively();
+
         processPollingWrite(max_count);
         return isPollingWriteFinished(data);
     }
@@ -491,6 +494,8 @@ extern "C" void scsiRead(uint8_t* data, uint32_t count, int* parityError)
     uint32_t count_words = count / 4;
     bool use_greenpak = (g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA || g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO);
 
+    SysTick_Handle_PreEmptively();
+
     if (g_scsi_phase == DATA_OUT && scsiDev.target->syncOffset > 0)
     {
         // Synchronous data transfer