天天看点

stm32f103 HAL库sdmmc bugstm32f103 HAL库sdmmc bug简述

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

继续阅读