From: Michael McMaster Date: Sun, 22 Jan 2017 07:40:13 +0000 (+1000) Subject: Synch transfer fix X-Git-Tag: v6.1.0~3 X-Git-Url: http://git.codesrc.com/gitweb.cgi?a=commitdiff_plain;h=2ba53be02febfdc02de14d58c1c84bebf5df0380;p=SCSI2SD-V6.git Synch transfer fix --- diff --git a/Makefile b/Makefile index b3fa3f64..b90b51a3 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,8 @@ build/stm32cubemx/stm32f2xx_hal_rcc.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_ build/stm32cubemx/stm32f2xx_hal_sd.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_sd.c build/stm32cubemx/stm32f2xx_hal_spi.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_spi.c build/stm32cubemx/stm32f2xx_hal_sram.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_sram.c +build/stm32cubemx/stm32f2xx_hal_tim.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_tim.c +build/stm32cubemx/stm32f2xx_hal_tim_ex.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_tim_ex.c build/stm32cubemx/stm32f2xx_hal_uart.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_uart.c build/stm32cubemx/stm32f2xx_ll_fsmc.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_ll_fsmc.c build/stm32cubemx/stm32f2xx_ll_sdmmc.o: STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_ll_sdmmc.c @@ -92,6 +94,8 @@ STM32OBJS = \ build/stm32cubemx/stm32f2xx_hal_sd.o \ build/stm32cubemx/stm32f2xx_hal_spi.o \ build/stm32cubemx/stm32f2xx_hal_sram.o \ + build/stm32cubemx/stm32f2xx_hal_tim.o \ + build/stm32cubemx/stm32f2xx_hal_tim_ex.o \ build/stm32cubemx/stm32f2xx_hal_uart.o \ build/stm32cubemx/stm32f2xx_ll_fsmc.o \ build/stm32cubemx/stm32f2xx_ll_sdmmc.o \ @@ -140,6 +144,7 @@ SRC = \ src/firmware/scsiPhy.c \ src/firmware/scsi.c \ src/firmware/sd.c \ + src/firmware/spinlock.c \ src/firmware/tape.c \ src/firmware/time.c \ src/firmware/trace.c \ diff --git a/include/hidpacket.h b/include/hidpacket.h index 9beb0022..384956f8 100644 --- a/include/hidpacket.h +++ b/include/hidpacket.h @@ -42,6 +42,10 @@ void hidPacket_recv(const uint8_t* bytes, size_t len); // available. const uint8_t* hidPacket_getPacket(size_t* len); +// Returns the received packet contents, or NULL if a complete packet isn't +// available. +const uint8_t* hidPacket_peekPacket(size_t* len); + // Call this with packet data to send. len <= USBHID_LEN // Overwrites any packet currently being sent. void hidPacket_send(const uint8_t* bytes, size_t len); diff --git a/rtl/fpga_bitmap.o b/rtl/fpga_bitmap.o index 77e590a8..c4ec7a48 100644 Binary files a/rtl/fpga_bitmap.o and b/rtl/fpga_bitmap.o differ diff --git a/src/firmware/config.c b/src/firmware/config.c index 127ca1b5..9bb8b113 100755 --- a/src/firmware/config.c +++ b/src/firmware/config.c @@ -25,6 +25,7 @@ #include "trace.h" #include "bootloader.h" #include "bsp.h" +#include "spinlock.h" #include "../../include/scsi2sd.h" #include "../../include/hidpacket.h" @@ -64,6 +65,25 @@ enum USB_STATE static int usbInEpState; +static void s2s_debugTimer(); + +// Debug timer to log via USB. +// Timer 6 & 7 is a simple counter with no external IO supported. +static s2s_lock_t usbDevLock = s2s_lock_init; +TIM_HandleTypeDef htim7; +static int debugTimerStarted = 0; +void TIM7_IRQHandler() +{ + HAL_TIM_IRQHandler(&htim7); +} +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (s2s_spin_trylock(&usbDevLock)) { + s2s_debugTimer(); + s2s_spin_unlock(&usbDevLock); + } +} + void s2s_configInit(S2S_BoardCfg* config) { @@ -108,7 +128,25 @@ void s2s_configInit(S2S_BoardCfg* config) config->flags6 = S2S_CFG_ENABLE_TERMINATOR; } } +} +static void debugInit(void) +{ + if (debugTimerStarted == 1) return; + + debugTimerStarted = 1; + // 10ms debug timer to capture logs over USB + __TIM7_CLK_ENABLE(); + htim7.Instance = TIM7; + htim7.Init.Prescaler = 10800 - 1; // 16bit. 108MHz down to 10KHz + htim7.Init.CounterMode = TIM_COUNTERMODE_UP; + htim7.Init.Period = 100 - 1; // 16bit. 10KHz down to 10ms. + htim7.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + HAL_TIM_Base_Init(&htim7); + HAL_TIM_Base_Start_IT(&htim7); + + HAL_NVIC_SetPriority(TIM7_IRQn, 10, 0); + HAL_NVIC_EnableIRQ(TIM7_IRQn); } @@ -262,6 +300,9 @@ processCommand(const uint8_t* cmd, size_t cmdSize) break; case S2S_CMD_DEBUG: + if (debugTimerStarted == 0) { + debugInit(); + } debugCommand(); break; @@ -273,10 +314,12 @@ processCommand(const uint8_t* cmd, size_t cmdSize) void s2s_configPoll() { + s2s_spin_lock(&usbDevLock); + if (!USBD_Composite_IsConfigured(&hUsbDeviceFS)) { usbInEpState = USB_IDLE; - return; + goto out; } if (USBD_HID_IsReportReady(&hUsbDeviceFS)) @@ -322,6 +365,65 @@ void s2s_configPoll() break; } +out: + s2s_spin_unlock(&usbDevLock); +} + +void s2s_debugTimer() +{ + if (!USBD_Composite_IsConfigured(&hUsbDeviceFS)) + { + usbInEpState = USB_IDLE; + return; + } + + if (USBD_HID_IsReportReady(&hUsbDeviceFS)) + { + uint8_t hidBuffer[USBHID_LEN]; + int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer)); + hidPacket_recv(hidBuffer, byteCount); + + size_t cmdSize; + const uint8_t* cmd = hidPacket_peekPacket(&cmdSize); + // This is called from an ISR, only process simple commands. + if (cmd && (cmdSize > 0)) + { + if (cmd[0] == S2S_CMD_DEBUG) + { + hidPacket_getPacket(&cmdSize); + debugCommand(); + } + else if (cmd[0] == S2S_CMD_PING) + { + hidPacket_getPacket(&cmdSize); + pingCommand(); + } + } + } + + switch (usbInEpState) + { + case USB_IDLE: + { + uint8_t hidBuffer[USBHID_LEN]; + const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer); + + if (nextChunk) + { + USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer)); + usbInEpState = USB_DATA_SENT; + } + } + break; + + case USB_DATA_SENT: + if (!USBD_HID_IsBusy(&hUsbDeviceFS)) + { + // Data accepted. + usbInEpState = USB_IDLE; + } + break; + } } diff --git a/src/firmware/hidpacket.c b/src/firmware/hidpacket.c index b35d5a8f..85c42220 100644 --- a/src/firmware/hidpacket.c +++ b/src/firmware/hidpacket.c @@ -111,6 +111,21 @@ hidPacket_getPacket(size_t* len) } } +const uint8_t* +hidPacket_peekPacket(size_t* len) +{ + if (rx.state == COMPLETE) + { + *len = rx.offset; + return rx.buffer; + } + else + { + *len = 0; + return NULL; + } +} + void hidPacket_send(const uint8_t* bytes, size_t len) { if (len <= sizeof(tx.buffer)) diff --git a/src/firmware/main.c b/src/firmware/main.c index eb776dab..2bb7d78f 100755 --- a/src/firmware/main.c +++ b/src/firmware/main.c @@ -117,6 +117,7 @@ void mainLoop() // run if the SD card is present at startup. // Don't use VBUS monitoring because that just tells us about // power, which could be from a charger +#if 0 if ((blockDev.state & DISK_PRESENT) && isUsbStarted && (scsiDev.cmdCount > 0) && // no need for speed without scsi @@ -129,6 +130,7 @@ void mainLoop() isUsbStarted = 0; } } +#endif else if (!(blockDev.state & DISK_PRESENT) && !isUsbStarted) { diff --git a/src/firmware/scsiPhy.c b/src/firmware/scsiPhy.c index ad6e2f79..fe92d247 100755 --- a/src/firmware/scsiPhy.c +++ b/src/firmware/scsiPhy.c @@ -476,7 +476,17 @@ void scsiEnterPhase(int phase) *SCSI_CTRL_TIMING = SCSI_SYNC_TIMING(scsiDev.target->syncPeriod); } - *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset; + // See note 26 in SCSI 2 standard: SCSI 1 implementations may assume + // "leading edge of the first REQ pulse beyond the REQ/ACK offset + // agreement would not occur until after the trailing edge of the + // last ACK pulse within the agreement." + // We simply subtract 1 from the offset to meet this requirement. + if (scsiDev.target->syncOffset >= 2) + { + *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset - 1; + } else { + *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset; + } } else { *SCSI_CTRL_SYNC_OFFSET = 0; @@ -548,70 +558,6 @@ void scsiPhyReset() } #endif - // FPGA comms test code - #ifdef FPGA_TEST - while(1) - { - for (int j = 0; j < SCSI_FIFO_DEPTH; ++j) - { - scsiDev.data[j] = j; - } - - if (!scsiPhyFifoEmpty()) - { - assertFail(); - } - - *SCSI_CTRL_PHASE = DATA_IN; - HAL_DMA_Start( - &memToFSMC, - (uint32_t) &scsiDev.data[0], - (uint32_t) SCSI_FIFO_DATA, - SCSI_FIFO_DEPTH / 4); - - HAL_DMA_PollForTransfer( - &memToFSMC, - HAL_DMA_FULL_TRANSFER, - 0xffffffff); - - if (!scsiPhyFifoFull()) - { - assertFail(); - } - - memset(&scsiDev.data[0], 0, SCSI_FIFO_DEPTH); - - *SCSI_CTRL_PHASE = DATA_OUT; - HAL_DMA_Start( - &fsmcToMem, - (uint32_t) SCSI_FIFO_DATA, - (uint32_t) &scsiDev.data[0], - SCSI_FIFO_DEPTH / 2); - - HAL_DMA_PollForTransfer( - &fsmcToMem, - HAL_DMA_FULL_TRANSFER, - 0xffffffff); - - if (!scsiPhyFifoEmpty()) - { - assertFail(); - } - - - for (int j = 0; j < SCSI_FIFO_DEPTH; ++j) - { - if (scsiDev.data[j] != (uint8_t) j) - { - assertFail(); - } - } - - s2s_fpgaReset(); - - } - #endif - #ifdef SCSI_FREQ_TEST while(1) { @@ -740,6 +686,7 @@ void scsiPhyConfig() // 8 = CD error // 16 = IO error // 32 = other error +// 64 = fpga comms error int scsiSelfTest() { if (scsiDev.phase != BUS_FREE) @@ -841,6 +788,69 @@ int scsiSelfTest() } */ + + // FPGA comms test code + for(i = 0; i < 10000; ++i) + { + for (int j = 0; j < SCSI_FIFO_DEPTH; ++j) + { + scsiDev.data[j] = j; + } + + if (!scsiPhyFifoEmpty()) + { + assertFail(); + } + + *SCSI_CTRL_PHASE = DATA_IN; + HAL_DMA_Start( + &memToFSMC, + (uint32_t) &scsiDev.data[0], + (uint32_t) SCSI_FIFO_DATA, + SCSI_FIFO_DEPTH / 4); + + HAL_DMA_PollForTransfer( + &memToFSMC, + HAL_DMA_FULL_TRANSFER, + 0xffffffff); + + if (!scsiPhyFifoFull()) + { + assertFail(); + } + + memset(&scsiDev.data[0], 0, SCSI_FIFO_DEPTH); + + *SCSI_CTRL_PHASE = DATA_OUT; + HAL_DMA_Start( + &fsmcToMem, + (uint32_t) SCSI_FIFO_DATA, + (uint32_t) &scsiDev.data[0], + SCSI_FIFO_DEPTH / 2); + + HAL_DMA_PollForTransfer( + &fsmcToMem, + HAL_DMA_FULL_TRANSFER, + 0xffffffff); + + if (!scsiPhyFifoEmpty()) + { + assertFail(); + } + + + for (int j = 0; j < SCSI_FIFO_DEPTH; ++j) + { + if (scsiDev.data[j] != (uint8_t) j) + { + result |= 64; + } + } + + s2s_fpgaReset(); + + } + *SCSI_CTRL_BSY = 0; return result; } diff --git a/src/firmware/spinlock.c b/src/firmware/spinlock.c new file mode 100755 index 00000000..a5d84145 --- /dev/null +++ b/src/firmware/spinlock.c @@ -0,0 +1,61 @@ +// Copyright (C) 2016 Michael McMaster +// +// This file is part of SCSI2SD. +// +// SCSI2SD is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// SCSI2SD is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SCSI2SD. If not, see . + +#include "spinlock.h" + +int s2s_spin_trylock(s2s_lock_t* lock) +{ + if (__LDREXW(lock) == 0) + { + // Try to set lock + int status = __STREXW(1, lock); + if (status == 0) + { + // got lock + // Do not start any other memory access + // until memory barrier is completed + __DMB(); + return 1; + } + } + + return 0; +} + +void s2s_spin_lock(s2s_lock_t* lock) +{ + int status = 0; + do + { + // Wait until lock is free + while (__LDREXW(lock) != 0); + + // Try to set lock + status = __STREXW(1, lock); + } while (status!=0); //retry until lock successfully + + // Do not start any other memory access + // until memory barrier is completed + __DMB(); +} + +void s2s_spin_unlock(s2s_lock_t* lock) +{ + // Ensure memory operations completed before releasing + __DMB(); + *lock = 0; +} diff --git a/src/firmware/spinlock.h b/src/firmware/spinlock.h new file mode 100755 index 00000000..11c4dc21 --- /dev/null +++ b/src/firmware/spinlock.h @@ -0,0 +1,38 @@ +// Copyright (C) 2016 Michael McMaster +// +// This file is part of SCSI2SD. +// +// SCSI2SD is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// SCSI2SD is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SCSI2SD. If not, see . +#ifndef S2S_SPINLOCK_H +#define S2S_SPINLOCK_H + +#include "stm32f2xx.h" + + +#define s2s_lock_t volatile uint32_t +#define s2s_lock_init 0 + +// Spinlock functions for Cortex-M3, based on ARM Application Note 321, +// ARM Cortex-M Programming Guide to Memory Barrier Instructions, 4.19 +// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHEJCHB.html +// +// s2s_spin_lock must NOT be used when mixing the main loop with a ISR, since +// the main code will never get a chance to unlock while the ISR is active. +// Use trylock in the ISR instead. + +int s2s_spin_trylock(s2s_lock_t* lock); +void s2s_spin_lock(s2s_lock_t* lock); +void s2s_spin_unlock(s2s_lock_t* lock); + +#endif