OpenEdv-开源电子网

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

SD卡连续写数据卡在SD_Error IsCardProgramming函数中

[复制链接]

1

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2019-4-13
在线时间
5 小时
发表于 2020-7-22 19:54:29 | 显示全部楼层 |阅读模式
1金钱
在SDIO+DMA模式下对SD卡连续写数据,每200ms写入一组,大概写300组数据这样子,程序就会死掉,通过打断点调试,发现程序卡在 SD_WriteBlock(u8 *buf,long long addr,  u16 blksize)函数末尾的循环:while((errorstatus==SD_OK)&&((cardstate==SD_CARD_PROGRAMMING)||(cardstate==SD_CARD_RECEIVING)))中,然后追踪 SD_Error IsCardProgramming(u8 *pstatus) 函数,发现是cardstate一直都等于SD_CARD_PROGRAMMING,求助各位大神,这是什么原因?

//SD卡写1个块
//buf:数据缓存区
//addr:写地址
//blksize:块大小          
//返回值:错误状态
SD_Error SD_WriteBlock(u8 *buf,long long addr,  u16 blksize)
{
        SD_Error errorstatus = SD_OK;
       
        u8  power=0,cardstate=0;
       
        u32 timeout=0,bytestransferred=0;
       
        u32 cardstatus=0,count=0,restwords=0;
       
        u32        tlen=blksize;                                                //总长度(字节)
       
        u32*tempbuff=(u32*)buf;                                                                 
       
        if(buf==NULL)return SD_INVALID_PARAMETER;//参数错误   

        SDIO->DCTRL=0x0;                                                        //数据控制寄存器清零(关DMA)   

        SDIO_DataInitStructure.SDIO_DataBlockSize= 0; ;//清除DPSM状态机配置
        SDIO_DataInitStructure.SDIO_DataLength= 0 ;
        SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
        SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
        SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
        SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
        SDIO_DataConfig(&SDIO_DataInitStructure);
       
       
        if(SDIO->RESP1&SD_CARD_LOCKED)return SD_LOCK_UNLOCK_FAILED;//卡锁了
        if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)        //大容量卡
        {
                blksize=512;
                addr>>=9;
        }   
        if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
        {
                power=convert_from_bytes_to_power_of_two(blksize);       

                SDIO_CmdInitStructure.SDIO_Argument = blksize;//发送CMD16+设置数据长度为blksize,短响应        
                SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
                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_SET_BLOCKLEN);        //等待R1响应
               
                if(errorstatus!=SD_OK)return errorstatus;           //响应错误         
               
        }else return SD_INVALID_PARAMETER;         

        SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;//发送CMD13,查询卡的状态,短响应        
        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
        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_SEND_STATUS);                //等待R1响应
       
        if(errorstatus!=SD_OK)return errorstatus;
        cardstatus=SDIO->RESP1;                                                                                                          
        timeout=SD_DATATIMEOUT;
           while(((cardstatus&0x00000100)==0)&&(timeout>0))         //检查READY_FOR_DATA位是否置位
        {
                timeout--;

                SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;//发送CMD13,查询卡的状态,短响应
                SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
                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_SEND_STATUS);        //等待R1响应                     
                if(errorstatus!=SD_OK)return errorstatus;                                    
                cardstatus=SDIO->RESP1;                                                                                                          
        }
        if(timeout==0)return SD_ERROR;
       
        SDIO_CmdInitStructure.SDIO_Argument = addr;//发送CMD24,写单块指令,短响应        
        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
        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_WRITE_SINGLE_BLOCK);//等待R1响应                     
        if(errorstatus!=SD_OK)return errorstatus;             
        StopCondition=0;                                                                        //单块写,不需要发送停止传输指令

        SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ;        //blksize, 控制器到卡       
        SDIO_DataInitStructure.SDIO_DataLength= blksize ;
        SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
        SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
        SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
        SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
        SDIO_DataConfig(&SDIO_DataInitStructure);
          
        timeout=SDIO_DATATIMEOUT;
        if (DeviceMode == SD_POLLING_MODE)
        {
                INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
                while(!(SDIO->STA&((1<<10)|(1<<4)|(1<<1)|(1<<3)|(1<<9))))//数据块发送成功/下溢/CRC/超时/起始位错误
                {
                        if(SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)                                                        //发送区半空,表示至少存了8个字
                        {
                                if((tlen-bytestransferred)<SD_HALFFIFOBYTES)//不够32字节了
                                {
                                        restwords=((tlen-bytestransferred)%4==0)?((tlen-bytestransferred)/4)(tlen-bytestransferred)/4+1);
                                       
                                        for(count=0;count<restwords;count++,tempbuff++,bytestransferred+=4)
                                        {
                                                SDIO_WriteData(*tempbuff);
                                        }
                                }else
                                {
                                        for(count=0;count<8;count++)
                                        {
                                                SDIO_WriteData(*(tempbuff+count));
                                        }
                                        tempbuff+=8;
                                        bytestransferred+=32;
                                }
                                timeout=0X3FFFFFFF;        //写数据溢出时间
                        }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_TXUNDERR) != RESET)         //接收fifo下溢错误
                {
                         SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);                //清错误标志
                        return SD_TX_UNDERRUN;                 
                }else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)         //接收起始位错误
                {
                         SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
                        return SD_START_BIT_ERR;                 
                }   
             
                INTX_ENABLE();//开启总中断
                SDIO->ICR=0X5FF;                         //清除所有标记          
        }else if(DeviceMode==SD_DMA_MODE)
        {
                SD_DMA_Config((u32*)buf,blksize,DMA_DIR_PeripheralDST);//SDIO DMA配置
                   TransferError=SD_OK;
                StopCondition=0;                        //单块写,不需要发送停止传输指令
                TransferEnd=0;                                //传输结束标置位,在中断服务置1
                SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<4)|(1<<9);        //配置产生数据接收完成中断
                 SDIO->DCTRL|=1<<3;                                                                //SDIO DMA使能.  
                while(((DMA2->ISR&0X2000)==RESET)&&timeout)timeout--;//等待传输完成
                if(timeout==0)
                {
                          SD_Init();                                                 //重新初始化SD卡,可以解决写入死机的问题
                        return SD_DATA_TIMEOUT;                        //超时         
                }
                timeout=SDIO_DATATIMEOUT;
                while((TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;
                if(timeout==0)return SD_DATA_TIMEOUT;                        //超时         
                  if(TransferError!=SD_OK)return TransferError;
        }  
        SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
        errorstatus=IsCardProgramming(&cardstate);
        while((errorstatus==SD_OK)&&((cardstate==SD_CARD_PROGRAMMING)||(cardstate==SD_CARD_RECEIVING)))
        {
                errorstatus=IsCardProgramming(&cardstate);
        }   
        return errorstatus;
}

