OpenEdv-开源电子网

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

使用原子哥的SDIO SD卡程序,发现上电的时候长时间进入了死循环

[复制链接]

28

主题

150

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
488
金钱
488
注册时间
2016-9-29
在线时间
113 小时
发表于 2018-1-9 14:26:29 | 显示全部楼层 |阅读模式
3金钱
本帖最后由 ZDawn 于 2018-1-9 14:31 编辑

    用别的板子烧了原子哥的SDIO程序之后,在 “查找SD卡的SCR寄存器值” 的函数子函数里面会死循环,FIFO无接收数据,导致SDIO->STA值一直为零。但是这种情况仅限于普通的上电。
    我用keil 和JLINK在线调试的话第一次也会进入死循环,但是用keil 调试的复位按钮之后,再重新执行就能正常运行,不再进入那个死循环。
    正常上电的话偶尔等1分钟也能读到FIFO的值从而跳出死循环。
    请问这会是什么原因导致每次的第一次上电时候,SDIO->STA值一直为零??(查询模式和DMA模式都是一样的结果)


    以下是程序:


//查找SD卡的SCR寄存器值
//rca:卡相对地址
//pscr:数据缓存区(存储SCR内容)
//返回值:错误状态                  
SD_Error FindSCR(u16 rca,u32 *pscr)
{
         u8 ii=50;
        
        u32 index = 0;
        SD_Error errorstatus = SD_OK;
        u32 tempscr[2]={0,0};  
         
        
        SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)8;         //发送CMD16,短响应,设置Block Size为8字节        
        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN; //         cmd16
        SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r1
        SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
        SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
        SDIO_SendCommand(&SDIO_CmdInitStructure);
        delay_ms(1);
        errorstatus=CmdResp1Error(SD_CMD_SET_BLOCKLEN);

        if(errorstatus!=SD_OK)return errorstatus;            

        SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;//发送CMD55,短响应         
        SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
        SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
        SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
        SDIO_SendCommand(&SDIO_CmdInitStructure);
        
         errorstatus=CmdResp1Error(SD_CMD_APP_CMD);
        
         if(errorstatus!=SD_OK)return errorstatus;

        SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
        SDIO_DataInitStructure.SDIO_DataLength = 8;  //8个字节长度,block为8字节,SD卡到SDIO.
        SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_8b  ;  //块大小8byte
        SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
        SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
        SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
        SDIO_DataConfig(&SDIO_DataInitStructure);               
        
//        delay_ms(1);
        
        SDIO_CmdInitStructure.SDIO_Argument = 0x0;
        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_SEND_SCR;        //发送ACMD51,短响应,参数为0        
        SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r1
        SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
        SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
        SDIO_SendCommand(&SDIO_CmdInitStructure);
//        delay_ms(1);
        
         errorstatus=CmdResp1Error(SD_CMD_SD_APP_SEND_SCR);
        
         if(errorstatus!=SD_OK)return errorstatus;
        
//        delay_ms(1);
        
       //进入死循环的段落,if 语句一直不通过判定
         while(!(SDIO->STA&(SDIO_FLAG_RXOVERR|SDIO_FLAG_DCRCFAIL|SDIO_FLAG_DTIMEOUT|SDIO_FLAG_DBCKEND|SDIO_FLAG_STBITERR)))
        {
                if(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)//接收FIFO数据可用
                {
                        *(tempscr+index)=SDIO_ReadData();        //读取FIFO内容
                        index++;
                        if(index>=2)break;
                }
        
        }
        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;                 
                }  
        SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
        //把数据顺序按8位为单位倒过来.           
        *(pscr+1)=((tempscr[0]&SD_0TO7BITS)<<24)|((tempscr[0]&SD_8TO15BITS)<<8)|((tempscr[0]&SD_16TO23BITS)>>8)|((tempscr[0]&SD_24TO31BITS)>>24);
        *(pscr)=((tempscr[1]&SD_0TO7BITS)<<24)|((tempscr[1]&SD_8TO15BITS)<<8)|((tempscr[1]&SD_16TO23BITS)>>8)|((tempscr[1]&SD_24TO31BITS)>>24);
         return errorstatus;
}

调试时候我用的复位按钮

调试时候我用的复位按钮

最佳答案

