Fix SD card corruption due to not waiting for SD to leave the programming state v6.4.1
authorMichael McMaster <michael@codesrc.com>
Fri, 23 Apr 2021 14:13:57 +0000 (00:13 +1000)
committerMichael McMaster <michael@codesrc.com>
Fri, 23 Apr 2021 14:13:57 +0000 (00:13 +1000)
STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_sdmmc.h
STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sd.c
STM32CubeMX/2021/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c
src/firmware/bsp_driver_sd.c
src/firmware/disk.c

index c966c9066952340379e934988fbfe33f70a652fd..9d70910056ae89da3d174894fd8f6a9abb4b3b38 100644 (file)
@@ -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);
index 6fffb51416f983d368167efeb95f052f0b364f22..1a09028f3a7d6080689dd77419dc10429f14235a 100644 (file)
@@ -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))
       {
index 4f23a455d8fc2d0bb144b8884f9a2edf8cc5b259..614b6dceacb46a3c1d1df4cf58e44471884e4c1a 100644 (file)
@@ -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 
index 5f31d24b6228d581b1962a3ff02f5e86c37e862a..fe2601c43d29abd2236267d722a2c6437789d14a 100755 (executable)
@@ -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; 
index 72cfeda9c2112bacfa170b7291d6e62aa33a21b7..1f849eca17c93349584e3918c5bce3823053264a 100755 (executable)
@@ -739,12 +739,6 @@ void scsiDiskPoll()
                int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;\r
 \r
                uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
-        #ifdef STM32F4xx\r
-        // TODO fix this hack\r
-        // corruption occurs with 65536 byte transfers but not 32768\r
-        // works fine on STM32F2 (or at least it did with older firmware ?\r
-        if (maxSectors > 64) maxSectors = 64;\r
-        #endif\r
 \r
                static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");\r
 \r
@@ -878,7 +872,10 @@ void scsiDiskPoll()
                                {\r
                                        // Wait while keeping BSY.\r
                                }\r
-                               HAL_SD_GetCardState(&hsd); // TODO check error response\r
+                while (HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_PROGRAMMING) \r
+                {\r
+                    // Wait while the SD card is writing buffer to flash\r
+                }\r
 \r
                                if (underrun && (!parityError || !enableParity))\r
                                {\r