OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 8478|回复: 9

SD卡卡死现象分析 踩坑记?!!

[复制链接]

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
发表于 2020-12-30 15:13:10 | 显示全部楼层 |阅读模式
本帖最后由 jiangyy 于 2020-12-30 15:19 编辑

  基于LIB库,移植原子的SD卡代码,采用的是寄存器查询模式。目前的项目产品已经开始量产化。据售后收集到的问题,反馈说机器有几台出现上电死机现象,无论怎么重启机器都卡死。后面更换SD卡,现象消失。或者重新拔插SD卡,上电正常。初步判断问题有几点:
  1.SD卡槽受损,两侧抓力不够
  2.SD卡损坏(概率极低)
  3.SD卡表面氧化或弹片接触不良
  后面分析,确实是卡槽有点接触不良,但是程序不至于导致死机。后面分析代码,看到确实有超时机制处理。仿真看看到底死在哪里,找到病根,死在这里。

  1. SD_Error SD_ReadBlock(u8 *buf,long long addr,u16 blksize)
  2. {
  3.         ************;
  4.         if(DeviceMode==SD_POLLING_MODE)                                                //查询模式,轮询数据         
  5.         {
  6.                  INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
  7.                 while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误   /*死在这里面*/
  8.                 {
  9.                         if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)                                                //接收区半满,表示至少存了8个字
  10.                         {
  11.                                 for(count=0;count<8;count++)                        //循环读取数据
  12.                                 {
  13.                                         *(tempbuff+count)=SDIO->FIFO;
  14.                                 }
  15.                                 tempbuff+=8;         
  16.                                 timeout=0X7FFFFF;         //读数据溢出时间
  17.                         }else         //处理超时
  18.                         {
  19.                                 if(timeout==0)return SD_DATA_TIMEOUT;
  20.                                 timeout--;
  21.                         }
  22.                 }
  23.                 if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)                //数据超时错误
  24.                 {                                                                                   
  25.                          SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);         //清错误标志
  26.                         return SD_DATA_TIMEOUT;
  27.                  }else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)        //数据块CRC错误
  28.                 {
  29.                          SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);                  //清错误标志
  30.                         return SD_DATA_CRC_FAIL;                  
  31.                 }else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)         //接收fifo上溢错误
  32.                 {
  33.                          SDIO_ClearFlag(SDIO_FLAG_RXOVERR);                //清错误标志
  34.                         return SD_RX_OVERRUN;                 
  35.                 }else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)         //接收起始位错误
  36.                 {
  37.                          SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
  38.                         return SD_START_BIT_ERR;                 
  39.                 }   
  40.                 while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)        //FIFO里面,还存在可用数据
  41.                 {
  42.                         *tempbuff=SDIO->FIFO;        //循环读取数据
  43.                         tempbuff++;
  44.                 }
  45.                 INTX_ENABLE();//开启总中断
  46.                 SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
  47.          
  48.         }
  49.         else
  50.         {
  51.                 ************;
  52.         }
  53. }
复制代码
死在wihle循环里面,其中全局变量timeout在上面就已经赋值 SDIO_DATATIMEOUT ,这个值很大。其次while循环里面的判断逻辑有错误,如果!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9)))条件一直满足,timeout变量会重复性的赋值,导致一直卡在while循环。网上搜索,有人说文件系统定义的变量(FATFS,FIL等等)是局部变量导致,改成全局变量解决,我感觉不是这个问题,我的都是全局变量。但是基于这个问题,我在while循环改变一下逻辑,防止死机现象,代码如下:
  1. if(DeviceMode==SD_POLLING_MODE)                                                //查询模式,轮询数据         
  2. {
  3.         timeout=0X7FFFFF;         //修改1
  4.         INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
  5.         while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误   /*死在这里面*/
  6.         {
  7.                 if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)                                                //接收区半满,表示至少存了8个字
  8.                 {
  9.                         for(count=0;count<8;count++)                        //循环读取数据
  10.                         {
  11.                                 *(tempbuff+count)=SDIO->FIFO;
  12.                         }
  13.                         tempbuff+=8;         
  14.                                
  15.                 }else         //处理超时
  16.                 {
  17.                         if(timeout==0)
  18.                         {
  19.                                 /*添加代码*/修改2
  20.                                 告诉PC上位机SD卡损坏;
  21.                                 return SD_DATA_TIMEOUT;
  22.                         }
  23.                         timeout--;
  24.                 }
  25.         }
  26.         if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)                //数据超时错误
  27.         {                                                                                   
  28.                 SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);         //清错误标志
  29.                 return SD_DATA_TIMEOUT;
  30.          }else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)        //数据块CRC错误
  31.         {
  32.                  SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);                  //清错误标志
  33.                 return SD_DATA_CRC_FAIL;                  
  34.         }else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)         //接收fifo上溢错误
  35.         {
  36.                  SDIO_ClearFlag(SDIO_FLAG_RXOVERR);                //清错误标志
  37.                 return SD_RX_OVERRUN;                 
  38.         }else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)         //接收起始位错误
  39.         {
  40.                  SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
  41.                 return SD_START_BIT_ERR;                 
  42.         }   
  43.         while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)        //FIFO里面,还存在可用数据
  44.         {
  45.                 *tempbuff=SDIO->FIFO;        //循环读取数据
  46.                 tempbuff++;
  47.         }
  48.         INTX_ENABLE();//开启总中断
  49.         SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记

  50. }