查看完整内容[请看2#楼]

你是用的我们开发板么?直接下载我们例程,不要做任何修改,测试看看?试试寄存器版本?
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

28

主题

150

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
488
金钱
488
注册时间
2016-9-29
在线时间
113 小时
 楼主| 发表于 2018-1-10 10:14:53 | 显示全部楼层
正点原子 发表于 2018-1-10 00:24
你是用的我们开发板么?直接下载我们例程,不要做任何修改,测试看看?试试寄存器版本?

我在板子上电3秒之后再去初始化SD卡结果就可以了,可能是我这张SD卡需要一定的电压稳定时间,或者是板子电路问题
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2018-1-9 14:26:30 | 显示全部楼层
你是用的我们开发板么?直接下载我们例程,不要做任何修改,测试看看?试试寄存器版本?
回复

使用道具 举报

28

主题

150

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
488
金钱
488
注册时间
2016-9-29
在线时间
113 小时
 楼主| 发表于 2018-1-9 14:30:39 | 显示全部楼层
板子我试过硬件复位的方法,也不能使程序正常。一定要用KEIL 在线调试的那个复位按钮来复位程序才正常。。。
回复

使用道具 举报

28

主题

150

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
488
金钱
488
注册时间
2016-9-29
在线时间
113 小时
 楼主| 发表于 2018-1-9 14:41:00 | 显示全部楼层
我在没有插SD卡的情况下用这条语“while(SD_Init());”去运行,程序不停地执行初始化,中途再插入SD卡的话也会卡死在上面程序的死循环中。
回复

使用道具 举报

28

主题

150

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
488
金钱
488
注册时间
2016-9-29
在线时间
113 小时
 楼主| 发表于 2018-1-9 14:43:04 | 显示全部楼层
用的16G  SD卡
回复

使用道具 举报

8

主题

62

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
233
金钱
233
注册时间
2017-12-4
在线时间
86 小时
发表于 2018-12-26 18:45:20 | 显示全部楼层
和你的情况完全一样,我也是16gb卡,卡在FindSCR那个循环。。。我现在又发现如果断开调试让程序单独运行是可以成功初始化的,请问楼主这个问题解决没有?
回复

使用道具 举报

8

主题

62

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
233
金钱
233
注册时间
2017-12-4
在线时间
86 小时
发表于 2018-12-26 18:51:21 | 显示全部楼层
我这边所有sdhc卡都需要软复位,而sdsc卡就直接可以初始化
回复

使用道具 举报

28

主题

150

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
488
金钱
488
注册时间
2016-9-29
在线时间
113 小时
 楼主| 发表于 2018-12-26 19:19:08 | 显示全部楼层
fEndman 发表于 2018-12-26 18:51
我这边所有sdhc卡都需要软复位,而sdsc卡就直接可以初始化

你说的软复位是指单片机软复位?
回复

使用道具 举报

8

主题

62

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
233
金钱
233
注册时间
2017-12-4
在线时间
86 小时
发表于 2018-12-26 19:37:45 | 显示全部楼层
ZDawn 发表于 2018-12-26 19:19
你说的软复位是指单片机软复位?

keil那个复位
回复

使用道具 举报

8

主题

62

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
233
金钱
233
注册时间
2017-12-4
在线时间
86 小时
发表于 2018-12-26 19:51:50 | 显示全部楼层
我这边发现了一个解决方案,首先,我是在stm32的sram里做的调试,而sram调试复位有个bug,就是每次复位后单片机PLL倍频系数会非常奇怪,导致单片机速度奇慢。我发现这点做了一个实验:在sd初始化函数sd卡上电前添加RCC_HCLKConfig(RCC_SYSCLK_Div4);函数以降低单片机速度(RCC_SYSCLK_Div4是实验出来的,2分频就又太快了),在设置好4位总线宽度后再添加RCC_HCLKConfig(RCC_SYSCLK_Div1);函数来恢复之前的正常运行速度。成功初始化,而且速度也比较可观。我曾经用spi操作sd也会经常因为速度太快而出现初始化问题。这个问题初步判断为初始化过程中线路干扰所致,所以降低速度可行。(我也不知道为什么降低sdio分频不起作用。。。当时我用spi操作sd卡也是,spi时钟的分频不起作用,只能降低总线时钟。。。。。。)
回复

使用道具 举报

4

主题

59

帖子

0

精华

高级会员

Rank: 4

积分
745
金钱
745
注册时间
2018-12-27
在线时间
82 小时
发表于 2018-12-27 08:55:07 | 显示全部楼层
还没看到这块提前帮顶
回复

使用道具 举报

28

主题

150

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
488
金钱
488
注册时间
2016-9-29
在线时间
113 小时
 楼主| 发表于 2018-12-27 18:21:43 | 显示全部楼层
fEndman 发表于 2018-12-26 19:51
我这边发现了一个解决方案,首先,我是在stm32的sram里做的调试,而sram调试复位有个bug,就是每次复位后单 ...

有一些我是这么解决的,在需要初始化TF卡的时候降低主频,初始化完毕后再次拉高主频。

然后我也用过别的可行的方法,就是不降低主频的情况下,由于有时候热插拔TF卡,会造成TF卡初始化失败并且卡死在某些循环代码里面,所以我找到所有会卡死的位置,添加“卡死次数判断”,要是连续循环执行n次失败的话,就认为是“TF卡初始化卡死了”,然后直接退出初始化函数,等程序下次再执行TF卡初始化的时候就成功了。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-23 03:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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