From d3d854c7c5e1089a42500f0cbc04b1bbe20fa5c5 Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Sat, 5 Nov 2016 16:19:35 +1000 Subject: [PATCH] Fix floating pins, SD high speed mode, and SCSI performance improvements --- CHANGELOG | 5 + Makefile | 7 +- .../Src/stm32f2xx_hal_sd.c | 10 +- STM32CubeMX/SCSI2SD-V6/Inc/tim.h | 73 ------ STM32CubeMX/SCSI2SD-V6/SCSI2SD-V6.ioc | 35 +-- STM32CubeMX/SCSI2SD-V6/Src/gpio.c | 34 +-- STM32CubeMX/SCSI2SD-V6/Src/main.c | 14 +- STM32CubeMX/SCSI2SD-V6/Src/tim.c | 133 ----------- STM32CubeMX/SCSI2SD-V6/Src/usbd_conf.c | 13 +- rtl/fpga_bitmap.o | Bin 32724 -> 32724 bytes src/firmware/bsp.h | 2 + src/firmware/config.c | 12 +- src/firmware/disk.c | 27 ++- src/firmware/main.c | 38 +++- src/firmware/scsi.c | 30 ++- src/firmware/scsi.h | 4 + src/firmware/scsiPhy.c | 83 ++++--- src/firmware/scsiPhy.h | 6 + src/firmware/sd.c | 214 +----------------- src/scsi2sd-util6/scsi2sd-util.cc | 2 +- .../src/stc/scintilla/src/Editor.cxx | 5 +- 21 files changed, 232 insertions(+), 515 deletions(-) delete mode 100755 STM32CubeMX/SCSI2SD-V6/Inc/tim.h delete mode 100755 STM32CubeMX/SCSI2SD-V6/Src/tim.c diff --git a/CHANGELOG b/CHANGELOG index e3674276..c0579e09 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +2016100X ? + - Enable synchronous transfers on SCSI1 hosts + - Support 4MB/s sync transfers for Amiga A590 (WD33C93) + - Faster SD performance, but cannot use USB + SD at the same time. + 20161006 6.0.13 - Fixed SCSI timing issue - Added glitch filter on SCSI signals. diff --git a/Makefile b/Makefile index 350c8584..b3fa3f64 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,6 @@ build/stm32cubemx/gpio.o: STM32CubeMX/SCSI2SD-V6/Src/gpio.c build/stm32cubemx/main.o: STM32CubeMX/SCSI2SD-V6/Src/main.c build/stm32cubemx/sdio.o: STM32CubeMX/SCSI2SD-V6/Src/sdio.c build/stm32cubemx/spi.o: STM32CubeMX/SCSI2SD-V6/Src/spi.c -build/stm32cubemx/tim.o: STM32CubeMX/SCSI2SD-V6/Src/tim.c build/stm32cubemx/stm32f2xx_hal_msp.o: STM32CubeMX/SCSI2SD-V6/Src/stm32f2xx_hal_msp.c build/stm32cubemx/stm32f2xx_it.o: STM32CubeMX/SCSI2SD-V6/Src/stm32f2xx_it.c build/stm32cubemx/usart.o: STM32CubeMX/SCSI2SD-V6/Src/usart.c @@ -52,8 +51,6 @@ 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 @@ -78,7 +75,6 @@ STM32OBJS = \ build/stm32cubemx/main.o \ build/stm32cubemx/sdio.o \ build/stm32cubemx/spi.o \ - build/stm32cubemx/tim.o \ build/stm32cubemx/stm32f2xx_hal_msp.o \ build/stm32cubemx/stm32f2xx_it.o \ build/stm32cubemx/usart.o \ @@ -96,8 +92,6 @@ 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 \ @@ -130,6 +124,7 @@ USBCOMPOSITE_SRC= \ SRC = \ src/firmware/bootloader.c \ + src/firmware/bsp.c \ src/firmware/cdrom.c \ src/firmware/config.c \ src/firmware/disk.c \ diff --git a/STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_sd.c b/STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_sd.c index 9d2062dc..7312d0e3 100755 --- a/STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_sd.c +++ b/STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_sd.c @@ -1953,10 +1953,12 @@ HAL_SD_ErrorTypedef HAL_SD_HighSpeed (SD_HandleTypeDef *hsd) __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); /* Test if the switch mode HS is ok */ - if ((SD_hs[13]& 2) != 2) - { - errorstate = SD_UNSUPPORTED_FEATURE; - } + // MM: These bits (0 to 271) are reserved in the spec I'm looking at ??? + // Should be safe to ignore the result. + //if ((SD_hs[13]& 2) != 2) + //{ + //errorstate = SD_UNSUPPORTED_FEATURE; + //} } return errorstate; diff --git a/STM32CubeMX/SCSI2SD-V6/Inc/tim.h b/STM32CubeMX/SCSI2SD-V6/Inc/tim.h deleted file mode 100755 index 99e8b860..00000000 --- a/STM32CubeMX/SCSI2SD-V6/Inc/tim.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - ****************************************************************************** - * File Name : TIM.h - * Description : This file provides code for the configuration - * of the TIM instances. - ****************************************************************************** - * - * COPYRIGHT(c) 2016 STMicroelectronics - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __tim_H -#define __tim_H -#ifdef __cplusplus - extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f2xx_hal.h" - -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -extern TIM_HandleTypeDef htim4; - -/* USER CODE BEGIN Private defines */ - -/* USER CODE END Private defines */ - -void MX_TIM4_Init(void); - -/* USER CODE BEGIN Prototypes */ - -/* USER CODE END Prototypes */ - -#ifdef __cplusplus -} -#endif -#endif /*__ tim_H */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/STM32CubeMX/SCSI2SD-V6/SCSI2SD-V6.ioc b/STM32CubeMX/SCSI2SD-V6/SCSI2SD-V6.ioc index 056fddb8..b490328d 100755 --- a/STM32CubeMX/SCSI2SD-V6/SCSI2SD-V6.ioc +++ b/STM32CubeMX/SCSI2SD-V6/SCSI2SD-V6.ioc @@ -455,36 +455,39 @@ ProjectManager.ProjectName=SCSI2SD-V6 ProjectManager.TargetToolchain=TrueSTUDIO ProjectManager.ToolChainLocation= RCC.48MHZClocksFreq_Value=48000000 -RCC.AHBFreq_Value=96000000 +RCC.AHBFreq_Value=108000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 -RCC.APB1Freq_Value=24000000 -RCC.APB1TimFreq_Value=48000000 +RCC.APB1Freq_Value=27000000 +RCC.APB1TimFreq_Value=54000000 RCC.APB2CLKDivider=RCC_HCLK_DIV2 -RCC.APB2Freq_Value=48000000 -RCC.APB2TimFreq_Value=96000000 -RCC.CortexFreq_Value=96000000 -RCC.EthernetFreq_Value=96000000 -RCC.FCLKCortexFreq_Value=96000000 +RCC.APB2Freq_Value=54000000 +RCC.APB2TimFreq_Value=108000000 +RCC.CortexFreq_Value=108000000 +RCC.EthernetFreq_Value=108000000 +RCC.FCLKCortexFreq_Value=108000000 RCC.FamilyName=M -RCC.HCLKFreq_Value=96000000 +RCC.HCLKFreq_Value=108000000 RCC.HSE_VALUE=20000000 RCC.HSI_VALUE=16000000 RCC.I2SClocksFreq_Value=96000000 -RCC.IPParameters=FamilyName,LSE_VALUE,HSI_VALUE,SYSCLKFreq_VALUE,AHBFreq_Value,CortexFreq_Value,APB1Freq_Value,APB2Freq_Value,HSE_VALUE,RTCHSEDivFreq_Value,LSI_VALUE,RTCFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,PLLCLKFreq_Value,48MHZClocksFreq_Value,VCOI2SOutputFreq_Value,VcooutputI2S,I2SClocksFreq_Value,RCC_MCO1Source,HCLKFreq_Value,FCLKCortexFreq_Value,APB1TimFreq_Value,APB2TimFreq_Value,EthernetFreq_Value,MCO2PinFreq_Value,APB1CLKDivider,APB2CLKDivider,MCO1PinFreq_Value,SYSCLKSource,PLLM +RCC.IPParameters=FamilyName,LSE_VALUE,HSI_VALUE,SYSCLKFreq_VALUE,AHBFreq_Value,CortexFreq_Value,APB1Freq_Value,APB2Freq_Value,HSE_VALUE,RTCHSEDivFreq_Value,LSI_VALUE,RTCFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,PLLCLKFreq_Value,48MHZClocksFreq_Value,VCOI2SOutputFreq_Value,VcooutputI2S,I2SClocksFreq_Value,RCC_MCO1Source,HCLKFreq_Value,FCLKCortexFreq_Value,APB1TimFreq_Value,APB2TimFreq_Value,EthernetFreq_Value,MCO2PinFreq_Value,APB1CLKDivider,APB2CLKDivider,MCO1PinFreq_Value,SYSCLKSource,PLLM,PLLN,PLLQ,PLLP RCC.LSE_VALUE=32768 RCC.LSI_VALUE=32000 -RCC.MCO1PinFreq_Value=96000000 -RCC.MCO2PinFreq_Value=96000000 -RCC.PLLCLKFreq_Value=96000000 +RCC.MCO1PinFreq_Value=108000000 +RCC.MCO2PinFreq_Value=108000000 +RCC.PLLCLKFreq_Value=108000000 RCC.PLLM=20 +RCC.PLLN=432 +RCC.PLLP=RCC_PLLP_DIV4 +RCC.PLLQ=9 RCC.RCC_MCO1Source=RCC_MCO1SOURCE_PLLCLK RCC.RTCFreq_Value=32000 RCC.RTCHSEDivFreq_Value=10000000 -RCC.SYSCLKFreq_VALUE=96000000 +RCC.SYSCLKFreq_VALUE=108000000 RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK RCC.VCOI2SOutputFreq_Value=192000000 RCC.VCOInputFreq_Value=1000000 -RCC.VCOOutputFreq_Value=192000000 +RCC.VCOOutputFreq_Value=432000000 RCC.VcooutputI2S=96000000 SDIO.BusWide=SDIO_BUS_WIDE_1B SDIO.IPParameters=BusWide,WideMode @@ -498,7 +501,7 @@ SH.S_TIM4_CH1.ConfNb=1 SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 SPI1.CLKPhase=SPI_PHASE_2EDGE SPI1.CLKPolarity=SPI_POLARITY_HIGH -SPI1.CalculateBaudRate=3.0 MBits/s +SPI1.CalculateBaudRate=3.375 MBits/s SPI1.IPParameters=Mode,CalculateBaudRate,BaudRatePrescaler,CLKPolarity,CLKPhase SPI1.Mode=SPI_MODE_MASTER USB_DEVICE.CLASS_NAME-HID_FS=HID diff --git a/STM32CubeMX/SCSI2SD-V6/Src/gpio.c b/STM32CubeMX/SCSI2SD-V6/Src/gpio.c index 484ea187..ba18a6d7 100755 --- a/STM32CubeMX/SCSI2SD-V6/Src/gpio.c +++ b/STM32CubeMX/SCSI2SD-V6/Src/gpio.c @@ -98,8 +98,9 @@ void MX_GPIO_Init(void) /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = nSPICFG_CS_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(nSPICFG_CS_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : PtPin */ @@ -119,27 +120,21 @@ void MX_GPIO_Init(void) /*Configure GPIO pins : PBPin PBPin PBPin */ GPIO_InitStruct.Pin = BOOT1_Pin|UNUSED_PB5_Pin|UNUSED_PB6_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - /*Configure GPIO pins : PE11 PE12 PE13 PE14 - PE15 PE0 PE1 */ - GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 - |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); - /*Configure GPIO pins : PBPin PBPin */ GPIO_InitStruct.Pin = UNUSED_PB12_Pin|UNUSED_PB13_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - /*Configure GPIO pins : PD8 PD9 PD10 PD6 */ - GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_6; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; + /*Configure GPIO pins : PD6, PD12 */ + // PD6: FSMC NWAIT, not used yet.PULLED UP in fpga pin config + // PD12: FPGA_GPIO1, not used. + GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PDPin PDPin */ @@ -170,11 +165,18 @@ void MX_GPIO_Init(void) HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pin : PA10 */ + // USB Host OTG ID pin GPIO_InitStruct.Pin = GPIO_PIN_10; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + // USB Host pins, currently unused. + GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + /*Configure GPIO pins : PBPin PBPin */ GPIO_InitStruct.Pin = nSD_WP_Pin|nSD_CD_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; diff --git a/STM32CubeMX/SCSI2SD-V6/Src/main.c b/STM32CubeMX/SCSI2SD-V6/Src/main.c index 5433bbf6..a80e0781 100755 --- a/STM32CubeMX/SCSI2SD-V6/Src/main.c +++ b/STM32CubeMX/SCSI2SD-V6/Src/main.c @@ -34,7 +34,6 @@ #include "stm32f2xx_hal.h" #include "sdio.h" #include "spi.h" -#include "tim.h" #include "usart.h" #include "usb_device.h" #include "usb_host.h" @@ -91,9 +90,8 @@ int main(void) MX_FSMC_Init(); MX_SDIO_SD_Init(); MX_SPI1_Init(); - // TODO re-enable MX_TIM4_Init(); - // TODO re-enable MX_USART3_UART_Init(); - // TODO re-enable MX_USB_HOST_Init(); + MX_USART3_UART_Init(); // Not used, but we don't want the pins floating. + // MX_USB_HOST_Init(); // Not used, pins set to GPIO /* USER CODE BEGIN 2 */ mainInit(); @@ -105,7 +103,7 @@ int main(void) while (1) { /* USER CODE END WHILE */ - // TODO re-enable MX_USB_HOST_Process(); + //MX_USB_HOST_Process(); /* USER CODE BEGIN 3 */ mainLoop(); @@ -130,9 +128,9 @@ void SystemClock_Config(void) RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 20; - RCC_OscInitStruct.PLL.PLLN = 192; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; - RCC_OscInitStruct.PLL.PLLQ = 4; + RCC_OscInitStruct.PLL.PLLN = 432; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; + RCC_OscInitStruct.PLL.PLLQ = 9; HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1 diff --git a/STM32CubeMX/SCSI2SD-V6/Src/tim.c b/STM32CubeMX/SCSI2SD-V6/Src/tim.c deleted file mode 100755 index 22011040..00000000 --- a/STM32CubeMX/SCSI2SD-V6/Src/tim.c +++ /dev/null @@ -1,133 +0,0 @@ -/** - ****************************************************************************** - * File Name : TIM.c - * Description : This file provides code for the configuration - * of the TIM instances. - ****************************************************************************** - * - * COPYRIGHT(c) 2016 STMicroelectronics - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "tim.h" - -#include "gpio.h" - -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -TIM_HandleTypeDef htim4; - -/* TIM4 init function */ -void MX_TIM4_Init(void) -{ - TIM_SlaveConfigTypeDef sSlaveConfig; - TIM_MasterConfigTypeDef sMasterConfig; - - htim4.Instance = TIM4; - htim4.Init.Prescaler = 0; - htim4.Init.CounterMode = TIM_COUNTERMODE_UP; - htim4.Init.Period = 0; - htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - HAL_TIM_Base_Init(&htim4); - - sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; - sSlaveConfig.InputTrigger = TIM_TS_TI1FP1; - sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; - sSlaveConfig.TriggerFilter = 0; - HAL_TIM_SlaveConfigSynchronization(&htim4, &sSlaveConfig); - - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig); - -} - -void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) -{ - - GPIO_InitTypeDef GPIO_InitStruct; - if(htim_base->Instance==TIM4) - { - /* USER CODE BEGIN TIM4_MspInit 0 */ - - /* USER CODE END TIM4_MspInit 0 */ - /* Peripheral clock enable */ - __TIM4_CLK_ENABLE(); - - /**TIM4 GPIO Configuration - PD12 ------> TIM4_CH1 - */ - GPIO_InitStruct.Pin = GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_LOW; - GPIO_InitStruct.Alternate = GPIO_AF2_TIM4; - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); - - /* USER CODE BEGIN TIM4_MspInit 1 */ - - /* USER CODE END TIM4_MspInit 1 */ - } -} - -void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base) -{ - - if(htim_base->Instance==TIM4) - { - /* USER CODE BEGIN TIM4_MspDeInit 0 */ - - /* USER CODE END TIM4_MspDeInit 0 */ - /* Peripheral clock disable */ - __TIM4_CLK_DISABLE(); - - /**TIM4 GPIO Configuration - PD12 ------> TIM4_CH1 - */ - HAL_GPIO_DeInit(GPIOD, GPIO_PIN_12); - - } - /* USER CODE BEGIN TIM4_MspDeInit 1 */ - - /* USER CODE END TIM4_MspDeInit 1 */ -} - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/STM32CubeMX/SCSI2SD-V6/Src/usbd_conf.c b/STM32CubeMX/SCSI2SD-V6/Src/usbd_conf.c index 2e7ed76e..07387caa 100755 --- a/STM32CubeMX/SCSI2SD-V6/Src/usbd_conf.c +++ b/STM32CubeMX/SCSI2SD-V6/Src/usbd_conf.c @@ -108,7 +108,18 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd) PA11 ------> USB_OTG_FS_DM PA12 ------> USB_OTG_FS_DP */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_11|GPIO_PIN_12); + // HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_11|GPIO_PIN_12); + // MM: Don't let pins float. + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Peripheral interrupt Deinit*/ HAL_NVIC_DisableIRQ(OTG_FS_IRQn); diff --git a/rtl/fpga_bitmap.o b/rtl/fpga_bitmap.o index d9597043aa589c569dc46a9d7f23809272dd6126..77e590a862a093f08770d5c62bcc2ed6da5057d2 100644 GIT binary patch literal 32724 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 literal 32724 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 diff --git a/src/firmware/bsp.h b/src/firmware/bsp.h index fd1a7108..353c9ea4 100644 --- a/src/firmware/bsp.h +++ b/src/firmware/bsp.h @@ -22,6 +22,8 @@ // The maximum burst is 16 bytes. #define S2S_DMA_ALIGN __attribute__((aligned(1024))) +void s2s_setNormalClock(); +void s2s_setFastClock(); #endif diff --git a/src/firmware/config.c b/src/firmware/config.c index e8237670..127ca1b5 100755 --- a/src/firmware/config.c +++ b/src/firmware/config.c @@ -37,7 +37,7 @@ #include -static const uint16_t FIRMWARE_VERSION = 0x060D; +static const uint16_t FIRMWARE_VERSION = 0x060E; // 1 flash row static const uint8_t DEFAULT_CONFIG[128] = @@ -170,10 +170,10 @@ debugCommand() response[14] = scsiDev.lastStatus; response[15] = scsiDev.lastSense; response[16] = scsiDev.phase; - response[17] = scsiStatusBSY(); - response[18] = scsiStatusSEL(); - response[19] = scsiStatusATN(); - response[20] = scsiStatusRST(); + response[17] = *SCSI_STS_SCSI; + response[18] = scsiDev.target != NULL ? scsiDev.target->syncOffset : 0; + response[19] = scsiDev.target != NULL ? scsiDev.target->syncPeriod : 0; + response[20] = scsiDev.minSyncPeriod; response[21] = scsiDev.rstCount; response[22] = scsiDev.selCount; response[23] = scsiDev.msgCount; @@ -184,7 +184,7 @@ debugCommand() response[28] = scsiDev.lastSenseASC; response[29] = *SCSI_STS_DBX; response[30] = LastTrace; - response[31] = scsiStatusACK(); + response[31] = 0; // Unused hidPacket_send(response, sizeof(response)); } diff --git a/src/firmware/disk.c b/src/firmware/disk.c index b3e612fe..d234854e 100755 --- a/src/firmware/disk.c +++ b/src/firmware/disk.c @@ -558,8 +558,11 @@ void scsiDiskPoll() { prep += completedDmaSectors; sdActive -= completedDmaSectors; - } else if (sdActive > 1) { - if (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33) { + } else if (sdActive > 1) + { + if ((scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 510] != 0xAA) || + (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33)) + { prep += 1; sdActive -= 1; } @@ -584,6 +587,7 @@ void scsiDiskPoll() for (int dodgy = 0; dodgy < sectors; dodgy++) { + scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 510] = 0xAA; scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 511] = 0x33; } @@ -621,12 +625,26 @@ void scsiDiskPoll() } uint16_t* scsiDmaData = (uint16_t*) &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]); - for (int k = 0; k < (dmaBytes + 1) / 2; ++k) + // Manually unrolled loop for performance. + // -Os won't unroll this for us automatically, + // especially since scsiPhyTx does volatile stuff. + // Reduces bus utilisation by making the fsmc split + // 32bits into 2 16 bit writes. + int k = 0; + for (; k + 4 < (dmaBytes + 1) / 2; k += 4) + { + scsiPhyTx32(scsiDmaData[k], scsiDmaData[k+1]); + scsiPhyTx32(scsiDmaData[k+2], scsiDmaData[k+3]); + } + for (; k < (dmaBytes + 1) / 2; ++k) { scsiPhyTx(scsiDmaData[k]); } i++; - while (!scsiPhyComplete() && !scsiDev.resetFlag) {} + while (!scsiPhyComplete() && !scsiDev.resetFlag) + { + __WFE(); // Wait for event + } scsiPhyFifoFlip(); scsiSetDataCount(dmaBytes); } @@ -639,6 +657,7 @@ void scsiDiskPoll() likely(scsiDev.phase == DATA_IN) && likely(!scsiDev.resetFlag)) { + __WFE(); // Wait for event } diff --git a/src/firmware/main.c b/src/firmware/main.c index 67f79565..eb776dab 100755 --- a/src/firmware/main.c +++ b/src/firmware/main.c @@ -18,6 +18,7 @@ #include "stm32f2xx.h" #include "config.h" +#include "bsp.h" #include "disk.h" #include "fpga.h" #include "led.h" @@ -26,6 +27,7 @@ #include "scsiPhy.h" #include "time.h" #include "trace.h" +#include "sdio.h" #include "usb_device/usb_device.h" #include "usb_device/usbd_composite.h" #include "usb_device/usbd_msc_storage_sd.h" @@ -34,6 +36,8 @@ const char* Notice = "Copyright (C) 2016 Michael McMaster "; uint32_t lastSDPoll; +static int isUsbStarted; + void mainEarlyInit() { // USB device is initialised before mainInit is called @@ -56,6 +60,7 @@ void mainInit() scsiInit(); MX_USB_DEVICE_Init(); // USB lun config now available. + isUsbStarted = 1; // Optional bootup delay int delaySeconds = 0; @@ -98,10 +103,39 @@ void mainLoop() scsiPhyConfig(); scsiInit(); + // Is a USB host connected ? + if (isUsbStarted) + { + USBD_Stop(&hUsbDeviceFS); + s2s_delay_ms(128); + USBD_Start(&hUsbDeviceFS); + } + } + + // Can we speed up the SD card ? + // Don't combine with the above block because that won't + // 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 ((blockDev.state & DISK_PRESENT) && + isUsbStarted && + (scsiDev.cmdCount > 0) && // no need for speed without scsi + !USBD_Composite_IsConfigured(&hUsbDeviceFS)) + { + if (HAL_SD_HighSpeed(&hsd) == SD_OK) + { + USBD_Stop(&hUsbDeviceFS); + s2s_setFastClock(); + isUsbStarted = 0; + } + } - USBD_Stop(&hUsbDeviceFS); - s2s_delay_ms(128); + else if (!(blockDev.state & DISK_PRESENT) && !isUsbStarted) + { + // Good time to restart USB. + s2s_setNormalClock(); USBD_Start(&hUsbDeviceFS); + isUsbStarted = 1; } } else diff --git a/src/firmware/scsi.c b/src/firmware/scsi.c index 914c0774..bf20f9df 100755 --- a/src/firmware/scsi.c +++ b/src/firmware/scsi.c @@ -73,6 +73,7 @@ static void enter_BusFree() s2s_ledOff(); scsiDev.phase = BUS_FREE; + scsiDev.selFlag = 0; } static void enter_MessageIn(uint8_t message) @@ -467,6 +468,7 @@ static void scsiReset() scsiDev.phase = BUS_FREE; scsiDev.atnFlag = 0; scsiDev.resetFlag = 0; + scsiDev.selFlag = 0; scsiDev.lun = -1; scsiDev.compatMode = COMPAT_UNKNOWN; @@ -488,6 +490,7 @@ static void scsiReset() scsiDev.target[i].syncOffset = 0; scsiDev.target[i].syncPeriod = 0; } + scsiDev.minSyncPeriod = 0; scsiDiskReset(); @@ -548,6 +551,10 @@ static void process_SelectionPhase() } uint8_t selStatus = *SCSI_STS_SELECTED; + if ((selStatus == 0) && (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SEL_LATCH)) + { + selStatus = scsiDev.selFlag; + } int tgtIndex; TargetState* target = NULL; @@ -615,6 +622,7 @@ static void process_SelectionPhase() { scsiDev.phase = BUS_BUSY; } + scsiDev.selFlag = 0; } static void process_MessageOut() @@ -757,13 +765,22 @@ static void process_MessageOut() int transferPeriod = extmsg[1]; int offset = extmsg[2]; - if ((scsiDev.compatMode < COMPAT_SCSI2) || - (transferPeriod > 50)) // 200ns, 5MB/s + if ((transferPeriod < scsiDev.minSyncPeriod) || + (scsiDev.minSyncPeriod == 0)) + { + scsiDev.minSyncPeriod = transferPeriod; + } + + if ((transferPeriod > 80) || // 320ns, 3.125MB/s + // Amiga A590 (WD33C93 chip) only does 3.5MB/s sync + // After 80 we start to run out of bits in the fpga timing + // register. + (transferPeriod == 0)) { scsiDev.target->syncOffset = 0; scsiDev.target->syncPeriod = 0; } else { - scsiDev.target->syncOffset = offset < 15 ? offset : 15; + scsiDev.target->syncOffset = offset < 63 ? offset : 63; // FAST20 / 50ns / 20MHz is disabled for now due to // data corruption while reading data. We can count the // ACK's correctly, but can't save the data to a register @@ -778,7 +795,7 @@ static void process_MessageOut() { scsiDev.target->syncPeriod = 25; // 100ns, 10MB/s } else { - scsiDev.target->syncPeriod = 50; // 200ns, 5MB/s + scsiDev.target->syncPeriod = transferPeriod; } } @@ -831,7 +848,7 @@ void scsiPoll(void) // one initiator in the chain. Support this by moving // straight to selection if SEL is asserted. // ie. the initiator won't assert BSY and it's own ID before moving to selection. - else if (*SCSI_STS_SELECTED) + else if (scsiDev.selFlag || *SCSI_STS_SELECTED) { enter_SelectionPhase(); } @@ -840,7 +857,7 @@ void scsiPoll(void) case BUS_BUSY: // Someone is using the bus. Perhaps they are trying to // select us. - if (*SCSI_STS_SELECTED) + if (scsiDev.selFlag || *SCSI_STS_SELECTED) { enter_SelectionPhase(); } @@ -937,6 +954,7 @@ void scsiInit() scsiDev.atnFlag = 0; scsiDev.resetFlag = 1; + scsiDev.selFlag = 0; scsiDev.phase = BUS_FREE; scsiDev.target = NULL; scsiDev.compatMode = COMPAT_UNKNOWN; diff --git a/src/firmware/scsi.h b/src/firmware/scsi.h index 2ef223ec..33f3c085 100755 --- a/src/firmware/scsi.h +++ b/src/firmware/scsi.h @@ -115,6 +115,9 @@ typedef struct // Set to true (1) if the RST flag was set. volatile int resetFlag; + // Set to sel register if the SEL flag was set. + volatile int selFlag; + // Set to true (1) if a parity error was observed. int parityError; @@ -151,6 +154,7 @@ typedef struct uint8_t lastStatus; uint8_t lastSense; uint16_t lastSenseASC; + uint8_t minSyncPeriod; // Debug use only. int needSyncNegotiationAck; } ScsiDevice; diff --git a/src/firmware/scsiPhy.c b/src/firmware/scsiPhy.c index e4962965..ad6e2f79 100755 --- a/src/firmware/scsiPhy.c +++ b/src/firmware/scsiPhy.c @@ -28,26 +28,44 @@ #include -// 5MB/s sync and async. -// Assumes a 96MHz fpga clock. +// Time until we consider ourselves selected +// 400ns at 108MHz +#define SCSI_DEFAULT_SELECTION 43 +#define SCSI_FAST_SELECTION 5 + +// async. +// Assumes a 108MHz 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_DEFAULT_TIMING ((0x6 << 4) | 0x9) + +// 3.125MB/s (80 period) to < 10MB/s sync +// Assumes a 108MHz fpga clock. (9 ns) +// (((period * 4) / 2) * 0.8) / 9 +// Done using 3 fixed point math. +// 2:0 Deskew count, 55ns normal, or 25ns if faster than 5.5MB/s +// 6:4 Hold count, 53ns normal, or 33ns if faster than 5.5MB/s +// 3:0 Assertion count, variable +#define SCSI_SYNC_DESKEW(period) (period < 45 ? SCSI_FAST10_DESKEW : SCSI_DEFAULT_DESKEW) +#define SCSI_SYNC_TIMING(period) (((period < 45 ? 0x4 : 0x6) << 4) | ((((((int)period) * 177) + 750)/1000) & 0xF)) // 10MB/s // 2:0 Deskew count, 25ns // 6:4 Hold count, 33ns // 3:0 Assertion count, 30ns -#define SCSI_FAST10_DESKEW 3 +// We want deskew + hold + assert + 3 to add up to 11 clocks +// the fpga code has 1 clock of overhead when transitioning from deskew to +// assert to hold +#define SCSI_FAST10_DESKEW 2 #define SCSI_FAST10_TIMING ((0x3 << 4) | 0x3) // 20MB/s // 2:0 Deskew count, 12ns // 6:4 Hold count, 17ns // 3:0 Assertion count, 15ns -#define SCSI_FAST20_DESKEW 2 +#define SCSI_FAST20_DESKEW 1 #define SCSI_FAST20_TIMING ((0x2 << 4) | 0x2) // Private DMA variables. @@ -60,22 +78,6 @@ static DMA_HandleTypeDef fsmcToMem; volatile uint8_t scsiRxDMAComplete; volatile uint8_t scsiTxDMAComplete; -#if 0 -CY_ISR_PROTO(scsiRxCompleteISR); -CY_ISR(scsiRxCompleteISR) -{ - traceIrq(trace_scsiRxCompleteISR); - scsiRxDMAComplete = 1; -} - -CY_ISR_PROTO(scsiTxCompleteISR); -CY_ISR(scsiTxCompleteISR) -{ - traceIrq(trace_scsiTxCompleteISR); - scsiTxDMAComplete = 1; -} -#endif - uint8_t scsiPhyFifoSel = 0; // global // scsi IRQ handler is initialised by the STM32 HAL. Connected to @@ -93,9 +95,14 @@ void EXTI4_IRQHandler() __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4); scsiDev.resetFlag = scsiDev.resetFlag || scsiStatusRST(); - // TODO grab SEL status as well + // selFlag is required for Philips P2000C which releases it after 600ns + // without waiting for BSY. + // Also required for some early Mac Plus roms + scsiDev.selFlag = *SCSI_STS_SELECTED; } + + __SEV(); // Set event. See corresponding __WFE() calls. } static void assertFail() @@ -129,7 +136,10 @@ scsiReadByte(void) scsiSetDataCount(1); trace(trace_spinPhyRxFifo); - while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {} + while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) + { + __WFE(); // Wait for event + } scsiPhyFifoFlip(); uint8_t val = scsiPhyRx(); // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read(); @@ -152,6 +162,7 @@ static void scsiReadPIO(uint8_t* data, uint32_t count) { uint16_t* fifoData = (uint16_t*)data; + for (int i = 0; i < (count + 1) / 2; ++i) { fifoData[i] = scsiPhyRx(); // TODO ASSUMES LITTLE ENDIAN @@ -218,7 +229,10 @@ scsiRead(uint8_t* data, uint32_t count, int* parityError) while (i < count && likely(!scsiDev.resetFlag)) { - while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {} + while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) + { + __WFE(); // Wait for event + } *parityError |= scsiParityError(); scsiPhyFifoFlip(); @@ -287,7 +301,10 @@ scsiWriteByte(uint8_t value) scsiSetDataCount(1); trace(trace_spinTxComplete); - while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {} + while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) + { + __WFE(); // Wait for event + } #if FIFODEBUG if (!scsiPhyFifoAltEmpty()) { @@ -382,6 +399,7 @@ scsiWrite(const uint8_t* data, uint32_t count) while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) { + __WFE(); // Wait for event } #if FIFODEBUG @@ -397,6 +415,7 @@ scsiWrite(const uint8_t* data, uint32_t count) } while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) { + __WFE(); // Wait for event } #if FIFODEBUG @@ -450,10 +469,11 @@ void scsiEnterPhase(int phase) // SCSI2 FAST Timing. 10MB/s. *SCSI_CTRL_DESKEW = SCSI_FAST10_DESKEW; *SCSI_CTRL_TIMING = SCSI_FAST10_TIMING; - } else { - // 5MB/s Timing - *SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW; - *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING; + } + else + { + *SCSI_CTRL_DESKEW = SCSI_SYNC_DESKEW(scsiDev.target->syncPeriod); + *SCSI_CTRL_TIMING = SCSI_SYNC_TIMING(scsiDev.target->syncPeriod); } *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset; @@ -675,6 +695,8 @@ void scsiPhyInit() *SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW; *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING; + *SCSI_CTRL_SEL_TIMING = SCSI_DEFAULT_SELECTION; + } void scsiPhyConfig() @@ -706,6 +728,9 @@ void scsiPhyConfig() ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY) ? SCSI_CTRL_FLAGS_ENABLE_PARITY : 0); + *SCSI_CTRL_SEL_TIMING = + (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SEL_LATCH) ? + SCSI_FAST_SELECTION : SCSI_DEFAULT_SELECTION; } diff --git a/src/firmware/scsiPhy.h b/src/firmware/scsiPhy.h index 1df96b95..c16d9314 100755 --- a/src/firmware/scsiPhy.h +++ b/src/firmware/scsiPhy.h @@ -31,6 +31,7 @@ #define SCSI_CTRL_FLAGS ((volatile uint8_t*)0x60000016) #define SCSI_CTRL_FLAGS_DISABLE_GLITCH 0x1 #define SCSI_CTRL_FLAGS_ENABLE_PARITY 0x2 +#define SCSI_CTRL_SEL_TIMING ((volatile uint8_t*)0x60000018) #define SCSI_STS_FIFO ((volatile uint8_t*)0x60000020) #define SCSI_STS_ALTFIFO ((volatile uint8_t*)0x60000022) @@ -55,6 +56,11 @@ } #define scsiPhyTx(val) *SCSI_FIFO_DATA = (val) + +// little endian specific !. Also relies on the fsmc outputting the lower +// half-word first. +#define scsiPhyTx32(a,b) *((volatile uint32_t*)SCSI_FIFO_DATA) = (((uint32_t)(b)) << 16) | (a) + #define scsiPhyRx() *SCSI_FIFO_DATA #define scsiPhyComplete() ((*SCSI_STS_FIFO_COMPLETE & 0x01) == 0x01) diff --git a/src/firmware/sd.c b/src/firmware/sd.c index 71ec535c..2f11b793 100755 --- a/src/firmware/sd.c +++ b/src/firmware/sd.c @@ -96,155 +96,6 @@ void sdCompleteTransfer() } -#if 0 -void -sdWriteMultiSectorDMA(uint8_t* outputBuffer) -{ - static uint8_t dmaRxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD}; - static uint8_t dmaTxTd[3] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD, CY_DMA_INVALID_TD}; - if (unlikely(dmaRxTd[0] == CY_DMA_INVALID_TD)) - { - dmaRxTd[0] = CyDmaTdAllocate(); - dmaRxTd[1] = CyDmaTdAllocate(); - dmaTxTd[0] = CyDmaTdAllocate(); - dmaTxTd[1] = CyDmaTdAllocate(); - dmaTxTd[2] = CyDmaTdAllocate(); - - // Transmit 512 bytes of data and then 2 bytes CRC, and then get the response byte - // We need to do this without stopping the clock - CyDmaTdSetConfiguration(dmaTxTd[0], 2, dmaTxTd[1], TD_INC_SRC_ADR); - CyDmaTdSetAddress(dmaTxTd[0], LO16((uint32)&writeStartToken), LO16((uint32)SDCard_TXDATA_PTR)); - - CyDmaTdSetConfiguration(dmaTxTd[1], SD_SECTOR_SIZE, dmaTxTd[2], TD_INC_SRC_ADR); - - CyDmaTdSetConfiguration(dmaTxTd[2], 2 + sizeof(writeResponseBuffer), CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN); - CyDmaTdSetAddress(dmaTxTd[2], LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR)); - - CyDmaTdSetConfiguration(dmaRxTd[0], SD_SECTOR_SIZE + 4, dmaRxTd[1], 0); - CyDmaTdSetAddress(dmaRxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer)); - CyDmaTdSetConfiguration(dmaRxTd[1], sizeof(writeResponseBuffer), CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN|TD_INC_DST_ADR); - CyDmaTdSetAddress(dmaRxTd[1], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&writeResponseBuffer)); - } - CyDmaTdSetAddress(dmaTxTd[1], LO16((uint32)outputBuffer), LO16((uint32)SDCard_TXDATA_PTR)); - - - // The DMA controller is a bit trigger-happy. It will retain - // a drq request that was triggered while the channel was - // disabled. - CyDmaChSetRequest(sdDMATxChan, CY_DMA_CPU_REQ); - CyDmaClearPendingDrq(sdDMARxChan); - - sdTxDMAComplete = 0; - sdRxDMAComplete = 0; - - // Re-loading the initial TD's here is very important, or else - // we'll be re-using the last-used TD, which would be the last - // in the chain (ie. CRC TD) - CyDmaChSetInitialTd(sdDMARxChan, dmaRxTd[0]); - CyDmaChSetInitialTd(sdDMATxChan, dmaTxTd[0]); - - // There is no flow control, so we must ensure we can read the bytes - // before we start transmitting - CyDmaChEnable(sdDMARxChan, 1); - CyDmaChEnable(sdDMATxChan, 1); -} - -int -sdWriteSectorDMAPoll() -{ - if (sdRxDMAComplete && sdTxDMAComplete) - { - if (sdIOState == SD_DMA) - { - // Retry a few times. The data token format is: - // XXX0AAA1 - int i = 0; - uint8_t dataToken; - do - { - dataToken = writeResponseBuffer[i]; // Response - ++i; - } while (((dataToken & 0x0101) != 1) && (i < sizeof(writeResponseBuffer))); - - // At this point we should either have an accepted token, or we'll - // timeout and proceed into the error case below. - if (unlikely(((dataToken & 0x1F) >> 1) != 0x2)) // Accepted. - { - sdIOState = SD_IDLE; - - sdWaitWriteBusy(); - sdSpiByte(0xFD); // STOP TOKEN - sdWaitWriteBusy(); - - sdCmdState = CMD_STATE_IDLE; - scsiDiskReset(); - sdClearStatus(); - - scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; - scsiDev.phase = STATUS; - } - else - { - sdIOState = SD_ACCEPTED; - } - } - - if (sdIOState == SD_ACCEPTED) - { - // Wait while the SD card is busy - if (sdSpiByte(0xFF) == 0xFF) - { - sdIOState = SD_IDLE; - } - } - - return sdIOState == SD_IDLE; - } - else - { - return 0; - } -} - -static void sdCompleteWrite() -{ - if (unlikely(sdIOState != SD_IDLE)) - { - // Not much choice but to wait until we've completed the transfer. - // Cancelling the transfer can't be done as we have no way to reset - // the SD card. - trace(trace_spinSDCompleteWrite); - while (!sdWriteSectorDMAPoll()) { /* spin */ } - } - - if (sdCmdState == CMD_STATE_WRITE) - { - sdWaitWriteBusy(); - - sdSpiByte(0xFD); // STOP TOKEN - - sdWaitWriteBusy(); - } - - - if (likely(scsiDev.phase == DATA_OUT)) - { - uint16_t r2 = sdDoCommand(SD_SEND_STATUS, 0, 0, 1); - if (unlikely(r2)) - { - sdClearStatus(); - scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED; - scsiDev.phase = STATUS; - } - } - sdCmdState = CMD_STATE_IDLE; -} - -#endif static void sdInitDMA() { // One-time init only. @@ -300,8 +151,13 @@ static int sdDoInit() result = 1; // SD Benchmark code - // Currently 8MB/s + // Currently 10MB/s in high-speed mode. #ifdef SD_BENCHMARK + if (HAL_SD_HighSpeed(&hsd) == SD_OK) // normally done in mainLoop() + { + s2s_setFastClock(); + } + while(1) { s2s_ledOn(); @@ -333,64 +189,6 @@ out: return result; } -#if 0 -void sdWriteMultiSectorPrep(uint32_t sdLBA, uint32_t sdSectors) -{ - uint32_t tmpNextLBA = sdLBA + sdSectors; - - if (!sdDev.ccs) - { - sdLBA = sdLBA * SD_SECTOR_SIZE; - tmpNextLBA = tmpNextLBA * SD_SECTOR_SIZE; - } - - if (sdCmdState == CMD_STATE_WRITE && sdCmdNextLBA == sdLBA) - { - // Well, that was lucky. We're already writing this data - sdCmdNextLBA = tmpNextLBA; - sdCmdTime = getTime_ms(); - } - else - { - sdPreCmdState(CMD_STATE_WRITE); - - // Set the number of blocks to pre-erase by the multiple block write - // command. We don't care about the response - if the command is not - // accepted, writes will just be a bit slower. Max 22bit parameter. - uint32 blocks = sdSectors > 0x7FFFFF ? 0x7FFFFF : sdSectors; - sdCommandAndResponse(SD_APP_CMD, 0); - sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks); - - uint8_t v = sdCommandAndResponse(SD_WRITE_MULTIPLE_BLOCK, sdLBA); - if (unlikely(v)) - { - scsiDiskReset(); - sdClearStatus(); - scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; - scsiDev.phase = STATUS; - } - else - { - sdCmdTime = getTime_ms(); - sdCmdNextLBA = tmpNextLBA; - sdCmdState = CMD_STATE_WRITE; - } - } -} - -void sdPoll() -{ - if ((scsiDev.phase == BUS_FREE) && - (sdCmdState != CMD_STATE_IDLE) && - (elapsedTime_ms(sdCmdTime) >= 50)) - { - sdPreCmdState(CMD_STATE_IDLE); - } -} - -#endif int sdInit() { // Check if there's an SD card present. diff --git a/src/scsi2sd-util6/scsi2sd-util.cc b/src/scsi2sd-util6/scsi2sd-util.cc index 82094764..988f9c7b 100644 --- a/src/scsi2sd-util6/scsi2sd-util.cc +++ b/src/scsi2sd-util6/scsi2sd-util.cc @@ -543,7 +543,7 @@ private: ss << "dfu-util "; } else { wxFileName exePath(wxStandardPaths::Get().GetExecutablePath()); - ss << exePath.GetPathWithSep() << "dfu-util "; + ss << '"' << exePath.GetPathWithSep() << "dfu-util\" "; } ss << "--download \"" << filename.c_str() << "\" --alt 0 --reset"; #endif diff --git a/src/scsi2sd-util6/wxWidgets/src/stc/scintilla/src/Editor.cxx b/src/scsi2sd-util6/wxWidgets/src/stc/scintilla/src/Editor.cxx index cd72953a..2081df28 100644 --- a/src/scsi2sd-util6/wxWidgets/src/stc/scintilla/src/Editor.cxx +++ b/src/scsi2sd-util6/wxWidgets/src/stc/scintilla/src/Editor.cxx @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -5841,9 +5842,9 @@ void Editor::GoToLine(int lineNo) { } static bool Close(Point pt1, Point pt2) { - if (abs(pt1.x - pt2.x) > 3) + if (std::abs(pt1.x - pt2.x) > 3) return false; - if (abs(pt1.y - pt2.y) > 3) + if (std::abs(pt1.y - pt2.y) > 3) return false; return true; } -- 2.38.5