复制代码

  改成这样,就不会死机。但是有个问题,这样会导致SD卡无法读取数据,但可以写数据。目前还没找到具体的原因,但是卡槽的失效确实会产生这个问题。
  基于HAL库,对比一样的读块操作函数,只看while那部分,代码如下:

  1.     while(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR))
  2.     {
  3.       if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF) && (dataremaining > 0U))
  4.       {
  5.         /* Read data from SDIO Rx FIFO */
  6.         for(count = 0U; count < 8U; count++)
  7.         {
  8.           data = SDIO_ReadFIFO(hsd->Instance);
  9.           *tempbuff = (uint8_t)(data & 0xFFU);
  10.           tempbuff++;
  11.           dataremaining--;
  12.           *tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
  13.           tempbuff++;
  14.           dataremaining--;
  15.           *tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
  16.           tempbuff++;
  17.           dataremaining--;
  18.           *tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
  19.           tempbuff++;
  20.           dataremaining--;
  21.         }
  22.       }

  23.       if(((HAL_GetTick()-tickstart) >=  Timeout) || (Timeout == 0U))
  24.       {
  25.         /* Clear all the static flags */
  26.         __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
  27.         hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
  28.         hsd->State= HAL_SD_STATE_READY;
  29.         hsd->Context = SD_CONTEXT_NONE;
  30.         return HAL_TIMEOUT;
  31.       }
  32.     }
复制代码
可以看出,HAL库的查询机制比LIB库逻辑更为谨慎,并没有在while循环重复性对时间变量赋值。项目中本想一直推荐使用HAL库,但是考虑开发周期,暂时没用。  对了,有哪位贴友,知道怎么处理这个异常现象,请留言,一起分析,共同进步。

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2023-3-14 20:55:34 | 显示全部楼层
backup2k 发表于 2023-3-7 14:50
我也是用正点原子ministm32的SD+FATFS代码遇到问题。做编程器应用,出现了把SD卡用坏的情况,目前用坏3块闪 ...

要使用数码高速SD卡
回复 支持 1 反对 0

使用道具 举报

233

主题

957

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1794
金钱
1794
注册时间
2011-10-9
在线时间
223 小时
发表于 2021-1-5 15:10:55 | 显示全部楼层
在实际程序里 能不用while就不用 大多数死机都是这个语句造成的   逻辑特别严密的老师除外
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2021-1-8 14:17:31 | 显示全部楼层
企业微信截图_16100864008535.png

加入一些测试用例,发现影响死机的最主要是  DAT0引脚,我模拟DAT0引脚绝缘,会导致死机现象,但是其他不会死机。
回复 支持 反对

使用道具 举报

19

主题

86

帖子

0

精华

高级会员

Rank: 4

积分
791
金钱
791
注册时间
2013-9-29
在线时间
178 小时
发表于 2021-3-29 12:48:52 | 显示全部楼层
楼主怎么解决的,遇到了同样的问题
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2021-3-29 14:22:45 | 显示全部楼层
zkyzhh 发表于 2021-3-29 12:48
楼主怎么解决的,遇到了同样的问题

增加超时机制,上面代码
回复 支持 反对

使用道具 举报

0

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
77
金钱
77
注册时间
2016-3-27
在线时间
11 小时
发表于 2021-3-31 11:38:38 | 显示全部楼层
学习中,受用了
回复 支持 反对

使用道具 举报

13

主题

643

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2432
金钱
2432
注册时间
2019-12-28
在线时间
527 小时
发表于 2021-4-1 10:55:02 | 显示全部楼层
学习中,感谢楼主分享
回复 支持 反对

使用道具 举报

6

主题

315

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1669
金钱
1669
注册时间
2018-1-29
在线时间
160 小时
发表于 2023-3-7 14:50:26 来自手机 | 显示全部楼层
我也是用正点原子ministm32的SD+FATFS代码遇到问题。做编程器应用,出现了把SD卡用坏的情况,目前用坏3块闪迪SD卡。程序就是读取SD卡文件系统的内容通过串行传输。实在想不通原因。
回复 支持 反对

使用道具 举报

14

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
283
金钱
283
注册时间
2015-4-19
在线时间
137 小时
发表于 2023-3-24 21:50:33 | 显示全部楼层
我现在就是卡死在这里,已经怀疑接触 或 SD 卡问题,一直不知道怎么解决
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-24 17:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表