关于SDIO POLLING模式驱动:SD_WriteMultiBlocks函数写入时间长

2019-07-20 15:34发布

问题发现:写入1024Bytes,f_write(file, Sd_write_buf, 1024, &_cnt);
               测试发现要花费4~5ms的时间。我修改了SD_WriteMultiBlocks函数,把write_ms_delta打印出来看发现的。
               那部分代码应该是等待TF卡反馈写入完成。
问题:有没有办法把这部分时间给省略掉呢?假如频繁写入的话(1秒钟100次),那么系统基本就没办法做其它事情了。

//SD卡写多个块
//buf:数据缓存区
//addr:写地址
//blksize:块大小
//nblks:要写入的块数
//返回值:错误状态                                                                                                  
SD_Error SD_WriteMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks)
{
        SD_Error errorstatus = SD_OK;
        u8  power = 0, cardstate = 0;
        u32 timeout=0,bytestransferred=0;
        u32 count = 0, restwords = 0;
        u32 tlen=nblks*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;         
        if(nblks>1)
        {                                          
                if(nblks*blksize>SD_MAX_DATA_LENGTH)return SD_INVALID_PARAMETER;   
             if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
            {
                        //提高性能
                                SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;                //发送ACMD55,短响应        
                                SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
                                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);                //等待R1响应
                               
                        if(errorstatus!=SD_OK)return errorstatus;                                 
                               
                                SDIO_CmdInitStructure.SDIO_Argument =nblks;                //发送CMD23,设置块数量,短响应          
                                SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCK_COUNT;
                                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_BLOCK_COUNT);//等待R1响应
                               
                        if(errorstatus!=SD_OK)return errorstatus;               
                    
                }

                                SDIO_CmdInitStructure.SDIO_Argument =addr;        //发送CMD25,多块写指令,短响应           
                                SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_MULT_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_MULT_BLOCK);        //等待R1响应                     
       
                if(errorstatus!=SD_OK)return errorstatus;

        SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ;        //blksize, 控制器到卡       
                                SDIO_DataInitStructure.SDIO_DataLength= nblks*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);
                               
                if(DeviceMode==SD_POLLING_MODE)
            {
                        timeout=SDIO_DATATIMEOUT;
                        INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
                        while(!(SDIO->STA&((1<<4)|(1<<1)|(1<<8)|(1<<3)|(1<<9))))//下溢/CRC/数据结束/超时/起始位错误
                        {
                                if(SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)                                                        //发送区半空,表示至少存了8字(32字节)
                                {          
                                        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->FIFO=*tempbuff;
                                                }
                                        }else                                                                                 //发送区半空,可以发送至少8字(32字节)数据
                                        {
                                                for(count=0;count<SD_HALFFIFO;count++)
                                                {
                                                        SDIO->FIFO=*(tempbuff+count);
                                                }
                                                tempbuff+=SD_HALFFIFO;
                                                bytestransferred+=SD_HALFFIFOBYTES;
                                        }
                                        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;                 
                }   
                                                                                                
                        if(SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET)                //发送结束
                        {                                                                                                                         
                                if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
                                {   
                                        SDIO_CmdInitStructure.SDIO_Argument =0;//发送CMD12+结束传输           
                                        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_STOP_TRANSMISSION;
                                        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_STOP_TRANSMISSION);//等待R1响应   
                                        if(errorstatus!=SD_OK)return errorstatus;         
                                }
                        }
                        INTX_ENABLE();//开启总中断
                         SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
            }else if(DeviceMode==SD_DMA_MODE)
                {
                   TransferError=SD_OK;
                        StopCondition=1;                        //多块写,需要发送停止传输指令
                        TransferEnd=0;                                //传输结束标置位,在中断服务置1
                        SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<4)|(1<<9);        //配置产生数据接收完成中断
                        SD_DMA_Config((u32*)buf,nblks*blksize,DMA_DIR_MemoryToPeripheral);                //SDIO DMA配置
                          SDIO->DCTRL|=1<<3;                                                                //SDIO DMA使能.
                        timeout=SDIO_DATATIMEOUT;
                         while(((DMA2->LISR&(1<<27))==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);
        write_ms_start = GetSysTime_ms();// 开始时间
        while((errorstatus==SD_OK)&&((cardstate==SD_CARD_PROGRAMMING)||(cardstate==SD_CARD_RECEIVING)))
        {
                errorstatus=IsCardProgramming(&cardstate);
        }   
        write_ms_end = GetSysTime_ms();// 结束时间
        write_ms_delta = write_ms_end - write_ms_start;// 时间差
        return errorstatus;          
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
正点原子
1楼-- · 2019-07-20 18:05
用操作系统,写卡的时候就写卡,不写的时候,就干其他事情。办法总比问题多。
岁月已无声
2楼-- · 2019-07-20 22:11
 精彩回答 2  元偷偷看……
岁月已无声
3楼-- · 2019-07-21 03:14
顶一个,谁有好的方法分享吗

一周热门 更多>