From fb9c26453038f15ec98eb0e151e23d2af38327b2 Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Sun, 11 Sep 2016 21:40:33 +1000 Subject: [PATCH] Fixed fsmc timing some more so it's stable - fsmc interface is now 16bits --- STM32CubeMX/SCSI2SD-V6/Src/fsmc.c | 47 +++++++++++++++++++++--------- rtl/fpga_bitmap.o | Bin 32724 -> 32724 bytes src/firmware/disk.c | 7 +++-- src/firmware/scsiPhy.c | 39 +++++++++++++++---------- src/firmware/scsiPhy.h | 46 +++++++++++++---------------- 5 files changed, 83 insertions(+), 56 deletions(-) diff --git a/STM32CubeMX/SCSI2SD-V6/Src/fsmc.c b/STM32CubeMX/SCSI2SD-V6/Src/fsmc.c index d01e9c33..8386762a 100755 --- a/STM32CubeMX/SCSI2SD-V6/Src/fsmc.c +++ b/STM32CubeMX/SCSI2SD-V6/Src/fsmc.c @@ -55,7 +55,7 @@ void MX_FSMC_Init(void) hsram1.Init.NSBank = FSMC_NORSRAM_BANK1; hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_ENABLE; hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_PSRAM; - hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_8; + hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE; @@ -67,18 +67,17 @@ void MX_FSMC_Init(void) hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; /* Timing */ - // 1 clock to read the address, but since the signals aren't stable - // at 96MHz we wait two more clocks - Timing.AddressSetupTime = 3; + // 1 clock to read the address, + 3 for the synchroniser + Timing.AddressSetupTime = 4; Timing.AddressHoldTime = 1; - Timing.DataSetupTime = 5; - // +1 clock hold time, +2 clock to let the bus settle (unstable at 96MHz) - // +1 clock to process read, 1 clock to output + // 3 for synchroniser, 1 to skip hold time, 1 to process read, 1 to output + Timing.DataSetupTime = 6; - // Allow a clock for us to release signals, or else we'll read - // our own output data as an address. - Timing.BusTurnAroundDuration = 1; + // Allow a clock for us to release signals, plus 3 for the synchroniser to + // realise the cycle has ended. Need to avoid both devices acting as outputs + // on the multiplexed lines at the same time. + Timing.BusTurnAroundDuration = 4; Timing.CLKDivision = 16; // Ignored for async Timing.DataLatency = 17; // Ignored for async @@ -108,6 +107,11 @@ static void HAL_FSMC_MspInit(void){ PE8 ------> FSMC_DA5 PE9 ------> FSMC_DA6 PE10 ------> FSMC_DA7 + PE11 ------> FSMC_DA8 + PE12 ------> FSMC_DA9 + PE13 ------> FSMC_DA10 + PE14 ------> FSMC_DA11 + PE15 ------> FSMC_DA12 PD14 ------> FSMC_DA0 PD15 ------> FSMC_DA1 PD0 ------> FSMC_DA2 @@ -115,10 +119,15 @@ static void HAL_FSMC_MspInit(void){ PD4 ------> FSMC_NOE PD5 ------> FSMC_NWE PD7 ------> FSMC_NE1 + PD8 ------> FSMC_DA13 + PD9 ------> FSMC_DA14 + PD10 ------> FSMC_DA15 PB7 ------> FSMC_NL + PE0 ------> FSMC_NBL0 + PE1 ------> FSMC_NBL1 */ /* GPIO_InitStruct */ - GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10; + GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; @@ -128,7 +137,7 @@ static void HAL_FSMC_MspInit(void){ /* GPIO_InitStruct */ GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1 - |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7; + |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; @@ -178,6 +187,11 @@ static void HAL_FSMC_MspDeInit(void){ PE8 ------> FSMC_DA5 PE9 ------> FSMC_DA6 PE10 ------> FSMC_DA7 + PE11 ------> FSMC_DA8 + PE12 ------> FSMC_DA9 + PE13 ------> FSMC_DA10 + PE14 ------> FSMC_DA11 + PE15 ------> FSMC_DA12 PD14 ------> FSMC_DA0 PD15 ------> FSMC_DA1 PD0 ------> FSMC_DA2 @@ -185,13 +199,18 @@ static void HAL_FSMC_MspDeInit(void){ PD4 ------> FSMC_NOE PD5 ------> FSMC_NWE PD7 ------> FSMC_NE1 + PD8 ------> FSMC_DA13 + PD9 ------> FSMC_DA14 + PD10 ------> FSMC_DA15 PB7 ------> FSMC_NL + PE0 ------> FSMC_NBL0 + PE1 ------> FSMC_NBL1 */ - HAL_GPIO_DeInit(GPIOE, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10); + HAL_GPIO_DeInit(GPIOE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15); HAL_GPIO_DeInit(GPIOD, GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1 - |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7); + |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10); HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7); diff --git a/rtl/fpga_bitmap.o b/rtl/fpga_bitmap.o index 5d95ad379864f3ded3819c81f19c54de08a936d5..604983ff7574c9a95f94115572661f83330211f2 100644 GIT binary patch literal 32724 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 Jkq{zz{~!2!a+Cl7 literal 32724 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 8; *SCSI_DATA_CNT_LO = count & 0xff; @@ -126,7 +126,7 @@ scsiReadByte(void) assertFail(); } #endif - startScsiRx(1); + scsiSetDataCount(1); trace(trace_spinPhyRxFifo); while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {} @@ -151,9 +151,10 @@ scsiReadByte(void) static void scsiReadPIO(uint8_t* data, uint32_t count) { - for (int i = 0; i < count; ++i) + uint16_t* fifoData = (uint16_t*)data; + for (int i = 0; i < (count + 1) / 2; ++i) { - data[i] = scsiPhyRx(); + fifoData[i] = scsiPhyRx(); // TODO ASSUMES LITTLE ENDIAN } // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read(); } @@ -168,7 +169,11 @@ scsiReadDMA(uint8_t* data, uint32_t count) scsiTxDMAComplete = 1; // TODO not used much scsiRxDMAComplete = 0; // TODO not used much - HAL_DMA_Start(&fsmcToMem, (uint32_t) SCSI_FIFO_DATA, (uint32_t) data, count); + HAL_DMA_Start( + &fsmcToMem, + (uint32_t) SCSI_FIFO_DATA, + (uint32_t) data, + (count + 1) / 2); } int @@ -209,7 +214,7 @@ scsiRead(uint8_t* data, uint32_t count) chunk = chunk & 0xFFFFFFF8; } #endif - startScsiRx(chunk); + scsiSetDataCount(chunk); while (i < count && likely(!scsiDev.resetFlag)) { @@ -226,7 +231,7 @@ scsiRead(uint8_t* data, uint32_t count) #endif if (nextChunk > 0) { - startScsiRx(nextChunk); + scsiSetDataCount(nextChunk); } #ifdef SCSI_FSMC_DMA @@ -278,6 +283,8 @@ scsiWriteByte(uint8_t value) scsiPhyTx(value); scsiPhyFifoFlip(); + scsiSetDataCount(1); + trace(trace_spinTxComplete); while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {} @@ -292,9 +299,10 @@ scsiWriteByte(uint8_t value) static void scsiWritePIO(const uint8_t* data, uint32_t count) { - for (int i = 0; i < count; ++i) + uint16_t* fifoData = (uint16_t*)data; + for (int i = 0; i < (count + 1) / 2; ++i) { - scsiPhyTx(data[i]); + scsiPhyTx(fifoData[i]); } } @@ -383,6 +391,7 @@ scsiWrite(const uint8_t* data, uint32_t count) #endif scsiPhyFifoFlip(); + scsiSetDataCount(chunk); i += chunk; } while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) @@ -486,7 +495,7 @@ void scsiPhyReset() *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING; // DMA Benchmark code - // Currently 6.6MB/s. Assume 13MB/s is achievable with 16 bits + // Currently 11MB/s. #ifdef DMA_BENCHMARK while(1) { @@ -551,7 +560,7 @@ void scsiPhyReset() &fsmcToMem, (uint32_t) SCSI_FIFO_DATA, (uint32_t) &scsiDev.data[0], - SCSI_FIFO_DEPTH); + SCSI_FIFO_DEPTH / 2); HAL_DMA_PollForTransfer( &fsmcToMem, @@ -598,11 +607,11 @@ static void scsiPhyInitDMA() memToFSMC.Init.PeriphInc = DMA_PINC_ENABLE; memToFSMC.Init.MemInc = DMA_MINC_DISABLE; memToFSMC.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; - memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; memToFSMC.Init.Mode = DMA_NORMAL; memToFSMC.Init.Priority = DMA_PRIORITY_LOW; // FIFO mode is needed to allow conversion from 32bit words to the - // 8bit FSMC interface. + // 16bit FSMC interface. memToFSMC.Init.FIFOMode = DMA_FIFOMODE_ENABLE; // We only use 1 word (4 bytes) in the fifo at a time. Normally it's @@ -622,7 +631,7 @@ static void scsiPhyInitDMA() fsmcToMem.Init.Direction = DMA_MEMORY_TO_MEMORY; fsmcToMem.Init.PeriphInc = DMA_PINC_DISABLE; fsmcToMem.Init.MemInc = DMA_MINC_ENABLE; - fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; fsmcToMem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; fsmcToMem.Init.Mode = DMA_NORMAL; fsmcToMem.Init.Priority = DMA_PRIORITY_LOW; diff --git a/src/firmware/scsiPhy.h b/src/firmware/scsiPhy.h index fa7e1684..718b25fb 100755 --- a/src/firmware/scsiPhy.h +++ b/src/firmware/scsiPhy.h @@ -18,25 +18,25 @@ #define SCSIPHY_H #define SCSI_CTRL_IDMASK ((volatile uint8_t*)0x60000000) -#define SCSI_CTRL_PHASE ((volatile uint8_t*)0x60000001) -#define SCSI_CTRL_BSY ((volatile uint8_t*)0x60000002) -#define SCSI_FIFO_SEL ((volatile uint8_t*)0x60000003) -#define SCSI_DATA_CNT_HI ((volatile uint8_t*)0x60000004) -#define SCSI_DATA_CNT_LO ((volatile uint8_t*)0x60000005) -#define SCSI_DATA_CNT_SET ((volatile uint8_t*)0x60000006) -#define SCSI_CTRL_DBX ((volatile uint8_t*)0x60000007) -#define SCSI_CTRL_SYNC_OFFSET ((volatile uint8_t*)0x60000008) -#define SCSI_CTRL_TIMING ((volatile uint8_t*)0x60000009) -#define SCSI_CTRL_TIMING2 ((volatile uint8_t*)0x6000000A) - -#define SCSI_STS_FIFO ((volatile uint8_t*)0x60000010) -#define SCSI_STS_ALTFIFO ((volatile uint8_t*)0x60000011) -#define SCSI_STS_FIFO_COMPLETE ((volatile uint8_t*)0x60000012) -#define SCSI_STS_SELECTED ((volatile uint8_t*)0x60000013) -#define SCSI_STS_SCSI ((volatile uint8_t*)0x60000014) -#define SCSI_STS_DBX ((volatile uint8_t*)0x60000015) - -#define SCSI_FIFO_DATA ((volatile uint8_t*)0x60000020) +#define SCSI_CTRL_PHASE ((volatile uint8_t*)0x60000002) +#define SCSI_CTRL_BSY ((volatile uint8_t*)0x60000004) +#define SCSI_FIFO_SEL ((volatile uint8_t*)0x60000006) +#define SCSI_DATA_CNT_HI ((volatile uint8_t*)0x60000008) +#define SCSI_DATA_CNT_LO ((volatile uint8_t*)0x6000000A) +#define SCSI_DATA_CNT_SET ((volatile uint8_t*)0x6000000C) +#define SCSI_CTRL_DBX ((volatile uint8_t*)0x6000000E) +#define SCSI_CTRL_SYNC_OFFSET ((volatile uint8_t*)0x60000010) +#define SCSI_CTRL_TIMING ((volatile uint8_t*)0x60000012) +#define SCSI_CTRL_TIMING2 ((volatile uint8_t*)0x60000014) + +#define SCSI_STS_FIFO ((volatile uint8_t*)0x60000020) +#define SCSI_STS_ALTFIFO ((volatile uint8_t*)0x60000022) +#define SCSI_STS_FIFO_COMPLETE ((volatile uint8_t*)0x60000024) +#define SCSI_STS_SELECTED ((volatile uint8_t*)0x60000026) +#define SCSI_STS_SCSI ((volatile uint8_t*)0x60000028) +#define SCSI_STS_DBX ((volatile uint8_t*)0x6000002A) + +#define SCSI_FIFO_DATA ((volatile uint16_t*)0x60000040) #define SCSI_FIFO_DEPTH 512 @@ -74,6 +74,8 @@ void scsiPhyReset(void); void scsiEnterPhase(int phase); void scsiEnterBusFree(void); +void scsiSetDataCount(uint32_t count); + void scsiWrite(const uint8_t* data, uint32_t count); void scsiRead(uint8_t* data, uint32_t count); void scsiWriteByte(uint8_t value); @@ -82,12 +84,6 @@ uint8_t scsiReadByte(void); void sdTmpRead(uint8_t* data, uint32_t lba, int sectors); void sdTmpWrite(uint8_t* data, uint32_t lba, int sectors); -#if 0 - -// Contains the odd-parity flag for a given 8-bit value. -extern const uint8_t Lookup_OddParity[256]; - -#endif extern volatile uint8_t scsiRxDMAComplete; extern volatile uint8_t scsiTxDMAComplete; -- 2.38.5