金牌会员
 
- 积分
- 2099
- 金钱
- 2099
- 注册时间
- 2017-2-11
- 在线时间
- 306 小时
|
本帖最后由 jiangyy 于 2020-12-30 15:19 编辑
基于LIB库,移植原子的SD卡代码,采用的是寄存器查询模式。目前的项目产品已经开始量产化。据售后收集到的问题,反馈说机器有几台出现上电死机现象,无论怎么重启机器都卡死。后面更换SD卡,现象消失。或者重新拔插SD卡,上电正常。初步判断问题有几点:
1.SD卡槽受损,两侧抓力不够
2.SD卡损坏(概率极低)
3.SD卡表面氧化或弹片接触不良
后面分析,确实是卡槽有点接触不良,但是程序不至于导致死机。后面分析代码,看到确实有超时机制处理。仿真看看到底死在哪里,找到病根,死在这里。
- SD_Error SD_ReadBlock(u8 *buf,long long addr,u16 blksize)
- {
- ************;
- if(DeviceMode==SD_POLLING_MODE) //查询模式,轮询数据
- {
- INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
- while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误 /*死在这里面*/
- {
- if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET) //接收区半满,表示至少存了8个字
- {
- for(count=0;count<8;count++) //循环读取数据
- {
- *(tempbuff+count)=SDIO->FIFO;
- }
- tempbuff+=8;
- timeout=0X7FFFFF; //读数据溢出时间
- }else //处理超时
- {
- if(timeout==0)return SD_DATA_TIMEOUT;
- timeout--;
- }
- }
- if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) //数据超时错误
- {
- SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清错误标志
- return SD_DATA_TIMEOUT;
- }else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) //数据块CRC错误
- {
- SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
- return SD_DATA_CRC_FAIL;
- }else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) //接收fifo上溢错误
- {
- SDIO_ClearFlag(SDIO_FLAG_RXOVERR); //清错误标志
- return SD_RX_OVERRUN;
- }else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) //接收起始位错误
- {
- SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
- return SD_START_BIT_ERR;
- }
- while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET) //FIFO里面,还存在可用数据
- {
- *tempbuff=SDIO->FIFO; //循环读取数据
- tempbuff++;
- }
- INTX_ENABLE();//开启总中断
- SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
-
- }
- else
- {
- ************;
- }
- }
复制代码 死在wihle循环里面,其中全局变量timeout在上面就已经赋值 SDIO_DATATIMEOUT ,这个值很大。其次while循环里面的判断逻辑有错误,如果!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9)))条件一直满足,timeout变量会重复性的赋值,导致一直卡在while循环。网上搜索,有人说文件系统定义的变量(FATFS,FIL等等)是局部变量导致,改成全局变量解决,我感觉不是这个问题,我的都是全局变量。但是基于这个问题,我在while循环改变一下逻辑,防止死机现象,代码如下:- if(DeviceMode==SD_POLLING_MODE) //查询模式,轮询数据
- {
- timeout=0X7FFFFF; //修改1
- INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
- while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误 /*死在这里面*/
- {
- if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET) //接收区半满,表示至少存了8个字
- {
- for(count=0;count<8;count++) //循环读取数据
- {
- *(tempbuff+count)=SDIO->FIFO;
- }
- tempbuff+=8;
-
- }else //处理超时
- {
- if(timeout==0)
- {
- /*添加代码*/修改2
- 告诉PC上位机SD卡损坏;
- return SD_DATA_TIMEOUT;
- }
- timeout--;
- }
- }
- if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) //数据超时错误
- {
- SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清错误标志
- return SD_DATA_TIMEOUT;
- }else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) //数据块CRC错误
- {
- SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
- return SD_DATA_CRC_FAIL;
- }else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) //接收fifo上溢错误
- {
- SDIO_ClearFlag(SDIO_FLAG_RXOVERR); //清错误标志
- return SD_RX_OVERRUN;
- }else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) //接收起始位错误
- {
- SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
- return SD_START_BIT_ERR;
- }
- while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET) //FIFO里面,还存在可用数据
- {
- *tempbuff=SDIO->FIFO; //循环读取数据
- tempbuff++;
- }
- INTX_ENABLE();//开启总中断
- SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
-
- }
复制代码
改成这样,就不会死机。但是有个问题,这样会导致SD卡无法读取数据,但可以写数据。目前还没找到具体的原因,但是卡槽的失效确实会产生这个问题。
基于HAL库,对比一样的读块操作函数,只看while那部分,代码如下:
- 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) && (dataremaining > 0U))
- {
- /* Read data from SDIO Rx FIFO */
- for(count = 0U; count < 8U; count++)
- {
- data = SDIO_ReadFIFO(hsd->Instance);
- *tempbuff = (uint8_t)(data & 0xFFU);
- tempbuff++;
- dataremaining--;
- *tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
- tempbuff++;
- dataremaining--;
- *tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
- tempbuff++;
- dataremaining--;
- *tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
- tempbuff++;
- dataremaining--;
- }
- }
- if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))
- {
- /* Clear all the static flags */
- __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
- hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
- hsd->State= HAL_SD_STATE_READY;
- hsd->Context = SD_CONTEXT_NONE;
- return HAL_TIMEOUT;
- }
- }
复制代码 可以看出,HAL库的查询机制比LIB库逻辑更为谨慎,并没有在while循环重复性对时间变量赋值。项目中本想一直推荐使用HAL库,但是考虑开发周期,暂时没用。 对了,有哪位贴友,知道怎么处理这个异常现象,请留言,一起分析,共同进步。
|
|