完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 zhang602054856 于 2013-11-27 14:29 编辑
ST官方的SD卡驱动函数,几乎都是根据需要判断SD卡返回的状态决定是否进行下一步操作。参考官网代码。 /************************************************************* byte : unsigned char // 8bit word :unsigned short // 16bit dword unsigned int // 32bit *************************************************************/ SD_ERROR SD_ReadSingleBlock(dword addr,byte *dataBuf,word blockSize) { SD_ERROR status=SD_OK; dword count=0,*tempBuff=(dword *)dataBuf; byte power=0; dword timeout; if(0 == dataBuf)return SD_INVALID_PARAMETER; SDIO_DCTRL=0x0; //数据控制寄存器清零(关DMA) SDIO_DataConfig(SD_DATATIMEOUT,0,0,0); //清除DPSM状态机配置 SDIO_DCTRL &= ~SDIO_DCTRL_DTEN; if(SDIO_RESP1&SD_CARD_LOCKED)return SD_LOCK_UNLOCK_FAILED; if(CardType==SDIO_HIGH_CAPACITY_SD_CARD){//大容量卡 blockSize=512; addr>>=9; // addr /= 512; } if((blockSize>0)&&(blockSize<=2048)&&((blockSize&(blockSize-1))==0)) { power=convert_from_bytes_to_power_of_two(blockSize); //发送CMD16+设置数据长度为blockSize,短响应 SDIO_SendCMD(SD_CMD_SET_BLOCKLEN,blockSize,1); status=CMDResponse1(SD_CMD_SET_BLOCKLEN); //等待R1响应 if(status!=SD_OK)return status; } else{ return SD_INVALID_PARAMETER; } SDIO_DataConfig(SD_DATATIMEOUT,blockSize,power,1); //blockSize,卡到控制器 TotalNumberOfBytes = blockSize; StopCondition = 0; //DestBuffer = dataBuf; //--------------发送CMD17-------------------// //从addr地址出读取数据,短响应 SDIO_SendCMD(SD_CMD_READ_SINGLE_BLOCK,addr,1); status=CMDResponse1(SD_CMD_READ_SINGLE_BLOCK);//等待R1响应 if(status!=SD_OK)return status; //响应错误 if(DeviceMode==SD_POLLING_MODE){//查询模式,轮询数据 //无上溢/CRC/超时/完成(标志)/起始位错误 while(!(SDIO_STA&(SDIO_STA_DCRCFAIL|SDIO_STA_DTIMEOUT| SDIO_STA_RXOVERR|SDIO_STA_STBITERR|SDIO_STA_DBCKEND))) { if(SDIO_STA&SDIO_STA_RXFIFOHF){ //接收区半满,表示至少存了8个32bit字 for(count=0;count<8;count++) //循环读取数据 { *(tempBuff+count)=SDIO_FIFO; } tempBuff+=8; } } if(SDIO_STA&SDIO_STA_DTIMEOUT){ //数据超时错误 SDIO_ICR |= SDIO_ICR_DTIMEOUTC; //清错误标志 return SD_DATA_TIMEOUT; } else if(SDIO_STA&SDIO_STA_DCRCFAIL){ //数据块CRC错误 SDIO_ICR |= SDIO_ICR_DCRCFAILC; //清错误标志 return SD_DATA_CRC_FAIL; } else if(SDIO_STA&SDIO_STA_RXOVERR){ //接收fifo上溢错误 SDIO_ICR |= SDIO_ICR_RXOVERRC; //清错误标志 return SD_RX_OVERRUN; } else if(SDIO_STA&SDIO_STA_STBITERR){ //接收起始位错误 SDIO_ICR |= SDIO_ICR_STBITERRC; //清错误标志 return SD_START_BIT_ERR; } // 读取FIFO缓冲区剩余的数据 while(SDIO_STA&SDIO_STA_RXDAVL) { *tempBuff=SDIO_FIFO; //循环读取数据 tempBuff++; } SDIO_ICR=SDIO_STATIC_FLAGS; } else if(DeviceMode==SD_DMA_MODE) { TransferError=SD_OK; StopCondition=0; //单块读,不需要发送停止传输指令 TransferEnd=0; //传输结束标置位,在中断服务置1 SDIO_MASK = SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|SDIO_MASK_RXOVERRIE| SDIO_MASK_DATAENDIE|SDIO_MASK_STBITERRIE; //配置需要的中断 SDIO_DCTRL |= SDIO_DCTRL_DMAEN; //SDIO DMA en SD_DMA2_Config(dataBuf,blockSize,0); timeout=SDIO_DATATIMEOUT; while(((DMA2_ISR&BIT13)==0)&&(TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;//等待传输完成 if(timeout==0)return SD_DATA_TIMEOUT;//超时 if(TransferError!=SD_OK)status=TransferError; } return status; } 这里的轮询模式和DMA模式的区别在于; 1. DMA模式下,FIFO缓冲区的数据会在第一时间内传送到指定的地址。这一过程是单片机自动运行,只需要配置好相应的DMA通道即可。 2. 而轮询模式下需要程序去读取FIFO缓冲区的数据。 这个数据缓冲区有几个状态标志,其中有半满,全满,有数据可用,等标志,这里只用到这三个。 其中半满的意思就是有至少8个32bit的数据。轮询模式下,可先循环读出这8个数据,然后再判断数据缓 冲区是否还有可用数据,如果有,读取剩余的数据。 /********************************************** SD卡写1个块 buf:数据缓存区 addr:写地址(SD卡地址) blksize:块大小(byte) **********************************************/ SD_ERROR SD_WriteBlock(byte *buf,dword addr,word blksize) { SD_ERROR status = SD_OK; byte power=0,cardstate=0; dword timeout=0,bytestransferred=0; dword cardstatus=0,count=0,restwords=0; dword tlen=blksize;//总长度(字节) dword*tempbuff=(dword*)buf; if(0 == buf)return SD_INVALID_PARAMETER; SDIO_DCTRL=0;//数据控制寄存器清零(关DMA) SDIO_DataConfig(SD_DATATIMEOUT,0,0,0); SDIO_DCTRL &= ~SDIO_DCTRL_DTEN; 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_SendCMD(SD_CMD_SET_BLOCKLEN,blksize,1); //发送CMD16+设置数据长度为blksize,短响应 status=CMDResponse1(SD_CMD_SET_BLOCKLEN); //等待R1响应 if(status!=SD_OK)return status; } else return SD_INVALID_PARAMETER; SDIO_SendCMD(SD_CMD_SEND_STATUS,(dword)RCA<<16,1);//发送CMD13,查询卡的状态,短响应 status=CMDResponse1(SD_CMD_SEND_STATUS);//等待R1响应 if(status!=SD_OK)return status; cardstatus=SDIO_RESP1; timeout=SD_DATATIMEOUT; while(((cardstatus&SD_STAT_READY_FOR_DATA)==0)&&(timeout>0))//检查READY_FOR_DATA位是否置位 { timeout--; SDIO_SendCMD(SD_CMD_SEND_STATUS,(dword)RCA<<16,1);//发送CMD13,查询卡的状态,短响应 status=CMDResponse1(SD_CMD_SEND_STATUS);//等待R1响应 if(status!=SD_OK)return status; cardstatus=SDIO_RESP1; } if(timeout==0)return SD_DATA_TIMEOUT; SDIO_SendCMD(SD_CMD_WRITE_SINGLE_BLOCK,addr,1);//发送CMD24,写单块指令,短响应 status=CMDResponse1(SD_CMD_WRITE_SINGLE_BLOCK);//等待R1响应 if(status!=SD_OK)return status; StopCondition=0;//单块写,不需要发送停止传输指令 SDIO_DataConfig(SD_DATATIMEOUT,blksize,power,0);//blksize, 控制器到卡 if(DeviceMode == SD_POLLING_MODE){ while(!(SDIO_STA&(SDIO_STA_DCRCFAIL|SDIO_STA_DTIMEOUT|SDIO_STA_TXUNDERR| SDIO_STA_STBITERR|SDIO_STA_DBCKEND)))//数据块发送成功/下溢/CRC/超时/起始位错误 { if(SDIO_STA&SDIO_STA_TXFIFOHE)//发送区半空,表示至少存了8个32bit字 { if((tlen-bytestransferred) { restwords=((tlen-bytestransferred)%4==0)?((tlen-bytestransferred)/4):((tlen-bytestransferred)/4+1); for(count=0;count { SDIO_FIFO=*tempbuff; } }else{ for(count=0;count<8;count++) { SDIO_FIFO=*(tempbuff+count); } tempbuff+=8; bytestransferred+=32; } } } if(SDIO_STA&SDIO_STA_DTIMEOUT){ //数据超时错误 SDIO_ICR |= SDIO_ICR_DTIMEOUTC; //清错误标志 return SD_DATA_TIMEOUT; } else if(SDIO_STA&SDIO_STA_DCRCFAIL){ //数据块CRC错误 SDIO_ICR |= SDIO_ICR_DCRCFAILC; //清错误标志 return SD_DATA_CRC_FAIL; } else if(SDIO_STA&SDIO_STA_TXUNDERR){ //接收fifo上溢错误 SDIO_ICR |= SDIO_ICR_TXUNDERRC; //清错误标志 return SD_TX_UNDERRUN; } else if(SDIO_STA&SDIO_STA_STBITERR){ //接收起始位错误 SDIO_ICR |= SDIO_ICR_STBITERRC; //清错误标志 return SD_START_BIT_ERR; } SDIO_ICR=SDIO_STATIC_FLAGS; //清除所有标记 } else if(DeviceMode==SD_DMA_MODE) { TransferError=SD_OK; StopCondition=0; //单块写,不需要发送停止传输指令 TransferEnd=0; //传输结束标置位,在中断服务置1 SDIO_MASK=SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|SDIO_MASK_TXUNDERRIE| SDIO_MASK_DATAENDIE|SDIO_MASK_STBITERRIE; SD_DMA2_Config((dword*)buf,blksize,1);//SDIO DMA配置 SDIO_DCTRL |= SDIO_DCTRL_DMAEN;//SDIO DMA使能 timeout=SDIO_DATATIMEOUT; while(((DMA2_ISR&BIT13)== 0 )&&timeout)timeout--;//等待传输完成 if(timeout==0){ Init_SDCard();//重新初始化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_ICR=SDIO_STATIC_FLAGS;//清除所有标记 status=GetSDCardMode(&cardstate); while((status==SD_OK)&&((cardstate==SD_CARD_PROGRAMMING)||(cardstate==SD_CARD_RECEIVING))) { status=GetSDCardMode(&cardstate); } return status; } |
|
相关推荐
12 个讨论
|
|
附件是源码驱动,测试通过,板子是发烧友论坛做活动的
|
|
|
|
|
|
轮询模式和DMA模式都测试过了,有问题的下面留言,看能不能帮助解决
|
|
|
|
|
|
厉害,佩服你
|
|
|
|
|
|
希望更好的例子出台啊
|
|
|
|
|
|
#在这里快速回复#单片机学习技术资料集合
|
|
|
|
|
|
#在这里快速回复#很好啊!技术支持,谢谢分享,学习了!
|
|
|
|
|
|
haogooggggooooooooooooooooooood
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-4 01:45 , Processed in 0.769231 second(s), Total 65, Slave 55 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号