From bc72931fc035af5f46f12a3de886a0a9b2d64319 Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Sat, 24 Apr 2021 00:13:57 +1000 Subject: [PATCH] Fix SD card corruption due to not waiting for SD to leave the programming state --- .../Inc/stm32f4xx_ll_sdmmc.h | 1 + .../Src/stm32f4xx_hal_sd.c | 29 ++++--- .../Src/stm32f4xx_ll_sdmmc.c | 25 ++++++ src/firmware/bsp_driver_sd.c | 85 +++++++++++++++++++ src/firmware/disk.c | 11 +-- 5 files changed, 132 insertions(+), 19 deletions(-) diff --git a/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_sdmmc.h b/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_sdmmc.h index c966c906..9d709100 100644 --- a/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_sdmmc.h +++ b/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_sdmmc.h @@ -1074,6 +1074,7 @@ uint32_t SDMMC_CmdReadSingleBlock(SDIO_TypeDef *SDIOx, uint32_t ReadAdd); uint32_t SDMMC_CmdReadMultiBlock(SDIO_TypeDef *SDIOx, uint32_t ReadAdd); uint32_t SDMMC_CmdWriteSingleBlock(SDIO_TypeDef *SDIOx, uint32_t WriteAdd); uint32_t SDMMC_CmdWriteMultiBlock(SDIO_TypeDef *SDIOx, uint32_t WriteAdd); +uint32_t SDMMC_CmdSetBlockCount(SDIO_TypeDef *SDIOx, uint32_t appCmdArg, uint32_t blockCount); uint32_t SDMMC_CmdEraseStartAdd(SDIO_TypeDef *SDIOx, uint32_t StartAdd); uint32_t SDMMC_CmdSDEraseStartAdd(SDIO_TypeDef *SDIOx, uint32_t StartAdd); uint32_t SDMMC_CmdEraseEndAdd(SDIO_TypeDef *SDIOx, uint32_t EndAdd); diff --git a/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sd.c b/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sd.c index 6fffb514..1a09028f 100644 --- a/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sd.c +++ b/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sd.c @@ -1352,6 +1352,19 @@ HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, return HAL_ERROR; } + if(NumberOfBlocks > 1U && hsd->SdCard.CardType == CARD_SDHC_SDXC) + { + /* MM: Prepare for write */ + errorstate = SDMMC_CmdSetBlockCount(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd) << 16, NumberOfBlocks); + if(errorstate != HAL_SD_ERROR_NONE) + { + __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + } + hsd->State = HAL_SD_STATE_BUSY; /* Initialize data control register */ @@ -1394,18 +1407,6 @@ HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, { hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA); - /* MM: Prepare for write */ -/* TODO - SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->RCA << 16)); - SDIO_CmdInitTypeDef mm_cmdinit; - mm_cmdinit.Argument = (uint32_t)NumberOfBlocks; - mm_cmdinit.CmdIndex = SDMMC_CMD_SET_BLOCK_COUNT; - mm_cmdinit.Response = SDIO_RESPONSE_SHORT; - mm_cmdinit.WaitForInterrupt = SDIO_WAIT_NO; - mm_cmdinit.CPSM = SDIO_CPSM_ENABLE; - (void)SDIO_SendCommand(hsd->Instance, &mm_cmdinit); - SDMMC_GetCmdResp1(hsd->Instance, SDMMC_CMD_SET_BLOCK_COUNT, SDIO_CMDTIMEOUT);*/ - /* Write Multi Block command */ errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); } @@ -1658,6 +1659,10 @@ void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd) HAL_SD_ErrorCallback(hsd); #endif /* USE_HAL_SD_REGISTER_CALLBACKS */ } + __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS); + + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; } if(((context & SD_CONTEXT_READ_SINGLE_BLOCK) == 0U) && ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) == 0U)) { diff --git a/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c b/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c index 4f23a455..614b6dce 100644 --- a/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c +++ b/STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c @@ -606,6 +606,31 @@ uint32_t SDMMC_CmdWriteSingleBlock(SDIO_TypeDef *SDIOx, uint32_t WriteAdd) return errorstate; } +/** + * @brief Set the count of a multi-block write command + * @param SDIOx: Pointer to SDIO register base + * @retval HAL status + */ +uint32_t SDMMC_CmdSetBlockCount(SDIO_TypeDef *SDIOx, uint32_t appCmdArg, uint32_t blockCount) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinit; + uint32_t errorstate; + + errorstate = SDMMC_CmdAppCommand(SDIOx, appCmdArg); + if(errorstate == HAL_SD_ERROR_NONE) + { + sdmmc_cmdinit.Argument = blockCount; + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_BLOCK_COUNT; + sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE; + (void)SDIO_SendCommand(SDIOx, &sdmmc_cmdinit); + errorstate = SDMMC_GetCmdResp1(SDIOx, SDMMC_CMD_SET_BLOCK_COUNT, SDIO_CMDTIMEOUT); + } + + return errorstate; +} + /** * @brief Send the Write Multi Block command and check the response * @param SDIOx: Pointer to SDIO register base diff --git a/src/firmware/bsp_driver_sd.c b/src/firmware/bsp_driver_sd.c index 5f31d24b..fe2601c4 100755 --- a/src/firmware/bsp_driver_sd.c +++ b/src/firmware/bsp_driver_sd.c @@ -63,6 +63,89 @@ uint8_t BSP_SD_Init(void) else { SD_state = MSD_OK; + +// Clock bypass mode is broken on STM32F205 +// This just corrupts data for now. +//#ifdef STM32F4xx +#if 0 + uint8_t SD_hs[64] = {0}; + //uint32_t SD_scr[2] = {0, 0}; + //uint32_t SD_SPEC = 0 ; + uint32_t count = 0; + uint32_t *tempbuff = (uint32_t *)SD_hs; + + // Prepare to read 64 bytes training data + SDIO_DataInitTypeDef config; + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = 64; + config.DataBlockSize = SDIO_DATABLOCK_SIZE_64B; + config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + config.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + config.DPSM = SDIO_DPSM_ENABLE; + (void)SDIO_ConfigData(hsd.Instance, &config); + + // High speed switch. + // SDR25 (25MB/s) mode 0x80FFFF01 + // Which is the max without going to 1.8v + uint32_t errorstate = SDMMC_CmdSwitch(hsd.Instance, 0x80FFFF01); + + // Low-level init for the bypass. Changes registers only + hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE; + SDIO_Init(hsd.Instance, hsd.Init); + + // Now we read some training data + + if (errorstate == HAL_SD_ERROR_NONE) + { + while(!__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND/* | SDIO_FLAG_STBITERR*/)) + { + if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXFIFOHF)) + { + for (count = 0; count < 8; count++) + { + *(tempbuff + count) = SDIO_ReadFIFO(hsd.Instance); + } + + tempbuff += 8; + } + } + + if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_CLEAR_FLAG(&hsd, SDIO_FLAG_DTIMEOUT); + SD_state = MSD_ERROR; + } + else if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_CLEAR_FLAG(&hsd, SDIO_FLAG_DCRCFAIL); + SD_state = MSD_ERROR; + } + else if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(&hsd, SDIO_FLAG_RXOVERR); + SD_state = MSD_ERROR; + } + /*else if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_STBITERR)) + { + __HAL_SD_CLEAR_FLAG(&hsd, SDIO_FLAG_STBITERR); + SD_state = MSD_ERROR; + }*/ + else + { + count = SD_DATATIMEOUT; + + while ((__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXDAVL)) && (count > 0)) + { + *tempbuff = SDIO_ReadFIFO(hsd.Instance); + tempbuff++; + count--; + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(&hsd, SDIO_STATIC_FLAGS); + } + } +#endif } } #endif @@ -199,6 +282,8 @@ uint8_t BSP_SD_WriteBlocks_DMA(uint8_t *pData, uint64_t BlockAddr, uint32_t NumO { SD_state = MSD_OK; } + + while (HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_PROGRAMMING) {} } return SD_state; diff --git a/src/firmware/disk.c b/src/firmware/disk.c index 72cfeda9..1f849eca 100755 --- a/src/firmware/disk.c +++ b/src/firmware/disk.c @@ -739,12 +739,6 @@ void scsiDiskPoll() int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY; uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE; - #ifdef STM32F4xx - // TODO fix this hack - // corruption occurs with 65536 byte transfers but not 32768 - // works fine on STM32F2 (or at least it did with older firmware ? - if (maxSectors > 64) maxSectors = 64; - #endif static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)"); @@ -878,7 +872,10 @@ void scsiDiskPoll() { // Wait while keeping BSY. } - HAL_SD_GetCardState(&hsd); // TODO check error response + while (HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_PROGRAMMING) + { + // Wait while the SD card is writing buffer to flash + } if (underrun && (!parityError || !enableParity)) { -- 2.38.5