From 4eaf57cdc7d30a25e1679766fb42bfe646246c6e Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Thu, 22 Sep 2016 19:21:55 +1000 Subject: [PATCH] Fixed scsi timing error and added glitch filter. --- CHANGELOG | 4 +++ STM32CubeMX/SCSI2SD-V6/Src/main.c | 2 +- STM32CubeMX/SCSI2SD-V6/Src/sdio.c | 2 +- STM32CubeMX/SCSI2SD-V6/Src/spi.c | 3 +- include/scsi2sd.h | 5 ++-- rtl/fpga_bitmap.o | Bin 32724 -> 32724 bytes src/firmware/config.c | 2 +- src/firmware/fpga.c | 6 ++-- src/firmware/scsiPhy.c | 44 ++++++++++++++++++++++-------- src/firmware/scsiPhy.h | 5 ++-- src/scsi2sd-util6/BoardPanel.cc | 13 ++++++++- src/scsi2sd-util6/BoardPanel.hh | 2 ++ src/scsi2sd-util6/ConfigUtil.cc | 24 ++++++++++++++++ 13 files changed, 87 insertions(+), 25 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 18309e9a..a6cd8c64 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +20160922 6.0.?? + - Fixed SCSI timing issue + - Added glitch filter on SCSI signals. + 20160912 6.0.10 - Fixed write issue with UHS-I Speed Class 3 SD cards. - More stability bug fixes diff --git a/STM32CubeMX/SCSI2SD-V6/Src/main.c b/STM32CubeMX/SCSI2SD-V6/Src/main.c index 45f98d9c..5433bbf6 100755 --- a/STM32CubeMX/SCSI2SD-V6/Src/main.c +++ b/STM32CubeMX/SCSI2SD-V6/Src/main.c @@ -91,7 +91,7 @@ int main(void) MX_FSMC_Init(); MX_SDIO_SD_Init(); MX_SPI1_Init(); - MX_TIM4_Init(); + // TODO re-enable MX_TIM4_Init(); // TODO re-enable MX_USART3_UART_Init(); // TODO re-enable MX_USB_HOST_Init(); diff --git a/STM32CubeMX/SCSI2SD-V6/Src/sdio.c b/STM32CubeMX/SCSI2SD-V6/Src/sdio.c index 678a9e7a..0f9a34b1 100755 --- a/STM32CubeMX/SCSI2SD-V6/Src/sdio.c +++ b/STM32CubeMX/SCSI2SD-V6/Src/sdio.c @@ -88,7 +88,7 @@ void HAL_SD_MspInit(SD_HandleTypeDef* hsd) GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - // No pullup on CMD + // No pullup on CLK GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; diff --git a/STM32CubeMX/SCSI2SD-V6/Src/spi.c b/STM32CubeMX/SCSI2SD-V6/Src/spi.c index bef2045f..25e0745e 100755 --- a/STM32CubeMX/SCSI2SD-V6/Src/spi.c +++ b/STM32CubeMX/SCSI2SD-V6/Src/spi.c @@ -54,7 +54,8 @@ void MX_SPI1_Init(void) hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; hspi1.Init.CLKPhase = SPI_PHASE_2EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; - hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; + // (96MHz / 2) / 4 = 12MHz. FPGA device allows up to 25MHz write + hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLED; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; diff --git a/include/scsi2sd.h b/include/scsi2sd.h index a59fd38d..e15d0b09 100755 --- a/include/scsi2sd.h +++ b/include/scsi2sd.h @@ -53,7 +53,7 @@ typedef enum S2S_CFG_ENABLE_UNIT_ATTENTION = 1, S2S_CFG_ENABLE_PARITY = 2, S2S_CFG_ENABLE_SCSI2 = 4, - // OBSOLETE S2S_CFG_DISABLE_GLITCH = 8, + S2S_CFG_DISABLE_GLITCH = 8, S2S_CFG_ENABLE_CACHE = 16, S2S_CFG_ENABLE_DISCONNECT = 32, S2S_CFG_ENABLE_SEL_LATCH = 64, @@ -203,7 +203,8 @@ typedef enum typedef enum { S2S_CFG_STATUS_GOOD, - S2S_CFG_STATUS_ERR + S2S_CFG_STATUS_ERR, + S2S_CFG_STATUS_BUSY } S2S_CFG_STATUS; diff --git a/rtl/fpga_bitmap.o b/rtl/fpga_bitmap.o index 604983ff7574c9a95f94115572661f83330211f2..20717dbc1764963cae1f46b851dcfb1421ed6d8c 100644 GIT binary patch literal 32724 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 U*x>JDy7OxV-O0dZAj9wf00IIE^#A|> literal 32724 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 Jkq{zz{~!2!a+Cl7 diff --git a/src/firmware/config.c b/src/firmware/config.c index 6430d573..7ab2001b 100755 --- a/src/firmware/config.c +++ b/src/firmware/config.c @@ -37,7 +37,7 @@ #include -static const uint16_t FIRMWARE_VERSION = 0x060A; +static const uint16_t FIRMWARE_VERSION = 0x060B; // 1 flash row static const uint8_t DEFAULT_CONFIG[128] = diff --git a/src/firmware/fpga.c b/src/firmware/fpga.c index 441d7851..bc1782d6 100755 --- a/src/firmware/fpga.c +++ b/src/firmware/fpga.c @@ -39,10 +39,8 @@ void s2s_fpgaInit() HAL_GPIO_WritePin( nFGPA_CRESET_B_GPIO_Port, nFGPA_CRESET_B_Pin, GPIO_PIN_SET); - // 800uS for iCE40HX1K. 1200uS for HX4K according to Appendix A of - // TN1248 - iCE40 Programming and Configuration. Note that the - // earlier text of the document says 300uS. - s2s_delay_us(1200); // Be generous + // 800uS for iCE40HX1K. tCR_SCK parameter in datasheet. + s2s_delay_us(800); uint8_t* fpgaData = &_fpga_bitmap_start; uint32_t fpgaBytes = (uint32_t) &_fpga_bitmap_size; diff --git a/src/firmware/scsiPhy.c b/src/firmware/scsiPhy.c index 7b4e4633..ca3b494a 100755 --- a/src/firmware/scsiPhy.c +++ b/src/firmware/scsiPhy.c @@ -28,13 +28,18 @@ #include -// 5MB/s +// Slowest timing. Aim for 1.5MB/s, but it's likely to be faster. +// Assumes a 96MHz fpga clock. +#define SCSI_SCSI1_DESKEW 0x7 +#define SCSI_SCSI1_TIMING ((0x7 << 4) | 0xF) + +// 5MB/s sync and async. // Assumes a 96MHz fpga clock. // 2:0 Deskew count, 55ns // 6:4 Hold count, 53ns // 3:0 Assertion count, 80ns -#define SCSI_DEFAULT_DESKEW 0x6 -#define SCSI_DEFAULT_TIMING ((0x5 << 4) | 0x8) +#define SCSI_SCSI2_DESKEW 0x6 +#define SCSI_SCSI2_TIMING ((0x5 << 4) | 0x8) // 10MB/s // 2:0 Deskew count, 25ns @@ -441,23 +446,32 @@ void scsiEnterPhase(int phase) if (scsiDev.target->syncPeriod == 12) { // SCSI2 FAST-20 Timing. 20MB/s. - *SCSI_CTRL_TIMING = SCSI_FAST20_DESKEW; - *SCSI_CTRL_TIMING2 = SCSI_FAST20_TIMING; + *SCSI_CTRL_DESKEW = SCSI_FAST20_DESKEW; + *SCSI_CTRL_TIMING = SCSI_FAST20_TIMING; } else if (scsiDev.target->syncPeriod == 25) { // SCSI2 FAST Timing. 10MB/s. - *SCSI_CTRL_TIMING = SCSI_FAST10_DESKEW; - *SCSI_CTRL_TIMING2 = SCSI_FAST10_TIMING; + *SCSI_CTRL_DESKEW = SCSI_FAST10_DESKEW; + *SCSI_CTRL_TIMING = SCSI_FAST10_TIMING; } else { // 5MB/s Timing - *SCSI_CTRL_TIMING = SCSI_DEFAULT_DESKEW; - *SCSI_CTRL_TIMING2 = SCSI_DEFAULT_TIMING; + *SCSI_CTRL_DESKEW = SCSI_SCSI2_DESKEW; + *SCSI_CTRL_TIMING = SCSI_SCSI2_TIMING; } + *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset; } else { *SCSI_CTRL_SYNC_OFFSET = 0; - *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING; + + if (scsiDev.compatMode >= COMPAT_SCSI2) { + // 5MB/s Timing + *SCSI_CTRL_DESKEW = SCSI_SCSI2_DESKEW; + *SCSI_CTRL_TIMING = SCSI_SCSI2_TIMING; + } else { + *SCSI_CTRL_DESKEW = SCSI_SCSI1_DESKEW; + *SCSI_CTRL_TIMING = SCSI_SCSI1_TIMING; + } } *SCSI_CTRL_PHASE = newPhase; @@ -492,7 +506,8 @@ void scsiPhyReset() *SCSI_CTRL_DBX = 0; *SCSI_CTRL_SYNC_OFFSET = 0; - *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING; + *SCSI_CTRL_DESKEW = SCSI_SCSI1_DESKEW; + *SCSI_CTRL_TIMING = SCSI_SCSI1_TIMING; // DMA Benchmark code // Currently 11MB/s. @@ -658,7 +673,8 @@ void scsiPhyInit() *SCSI_CTRL_DBX = 0; *SCSI_CTRL_SYNC_OFFSET = 0; - *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING; + *SCSI_CTRL_DESKEW = SCSI_SCSI1_DESKEW; + *SCSI_CTRL_TIMING = SCSI_SCSI1_TIMING; } @@ -684,6 +700,10 @@ void scsiPhyConfig() } } *SCSI_CTRL_IDMASK = idMask; + + *SCSI_CTRL_FLAGS = + (scsiDev.boardCfg.flags & S2S_CFG_DISABLE_GLITCH) ? 1 : 0; + } diff --git a/src/firmware/scsiPhy.h b/src/firmware/scsiPhy.h index 718b25fb..7f52280c 100755 --- a/src/firmware/scsiPhy.h +++ b/src/firmware/scsiPhy.h @@ -26,8 +26,9 @@ #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_CTRL_DESKEW ((volatile uint8_t*)0x60000012) +#define SCSI_CTRL_TIMING ((volatile uint8_t*)0x60000014) +#define SCSI_CTRL_FLAGS ((volatile uint8_t*)0x60000016) #define SCSI_STS_FIFO ((volatile uint8_t*)0x60000020) #define SCSI_STS_ALTFIFO ((volatile uint8_t*)0x60000022) diff --git a/src/scsi2sd-util6/BoardPanel.cc b/src/scsi2sd-util6/BoardPanel.cc index 90fd6cd4..54ea2352 100644 --- a/src/scsi2sd-util6/BoardPanel.cc +++ b/src/scsi2sd-util6/BoardPanel.cc @@ -53,7 +53,7 @@ BoardPanel::BoardPanel(wxWindow* parent, const S2S_BoardCfg& initialConfig) : myParent(parent), myDelayValidator(new wxIntegerValidator) { - wxFlexGridSizer *fgs = new wxFlexGridSizer(10, 2, 9, 25); + wxFlexGridSizer *fgs = new wxFlexGridSizer(11, 2, 9, 25); fgs->Add(new wxStaticText(this, wxID_ANY, wxT(""))); myTermCtrl = @@ -118,6 +118,15 @@ BoardPanel::BoardPanel(wxWindow* parent, const S2S_BoardCfg& initialConfig) : myScsi2Ctrl->SetToolTip(_("Enable high-performance mode. May cause problems with SASI/SCSI1 hosts.")); fgs->Add(myScsi2Ctrl); + fgs->Add(new wxStaticText(this, wxID_ANY, wxT(""))); + myGlitchCtrl = + new wxCheckBox( + this, + ID_glitchCtrl, + _("Disable glitch filter")); + myGlitchCtrl->SetToolTip(_("Improve performance at the cost of noise immunity. Only use with short cables.")); + fgs->Add(myGlitchCtrl); + fgs->Add(new wxStaticText(this, wxID_ANY, wxT(""))); myCacheCtrl = new wxCheckBox( @@ -176,6 +185,7 @@ BoardPanel::getConfig() const (myParityCtrl->IsChecked() ? S2S_CFG_ENABLE_PARITY : 0) | (myUnitAttCtrl->IsChecked() ? S2S_CFG_ENABLE_UNIT_ATTENTION : 0) | (myScsi2Ctrl->IsChecked() ? S2S_CFG_ENABLE_SCSI2 : 0) | + (myGlitchCtrl->IsChecked() ? S2S_CFG_DISABLE_GLITCH : 0) | (myCacheCtrl->IsChecked() ? S2S_CFG_ENABLE_CACHE: 0) | (myDisconnectCtrl->IsChecked() ? S2S_CFG_ENABLE_DISCONNECT: 0) | (mySelLatchCtrl->IsChecked() ? S2S_CFG_ENABLE_SEL_LATCH : 0) | @@ -196,6 +206,7 @@ BoardPanel::setConfig(const S2S_BoardCfg& config) myParityCtrl->SetValue(config.flags & S2S_CFG_ENABLE_PARITY); myUnitAttCtrl->SetValue(config.flags & S2S_CFG_ENABLE_UNIT_ATTENTION); myScsi2Ctrl->SetValue(config.flags & S2S_CFG_ENABLE_SCSI2); + myGlitchCtrl->SetValue(config.flags & S2S_CFG_DISABLE_GLITCH); myTermCtrl->SetValue(config.flags6 & S2S_CFG_ENABLE_TERMINATOR); myCacheCtrl->SetValue(config.flags & S2S_CFG_ENABLE_CACHE); myDisconnectCtrl->SetValue(config.flags & S2S_CFG_ENABLE_DISCONNECT); diff --git a/src/scsi2sd-util6/BoardPanel.hh b/src/scsi2sd-util6/BoardPanel.hh index 06fadf31..8a8bc04f 100644 --- a/src/scsi2sd-util6/BoardPanel.hh +++ b/src/scsi2sd-util6/BoardPanel.hh @@ -55,6 +55,7 @@ private: ID_parityCtrl = wxID_HIGHEST + 1, ID_unitAttCtrl, ID_scsi2Ctrl, + ID_glitchCtrl, ID_termCtrl, ID_cacheCtrl, ID_disconnectCtrl, @@ -71,6 +72,7 @@ private: wxCheckBox* myParityCtrl; wxCheckBox* myUnitAttCtrl; wxCheckBox* myScsi2Ctrl; + wxCheckBox* myGlitchCtrl; wxCheckBox* myTermCtrl; wxCheckBox* myCacheCtrl; wxCheckBox* myDisconnectCtrl; diff --git a/src/scsi2sd-util6/ConfigUtil.cc b/src/scsi2sd-util6/ConfigUtil.cc index 1b68f5d2..9db2ded6 100755 --- a/src/scsi2sd-util6/ConfigUtil.cc +++ b/src/scsi2sd-util6/ConfigUtil.cc @@ -319,6 +319,18 @@ ConfigUtil::toXML(const S2S_BoardCfg& config) (config.flags & S2S_CFG_ENABLE_CACHE ? "true" : "false") << "\n" << + " \n" << + " " << + (config.flags & S2S_CFG_DISABLE_GLITCH ? "true" : "false") << + "\n" << + + " " << (config.flags & S2S_CFG_ENABLE_DISCONNECT ? "true" : "false") << "\n" << @@ -532,6 +544,18 @@ parseBoardConfig(wxXmlNode* node) result.flags = result.flags & ~S2S_CFG_ENABLE_SCSI2; } } + else if (child->GetName() == "disableGlitchFilter") + { + std::string s(child->GetNodeContent().mb_str()); + if (s == "true") + { + result.flags |= S2S_CFG_DISABLE_GLITCH; + } + else + { + result.flags = result.flags & ~S2S_CFG_DISABLE_GLITCH; + } + } else if (child->GetName() == "enableTerminator") { std::string s(child->GetNodeContent().mb_str()); -- 2.38.5