stm32f103 HAL庫sdmmc bug
釋出版本: 1.0
檔案密級: 公開資料
前言
概述
讀者
本文檔(本指南)主要使用于以下工程師:
軟體開發工程師
産品版本 修訂記錄
日期 | 版本 | 作者/郵箱 | 修訂說明 |
---|---|---|---|
2019-12-29 | V1.0 | wingceltis-c/[email protected] | 初始版本 |
文章目錄
- stm32f103 HAL庫sdmmc bug
- 簡述
-
- 1.TIMEOUT标志位清除錯誤
- 2. CMD55響應資料判斷異常
簡述
這段時間用stm32f103寫個小項目需要用到sd卡 + fatfs檔案系統的功能。用cube配置完成後,1G 2G的sd卡讀寫都沒有問題,256M的卡在執行f_mount的時候會傳回FR_NOT_READY錯誤,跟了下代碼發現是在stm32f1xx_hal_sd.c的SD_PowerON方法中,因為1G 2G的卡剛好是V2.0的版本,而手上的256M剛好是V1.x的版本,這就導緻走的流程有點不一樣,不過正常來說HAL庫應該也是要支援V1.x版本的。百度了下相關錯誤并且和正點原子3.5庫函數版本的代碼對比了下發現是下面的錯誤導緻的。
1.TIMEOUT标志位清除錯誤
在stm32f1xx_hal_sd.c的SD_PowerON方法中,會先發送CMD8指令判斷目前SD卡的版本,如果有響應就是V2.0,沒有響應就是V1.X版本或者MMC卡。 hal庫中SDMMC_CmdOperCond這個方法會先發送CMD8指令然後調用SDMMC_GetCmdResp7方法接收響應的資料,我這個256M的卡是V1.x版本是以沒有響應會報逾時錯誤,正常邏輯就是清除逾時标志位然後傳回對應錯誤即可,HAL庫這裡應該是書寫錯誤,寫成了清除SDIO_FLAG_CMDREND 标志位。導緻後面的指令會直接報逾時錯誤。
錯誤代碼:
static uint32_t SDMMC_GetCmdResp7(SDIO_TypeDef *SDIOx)
if (__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT))
{
/* Card is SD V2.0 compliant */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CMDREND); //這裡應該要清除逾時标志位的
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
把SDIO_FLAG_CMDREND改成 SDIO_FLAG_CTIMEOUT即可,修改成如下代碼:
static uint32_t SDMMC_GetCmdResp7(SDIO_TypeDef *SDIOx)
if (__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT))
{
/* Card is SD V2.0 compliant */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_FLAG_CTIMEOUT); //清除逾時标志位
return SDMMC_ERROR_CMD_RSP_TIMEOUT;
}
2. CMD55響應資料判斷異常
接着上面的流程,發送CMD8沒響應後接着會發送CMD55,如果有響應就是V1.x版本的SD卡沒有響應就是MMC卡(預設HAL庫好像是不支援MMC卡)。這個CMD55的接受方法SDMMC_GetCmdResp1也有問題,HAL庫收到CMD55響應後,還會判斷資料内容,隻要不是全0就會報錯 SDMMC_OCR_ILLEGAL_CMD,剛好我手上的卡會傳回一串非零數字,導緻初始化失敗,是以這裡直接清除這個标志位即可。
修改如下:
static uint32_t SDMMC_GetCmdResp1(SDIO_TypeDef *SDIOx, uint8_t SD_CMD, uint32_t Timeout)
/* Clear all the static flags */
__SDIO_CLEAR_FLAG(SDIOx, SDIO_STATIC_FLAGS);
/* We have received response, retrieve it for analysis */
response_r1 = SDIO_GetResponse(SDIOx, SDIO_RESP1);
/*
2019-12-28
收到CMD55響應後,還會判斷資料内容,隻要不是全0就會報錯 SDMMC_OCR_ILLEGAL_CMD。
有些卡會傳回一串非零數字,導緻初始化失敗,是以這裡直接清除标志位。
*/
response_r1 &= !SDMMC_OCR_ILLEGAL_CMD;
if ((response_r1 & SDMMC_OCR_ERRORBITS) == SDMMC_ALLZERO)
{
return SDMMC_ERROR_NONE;
}
參考連結:
http://www.stm32cube.com/question/1106
http://www.stmcu.org.cn/module/forum/thread-614460-1-1.html