//检查卡是否正在执行写操作
//pstatus:当前状态.
//返回值:错误代码
SD_Error IsCardProgramming(u8 *pstatus)
{
        vu32 respR1 = 0, status = 0;


        SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16; //卡相对地址参数
        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;//发送CMD13        
        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);       

        status=SDIO->STA;
       
        while(!(status&((1<<0)|(1<<6)|(1<<2))))status=SDIO->STA;//等待操作完成
       
        if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET)                        //CRC检测失败
        {  
                SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);        //清除错误标记
                return SD_CMD_CRC_FAIL;
        }
        if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET)                        //命令超时
        {
                SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);                        //清除错误标记
                return SD_CMD_RSP_TIMEOUT;
        }
        if(SDIO->RESPCMD!=SD_CMD_SEND_STATUS)return SD_ILLEGAL_CMD;
       
        SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
       
        respR1=SDIO->RESP1;
       
        *pstatus=(u8)((respR1>>9)&0x0000000F);    //*pstatus=0x07
        return SD_OK;
}



最佳答案

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

的确是卡的问题
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2019-4-13
在线时间
5 小时
 楼主| 发表于 2020-7-22 19:54:30 | 显示全部楼层
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2020-7-23 02:10:04 | 显示全部楼层
换个卡试试
回复

使用道具 举报

9

主题

219

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1433
金钱
1433
注册时间
2020-5-12
在线时间
394 小时
发表于 2020-7-23 15:48:18 | 显示全部楼层
我想问下dma模式需要怎么修改才能使用。我用rct6不能写入数据。
回复

使用道具 举报

1

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2019-4-13
在线时间
5 小时
 楼主| 发表于 2020-7-23 17:10:27 | 显示全部楼层
叶子君 发表于 2020-7-23 15:48
我想问下dma模式需要怎么修改才能使用。我用rct6不能写入数据。

我是参考这个帖子里的问题,DISABLE 改成ENABLE 。
怎么使用DMA来读SD卡?
http://www.openedv.com/forum.php ... 9939&fromuid=136732
(出处: OpenEdv-开源电子网)
回复

使用道具 举报

9

主题

219

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1433
金钱
1433
注册时间
2020-5-12
在线时间
394 小时
发表于 2020-7-24 08:56:18 | 显示全部楼层
lyz07 发表于 2020-7-23 17:10
我是参考这个帖子里的问题,DISABLE 改成ENABLE 。
怎么使用DMA来读SD卡?
http://www.openedv.com/for ...

谢谢,搞了好久都没查出来
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-9 01:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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