STM32 SPI驱动SD卡发送CMD命令未获得正确返回值

        最近调试SD卡的时候遇到了发送CMD命令但没有收到正确回应的问题。先简单叙述一下开发环境,我使用的是STM32CubeMX+MDK5,板子用的是原子哥F407探索者。这次的需求是使用SPI驱动SD卡,并建立FATFS文件系统用于管理卡内数据,另外使能了串口1并重定向了printf到串口以便直接观察。

        基本了解SD卡驱动流程后就直接开始实战操作(SD卡的驱动流程、卡的驱动及挂载文件系统的代码都可以在网上找,很容易能够找到,这里就不赘述了),在下载的代码基础上用if语句判断f_mkfs、f_mount和f_open函数是否成功执行,成功返回0,否则返回错误代码。建立工程文件并且编译无误后直接烧录到板子上。摁下reset后自信的以为写入的数据能够一行行的打印在串口助手上(之所以自信因为之前用SDIO调试一次性过关),但结果却狠狠打脸。

图 1.0

        f_mount函数返回了错误代码3,f_open函数甚至没有显示错误代码,说明程序卡在了f_mount函数里。那么接下来就在代码中查看这个错误代码的详细定义。

图 1.1

        错误代码3,FR_NOT_READY,这意味着SD卡的初始化就没有成功,说明在向SD卡发送cmd0命令后,SD卡并没有给我们返回正确的值,不知道为什么会出现这个问题,那就直接上百度。百度上的回答各式各样,其中一个较多的回答是将f_mount函数的最后一个参数改为0,改了之后确实函数返回了0,但串口助手上什么都没有了,后来搞明白了,这个参数为0就是后面再执行加载操作,也就是说无论是否外挂设备,函数都会返回0,但这样是没有意义的,问题还是没有解决。这之后我又试过很多网上的方案,拉高无线模块、flash的片选,拉高SPI的MOSI、SCK,改时钟频率等等,但都没有解决问题。思来想去,我觉得问题肯定出在硬件上,只好又去啃原理图了。

图 1.2

         我甚至想过会不会SPI的管脚没有接到板载卡槽的管脚上,但看原理图SDIO和SPI是有共用管脚的,最后实在没有办法了,就单独买了一个SPI的模块。本来我都没抱多大希望的,结果偏偏就行了。

图 1.3

        成功进入卡识别模式,识别出了卡的类型,但却没能进入数据传输模式,f_mount函数依旧没有完全执行,返回的错误代码变成了1,FR_DISK_ERR(这里可先忽略上图中的cmd17)。没办法,只好debug打断点去找问题所在了。

图 1.4

        通过打断点找到了问题所在,f_mount函数返回的错误代码1是由move_window函数返回的,路径是:f_mount->find_volume->check_fs->move_window,move window函数又调用了disk_read函数,这个函数的返回值不等于RES_OK,导致move_window函数最终返回了FR_DISK_ERR。

图 1.5

       再进到disk_read函数中,调用了SD_ReadDisk函数并把返回值赋给了res,而SD_ReadDisk函数的返回值不为0,因此 disk_read函数返回了RES_ERROR。

图 1.6

        再进到SD_ReadDisk函数中就找到问题的根源了,板子给SD卡发送CMD17,正常情况下,SD卡回应0x00,然后是0xFE,紧跟着是512字节的数据,于是我将发送CMD17后的回应值打印出来,果然返回值不是0x00(见图 1.3)。

        SD卡能进入卡识别模式说明CMD0是成功发送的,那么这里的CMD17也应该是成功发送的,但SD卡却没有回应0x00,但也不是完全没回应,0x6F(111)看起来应该是个随机数,没什么特别含义,我又突然想到之前在网上看到有说SPI通讯时杜邦线不太稳定,想到这里我大概已经猜到问题所在了,很有可能是在传输过程中由于距离的问题电压不稳,从而导致数据异常。于是我将连接线做短到12~15cm后再次尝试。

图 1.7

        果然,问题解决了,发送CMD17后SD卡正确回应了0x00,f_mount、f_mkfs、f_open函数也不再报错。卡在这个问题将近两周时间,最后仅仅是线长的问题,听起来是有点抽象,不过遇到这个问题的朋友可以顺着这个思路慢慢排查是究竟是代码或者是其他的什么问题。

        至于为什么把SD卡插在板载的卡槽上不行,用单独的模块就行我也不太清楚,我把单独模块的原理图附上,如果有大佬看到这里希望能解答一下。

图 1.8

        最后给大家看看我之前使用的杜邦线长度,很夸张。

图 1.9
物联沃分享整理
物联沃-IOTWORD物联网 » STM32 SPI驱动SD卡发送CMD命令未获得正确返回值

发表评论