基于STM32采用CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试(中篇)

3.2 spi硬件时序方式
上面的3.1小节是采用spi模拟时序驱动sd nand,stm32本身集成有spi硬件模块,可以直接利用stm32硬件spi接口读写。
下面贴出底层的适配代码。 上面贴出的驱动代码里,已经将驱动接口部分和协议逻辑部分区分开了,替换底层的sip读写代码非常方便。
(1)主要替换的代码/*
函数功能:spi初始化(模拟spi)
硬件连接:
miso--->pb14
mosi--->pb15
sclk--->pb13
*/
void spi_init(void)
{
/*开启时钟*/
rcc->apb1enr|=1gpiob->odr|=0x7cr1|=0    cnt=0;
    while((spi2->sr&1dr;          //返回收到的数据
}
函数功能:sd卡底层接口,通过spi时序向sd卡读写一个字节
函数参数:data是要写入的数据
返 回 值:读到的数据
*/
u8 sdcardreadwriteonebyte(u8 datatx)
{  
    return spi_readwriteonebyte(datatx);
}
(2)运行效果3.3 sdio方式
如果想提高sd nand的读写速度,可以采用sdio协议,stm32本身有sdio的硬件支持,配置好sdio的寄存器即可完成sd nand的操作。 sdio的数据线都比spi多,读写速度自然没法比的。
下面贴出stm32f103ze上面编写的sdio协议读写sd nand的驱动代码。
(1)整体工程代码
(2)sdio.c#include sdio_sdcard.h
#include string.h  
#include sys.h  
#include usart.h
static u8 cardtype=sdio_std_capacity_sd_card_v1_1; //sd卡类型(默认为1.x卡)
static u32 csd_tab[4],cid_tab[4],rca=0;       //sd卡csd,cid以及相对地址(rca)数据
static u8 devicemode=sd_dma_mode;             //工作模式,注意,工作模式必须通过sdio_sdcardsetdevicemode,后才算数.这里只是定义一个默认的模式(sd_dma_mode)
static u8 stopcondition=0;             //是否发送停止传输标志位,dma多块读写的时候用到  
volatile sdio_sd_error_info transfererror=sd_ok;   //数据传输错误标志,dma读写时使用     
volatile u8 transferend=0;             //传输结束标志,dma读写时使用
sd_cardinfo sdcardinfo;               //sd卡信息
//sdio_sdcardreaddisksector/sdio_sdcardwritedisksector函数专用buf,当这两个函数的数据缓存区地址不是4字节对齐的时候,
//需要用到该数组,确保数据缓存区地址是4字节对齐的.
__align(4) u8 sdio_data_buffer[512];
/*
sd卡与开发板的sdio方式接线关系如下:
data0---pc8
data1---pc9
data2---pc10
data3---pc11
clk-----pc1
cmd-----pd2
*/
/*
函数功能:sdio方式初始化sd卡 
返回值  :错误代码;(0,无错误)
*/
sdio_sd_error_info sdio_sdcardinit(void)
{
u8 clkdiv=0;
sdio_sd_error_info errorstatus=sd_ok;    
//sdio io口初始化
rcc->apb2enr|=1gpiod->crl&=0xfffff0ff; 
gpiod->crl|=0x00000b00; //pd2复用输出,pd7 上拉输入
//sdio外设寄存器设置为默认值    
sdio->power=0x00000000;
sdio->clkcr=0x00000000;
sdio->arg=0x00000000;
sdio->cmd=0x00000000;
sdio->dtimer=0x00000000;
sdio->dlen=0x00000000;
sdio->dctrl=0x00000000;
sdio->icr=0x00c007ff;
sdio->mask=0x00000000;   
  stm32_nvic_setpriority(sdio_irqn,0,0); //sdio中断配置
  errorstatus=sdio_sdpoweron();             //sd卡上电
  sdio_sdcardinitializecards();         //初始化sd卡   
  sdio_sdcardgetinfo(&sdcardinfo);             //获取卡信息
  sdio_sdcardselectaddr((u32)(sdcardinfo.rcaclkcr=tmpreg;
}
/*
函数功能: sdio发送命令函数
函数参数:
         cmdindex:命令索引,低六位有效
         waitrsp:期待的相应.00/10,无响应;01,短响应;11,长响应
         arg:参数
*/
void sdio_sendcmd(u8 cmdindex,u8 waitrsp,u32 arg)
{
u32 tmpreg;
sdio->arg=arg;
tmpreg=sdio->cmd; 
tmpreg&=0xfffff800; //清除index和waitrsp
tmpreg|=cmdindex&0x3f; //设置新的index  
tmpreg|=waitrsp<<6; //设置新的wait rsp 
tmpreg|=0<<8; //无等待
  tmpreg|=1dtimer=datatimeout;
  sdio->dlen=datalen&0x1ffffff; //低25位有效
tmpreg=sdio->dctrl; 
tmpreg&=0xffffff08; //清除之前的设置.
tmpreg|=blksize<<4; //设置块大小
tmpreg|=0<<2; //块数据传输
tmpreg|=(dir&0x01)<<1; //方向控制
tmpreg|=1clkcr=0; //清空clkcr之前的设置
sdio->clkcr|=031)==1)?1:0);   //判断sd卡上电是否完成
count++;
}
if(count>=sd_max_volt_trial)
{
errorstatus=sd_invalid_voltrange;
return errorstatus;
}  
if(response&=sd_high_capacity)
{
cardtype=sdio_high_capacity_sd_card;
}
  }
  return(errorstatus);
}
/*
函数功能: sd卡断电
返回值:错误代码;(0,无错误)
*/
sdio_sd_error_info sd_poweroff(void)
{
  sdio->power&=~(3resp1;
cid_tab[1]=sdio->resp2;
cid_tab[2]=sdio->resp3;
cid_tab[3]=sdio->resp4;
}
if((sdio_std_capacity_sd_card_v1_1==cardtype)||(sdio_std_capacity_sd_card_v2_0==cardtype)||(sdio_secure_digital_io_combo_card==cardtype)||(sdio_high_capacity_sd_card==cardtype))//判断卡类型
{
sdio_sendcmd(sd_cmd_set_rel_addr,1,0); //发送cmd3,短响应 
errorstatus=sdio_cmdresp6error(sd_cmd_set_rel_addr,&rca);//等待r6响应 
if(errorstatus!=sd_ok)return errorstatus;    //响应错误     
}   
  if(sdio_multimedia_card==cardtype)
  {
    sdio_sendcmd(sd_cmd_set_rel_addr,1,(u32)(rca<<16));//发送cmd3,短响应    
    errorstatus=sdio_cmdresp2error(); //等待r2响应   
    if(errorstatus!=sd_ok)return errorstatus;    //响应错误  
  }
if(sdio_secure_digital_io_card!=cardtype) //非secure_digital_io_card
{
rca = rca;
sdio_sendcmd(sd_cmd_send_csd,3,(u32)(rcaresp2;
csd_tab[2]=sdio->resp3;
csd_tab[3]=sdio->resp4;     
}
return sd_ok;//卡初始化成功
}
/*
函数功能:得到卡信息
函数参数:
        cardinfo:卡信息存储区
返回值:错误状态
*/
sdio_sd_error_info sdio_sdcardgetinfo(sd_cardinfo *cardinfo)
{
  sdio_sd_error_info errorstatus=sd_ok;
u8 tmp=0;    
cardinfo->cardtype=(u8)cardtype; //卡类型
cardinfo->rca=(u16)rca;     //卡rca值
tmp=(u8)((csd_tab[0]&0xff000000)>>24);
cardinfo->sd_csd.csdstruct=(tmp&0xc0)>>6; //csd结构
cardinfo->sd_csd.sysspecversion=(tmp&0x3c)>>2; //2.0协议还没定义这部分(为保留),应该是后续协议定义的
cardinfo->sd_csd.reserved1=tmp&0x03; //2个保留位  
tmp=(u8)((csd_tab[0]&0x00ff0000)>>16); //第1个字节
cardinfo->sd_csd.taac=tmp;     //数据读时间1
tmp=(u8)((csd_tab[0]&0x0000ff00)>>8);   //第2个字节
cardinfo->sd_csd.nsac=tmp;   //数据读时间2
tmp=(u8)(csd_tab[0]&0x000000ff); //第3个字节
cardinfo->sd_csd.maxbusclkfrec=tmp;   //传输速度    
tmp=(u8)((csd_tab[1]&0xff000000)>>24); //第4个字节
cardinfo->sd_csd.cardcomdclasses=tmp16); //第5个字节
cardinfo->sd_csd.cardcomdclasses|=(tmp&0xf0)>>4;//卡指令类低四位
cardinfo->sd_csd.rdblocklen=tmp&0x0f;     //最大读取数据长度
tmp=(u8)((csd_tab[1]&0x0000ff00)>>8); //第6个字节
cardinfo->sd_csd.partblockread=(tmp&0x80)>>7; //允许分块读
cardinfo->sd_csd.wrblockmisalign=(tmp&0x40)>>6; //写块错位
cardinfo->sd_csd.rdblockmisalign=(tmp&0x20)>>5; //读块错位
cardinfo->sd_csd.dsrimpl=(tmp&0x10)>>4;
cardinfo->sd_csd.reserved2=0; //保留
  if((cardtype==sdio_std_capacity_sd_card_v1_1)||(cardtype==sdio_std_capacity_sd_card_v2_0)||(sdio_multimedia_card==cardtype))//标准1.1/2.0卡/mmc卡
{
cardinfo->sd_csd.devicesize=(tmp&0x03)cardinfo->sd_csd.devicesize|=(tmp&0xc0)>>6;
  cardinfo->sd_csd.maxrdcurrentvddmin=(tmp&0x38)>>3;
cardinfo->sd_csd.maxrdcurrentvddmax=(tmp&0x07);
  tmp=(u8)((csd_tab[2]&0x00ff0000)>>16); //第9个字节
cardinfo->sd_csd.maxwrcurrentvddmin=(tmp&0xe0)>>5;
cardinfo->sd_csd.maxwrcurrentvddmax=(tmp&0x1c)>>2;
cardinfo->sd_csd.devicesizemul=(tmp&0x03)8);   //第10个字节
cardinfo->sd_csd.devicesizemul|=(tmp&0x80)>>7;
  cardinfo->cardcapacity=(cardinfo->sd_csd.devicesize+1);//计算卡容量
cardinfo->cardcapacity*=(1cardblocksize=1cardcapacity*=cardinfo->cardblocksize;
}else if(cardtype==sdio_high_capacity_sd_card) //高容量卡
{
  tmp=(u8)(csd_tab[1]&0x000000ff); //第7个字节
cardinfo->sd_csd.devicesize=(tmp&0x3f)24); //第8个字节
  cardinfo->sd_csd.devicesize|=(tmp16); //第9个字节
  cardinfo->sd_csd.devicesize|=(tmp);
  tmp=(u8)((csd_tab[2]&0x0000ff00)>>8); //第10个字节
  cardinfo->cardcapacity=(long long)(cardinfo->sd_csd.devicesize+1)*512*1024;//计算卡容量
cardinfo->cardblocksize=512; //块大小固定为512字节
}   
cardinfo->sd_csd.erasegrsize=(tmp&0x40)>>6;
cardinfo->sd_csd.erasegrmul=(tmp&0x3f)>7;
cardinfo->sd_csd.wrprotectgrsize=(tmp&0x7f);
  tmp=(u8)((csd_tab[3]&0xff000000)>>24); //第12个字节
cardinfo->sd_csd.wrprotectgrenable=(tmp&0x80)>>7;
cardinfo->sd_csd.mandeflecc=(tmp&0x60)>>5;
cardinfo->sd_csd.wrspeedfact=(tmp&0x1c)>>2;
cardinfo->sd_csd.maxwrblocklen=(tmp&0x03)16); //第13个字节
cardinfo->sd_csd.maxwrblocklen|=(tmp&0xc0)>>6;
cardinfo->sd_csd.writeblockpapartial=(tmp&0x20)>>5;
cardinfo->sd_csd.reserved3=0;
cardinfo->sd_csd.contentprotectappli=(tmp&0x01);  
tmp=(u8)((csd_tab[3]&0x0000ff00)>>8); //第14个字节
cardinfo->sd_csd.fileformatgrouop=(tmp&0x80)>>7;
cardinfo->sd_csd.copyflag=(tmp&0x40)>>6;
cardinfo->sd_csd.permwrprotect=(tmp&0x20)>>5;
cardinfo->sd_csd.tempwrprotect=(tmp&0x10)>>4;
cardinfo->sd_csd.fileformat=(tmp&0x0c)>>2;
cardinfo->sd_csd.ecc=(tmp&0x03);  
tmp=(u8)(csd_tab[3]&0x000000ff); //第15个字节
cardinfo->sd_csd.csd_crc=(tmp&0xfe)>>1;
cardinfo->sd_csd.reserved4=1;  
tmp=(u8)((cid_tab[0]&0xff000000)>>24); //第0个字节
cardinfo->sd_cid.manufacturerid=tmp;     
tmp=(u8)((cid_tab[0]&0x00ff0000)>>16); //第1个字节
cardinfo->sd_cid.oem_appliid=tmp8); //第2个字节
cardinfo->sd_cid.oem_appliid|=tmp;     
tmp=(u8)(cid_tab[0]&0x000000ff); //第3个字节
cardinfo->sd_cid.prodname1=tmp24); //第4个字节
cardinfo->sd_cid.prodname1|=tmp16);     //第5个字节
cardinfo->sd_cid.prodname1|=tmp8); //第6个字节
cardinfo->sd_cid.prodname1|=tmp;    
tmp=(u8)(cid_tab[1]&0x000000ff);   //第7个字节
cardinfo->sd_cid.prodname2=tmp;   
tmp=(u8)((cid_tab[2]&0xff000000)>>24); //第8个字节
cardinfo->sd_cid.prodrev=tmp;  
tmp=(u8)((cid_tab[2]&0x00ff0000)>>16); //第9个字节
cardinfo->sd_cid.prodsn=tmp8); //第10个字节
cardinfo->sd_cid.prodsn|=tmpcardinfo->sd_cid.prodsn|=tmp;      
tmp=(u8)((cid_tab[3]&0x00ff0000)>>16); //第13个字节
cardinfo->sd_cid.reserved1|=(tmp&0xf0)>>4;
cardinfo->sd_cid.manufactdate=(tmp&0x0f)8); //第14个字节
cardinfo->sd_cid.manufactdate|=tmp;   
tmp=(u8)(cid_tab[3]&0x000000ff); //第15个字节
cardinfo->sd_cid.cid_crc=(tmp&0xfe)>>1;
cardinfo->sd_cid.reserved2=1;  
return errorstatus;
}
/*
函数功能: 设置sdio总线宽度
函数参数:
        wmode:位宽模式.0,1位数据宽度;1,4位数据宽度;2,8位数据宽度
返回值:sd卡错误状态
*/
sdio_sd_error_info sdio_sdcardenablewidebusoperation(u32 wmode)
{
    sdio_sd_error_info errorstatus=sd_ok;
    if((sdio_std_capacity_sd_card_v1_1==cardtype)||(sdio_std_capacity_sd_card_v2_0==cardtype)||(sdio_high_capacity_sd_card==cardtype))
    {
      if(wmode>=2)return sd_unsupported_feature;//不支持8位模式
      else   
      {
        errorstatus=sdio_sdcardenwidebus(wmode);
        if(sd_ok==errorstatus)
        {
          sdio->clkcr&=~(3=9;
    }   
    sdio_senddataconfig(sd_datatimeout,0,0,0); //清除dpsm状态机配置
    if(sdio->resp1&sd_card_locked)return sd_lock_unlock_failed;//卡锁了
    if((blksize>0)&&(blksizesta&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1    }else if(devicemode==sd_dma_mode)
    {
      sdio_sdcard_dmaconfig((u32*)buf,blksize,0); 
      transfererror=sd_ok;
      stopcondition=0; //单块读,不需要发送停止传输指令
      transferend=0; //传输结束标置位,在中断服务置1
      sdio->mask|=(1<<1)|(1<<3)|(1<<8)|(1<<5)|(1if(cardtype==sdio_high_capacity_sd_card)//大容量卡
{
blksize=512;
addr>>=9;
}  
  sdio_senddataconfig(sd_datatimeout,0,0,0); //清除dpsm状态机配置
if(sdio->resp1&sd_card_locked)return sd_lock_unlock_failed;//卡锁了
if((blksize>0)&&(blksize1) //多块读  
{     
    if(nblks*blksize>sd_max_data_length)return sd_invalid_parameter;//判断是否超过最大接收长度
sdio_senddataconfig(sd_datatimeout,nblks*blksize,power,1);//nblks*blksize,512块大小,卡到控制器   
  sdio_sendcmd(sd_cmd_read_mult_block,1,addr); //发送cmd18+从addr地址出读取数据,短响应    
errorstatus=sdio_cmdresp1error(sd_cmd_read_mult_block);//等待r1响应   
if(errorstatus!=sd_ok)return errorstatus;    //响应错误   
  if(devicemode==sd_polling_mode)
{
// intx_disable();//关闭总中断(polling模式,严禁中断打断sdio读写操作!!!)
while(!(sdio->sta&((1<<5)|(1<<1)|(1<<3)|(1<<8)|(1  sdio_senddataconfig(sd_datatimeout,0,0,0); //清除dpsm状态机配置
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,1,blksize); //发送cmd16+设置数据长度为blksize,短响应    
errorstatus=sdio_cmdresp1error(sd_cmd_set_blocklen); //等待r1响应   
if(errorstatus!=sd_ok)return errorstatus;    //响应错误  
}else return sd_invalid_parameter;  
  sdio_sendcmd(sd_cmd_send_status,1,(u32)rca0)) //检查ready_for_data位是否置位
{
timeout--;
    sdio_sendcmd(sd_cmd_send_status,1,(u32)rcasta&((1<<10)|(1<<4)|(1<<1)|(1<<3)|(1  errorstatus=sdio_sdcardprogrammingstate(&cardstate);
  while((errorstatus==sd_ok)&&((cardstate==sd_card_programming)||(cardstate==sd_card_receiving)))
{
errorstatus=sdio_sdcardprogrammingstate(&cardstate);
}   
return errorstatus;
}
/*
函数功能:sd卡写多个块 
函数参数:
        buf:数据缓存区
        addr:写地址
        blksize:块大小
        nblks:要写入的块数
返回值:错误状态
*/    
sdio_sd_error_info sdio_sdcardwritemultiblocks(u8 *buf,long long addr,u16 blksize,u32 nblks)
{
sdio_sd_error_info 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_senddataconfig(sd_datatimeout,0,0,0); //清除dpsm状态机配置
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)&&(blksize1)
{   
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_sendcmd(sd_cmd_app_cmd,1,(u32)rca}
tempbuff+=sd_halffifo;
bytestransferred+=sd_halffifobytes;
}
timeout=0x3fffffff; //写数据溢出时间
}else
{
if(timeout==0)return sd_data_timeout; 
timeout--;
}

if(sdio->sta&(1  errorstatus=sdio_sdcardprogrammingstate(&cardstate);
  while((errorstatus==sd_ok)&&((cardstate==sd_card_programming)||(cardstate==sd_card_receiving)))
{
errorstatus=sdio_sdcardprogrammingstate(&cardstate);
}   
return errorstatus;    
}
/*
函数功能: sdio中断服务函数
*/   
void sdio_irqhandler(void) 
{
    sdio_sdcardprocessirqsrc();//处理所有sdio相关中断
}
/*
函数功能: sdio中断处理函数
函数参数: 处理sdio传输过程中的各种中断事务
返回值:错误代码
*/
sdio_sd_error_info sdio_sdcardprocessirqsrc(void)
{
if(sdio->sta&(1if(status&((1<<0)|(1<<2)|(1<<6)))break;//crc错误/命令响应超时/已经收到响应(crc校验成功)
}
  if((timeout==0)||(status&(1return errorstatus;
}  
if(status&1      if(status&((1<<0)|(1<<2)|(1<<6)))break;//crc错误/命令响应超时/已经收到响应(crc校验成功)
    } 
    if(status&(1      return sd_cmd_rsp_timeout;
    }
    if(status&(1    return (sdio_sd_error_info)(sdio->resp1&sd_ocr_errorbits);//返回卡响应
}
/*
函数功能: 检查r3响应的错误状态
返回值:   错误状态
*/
sdio_sd_error_info sdio_cmdresp3error(void)
{
u32 status;  
  while(1)
{
status=sdio->sta;
if(status&((1<<0)|(1<<2)|(1<<6)))break;//crc错误/命令响应超时/已经收到响应(crc校验成功)
}
  if(status&(1      if(status&((1<<0)|(1<<2)|(1<<6)))break;//crc错误/命令响应超时/已经收到响应(crc校验成功)
    }
    if((timeout==0)||(status&(1      return errorstatus;
    }  
    if(status&1if(status&((1<<0)|(1<<2)|(1<<6)))break;//crc错误/命令响应超时/已经收到响应(crc校验成功)
}
if(status&(1return sd_cmd_rsp_timeout;
}  
if(status&1rspr1=sdio->resp1; //得到响应  
if(sd_allzero==(rspr1&(sd_r6_general_unknown_error|sd_r6_illegal_cmd|sd_r6_com_crc_failed)))
{
*prca=(u16)(rspr1>>16); //右移16位得到,rca
return errorstatus;
}
    if(rspr1&sd_r6_general_unknown_error)return sd_general_unknown_error;
    if(rspr1&sd_r6_illegal_cmd)return sd_illegal_cmd;
    if(rspr1&sd_r6_com_crc_failed)return sd_com_crc_failed;
return errorstatus;
}
/*
函数功能:sdio使能宽总线模式
函数参数:
         enx:0,不使能;1,使能;
返回值:错误状态
*/
sdio_sd_error_info sdio_sdcardenwidebus(u8 enx)
{
sdio_sd_error_info errorstatus = sd_ok;
  u32 scr[2]={0,0};
u8 arg=0x00;
if(enx)arg=0x02;
else arg=0x00;
  if(sdio->resp1&sd_card_locked)return sd_lock_unlock_failed;//sd卡处于locked状态     
  errorstatus=sdio_sdcardfindscr(rca,scr); //得到scr寄存器数据
  if(errorstatus!=sd_ok)return errorstatus;
if((scr[1]&sd_wide_bus_support)!=sd_allzero) //支持宽总线
{
sdio_sendcmd(sd_cmd_app_cmd,1,(u32)rca<<16); //发送cmd55+rca,短响应   
errorstatus=sdio_cmdresp1error(sd_cmd_app_cmd);
if(errorstatus!=sd_ok)return errorstatus; 
sdio_sendcmd(sd_cmd_app_sd_set_buswidth,1,arg);//发送acmd6,短响应,参数:10,4位;00,1位.   
errorstatus=sdio_cmdresp1error(sd_cmd_app_sd_set_buswidth);
return errorstatus;
}else return sd_request_not_applicable; //不支持宽总线设置  
}
/*
函数功能: 检查卡是否正在执行写操作
函数参数: pstatus:当前状态
返回值:错误代码
*/
sdio_sd_error_info sdio_sdcardprogrammingstate(u8 *pstatus)
{
  vu32 respr1 = 0, status = 0; 
  sdio_sendcmd(sd_cmd_send_status,1,(u32)rcawhile(!(status&((1<<0)|(1<<6)|(1  if(status&(1return sd_cmd_crc_fail;
}
  if(status&(1respr1=sdio->resp1;
*pstatus=(u8)((respr1>>9)&0x0000000f);
return sd_ok;
}
/*
函数功能: 读取当前卡状态
函数参数: 
        pcardstatus:卡状态
返回值 :错误代码
*/
sdio_sd_error_info sdio_sdcardsendstatus(uint32_t *pcardstatus)
{
sdio_sd_error_info errorstatus = sd_ok;
if(pcardstatus==null)
{
errorstatus=sd_invalid_parameter;
return errorstatus;
}
  sdio_sendcmd(sd_cmd_send_status,1,rca>9) & 0x0f);
}
/*
函数功能:查找sd卡的scr寄存器值
函数参数:
        rca:卡相对地址
        pscr:数据缓存区(存储scr内容)
返回值:错误状态
*/   
sdio_sd_error_info sdio_sdcardfindscr(u16 rca,u32 *pscr)

u32 index = 0; 
sdio_sd_error_info errorstatus = sd_ok;
u32 tempscr[2]={0,0};  
  sdio_sendcmd(sd_cmd_set_blocklen,1,8); //发送cmd16,短响应,设置block size为8字节   
  errorstatus=sdio_cmdresp1error(sd_cmd_set_blocklen);
  if(errorstatus!=sd_ok)return errorstatus;     
  sdio_sendcmd(sd_cmd_app_cmd,1,(u32)rcasta&(1=2)break;
}
}
  if(sdio->sta&(1//把数据顺序按8位为单位倒过来.   
*(pscr+1)=((tempscr[0]&sd_0to7bits)<<24)|((tempscr[0]&sd_8to15bits)8)|((tempscr[0]&sd_24to31bits)>>24);
*(pscr)=((tempscr[1]&sd_0to7bits)<<24)|((tempscr[1]&sd_8to15bits)8)|((tempscr[1]&sd_24to31bits)>>24);
  return errorstatus;
}
/*
函数功能: 得到numberofbytes以2为底的指数
函数参数: numberofbytes:字节数
返回值:以2为底的指数值
*/
u8 convert_from_bytes_to_power_of_two(u16 numberofbytes)
{
u8 count=0;
while(numberofbytes!=1)
{
numberofbytes>>=1;
count++;
}
return count;
}
/*
函数功能: 配置sdio dma  
函数参数: 
        mbuf:存储器地址
        bufsize:传输数据量
        dir:方向;1,存储器-->sdio(写数据);0,sdio-->存储器(读数据);
*/
void sdio_sdcard_dmaconfig(u32*mbuf,u32 bufsize,u8 dir)
{  
  dma2->ifcr|=(0xffifo;//dma2 外设地址 
dma2_channel4->cmar=(u32)mbuf; //dma2,存储器地址
  dma2_channel4->ccr|=1<<0; //开启dma通道
}
/*
函数功能: 读sd卡
函数参数:
        buf:读数据缓存区
        sector:扇区地址
        cnt:扇区个数
返回值:错误状态;0,正常;其他,错误代码;
*/  
u8 sdio_sdcardreaddisksector(u8*buf,u32 sector,u8 cnt)
{
u8 sta=sd_ok;
long long lsector=sector;
u8 n;
lsector<<=9;
if((u32)buf%4!=0)
{
for(n=0;n
{
sta=sdio_sdcardreadblock(sdio_data_buffer,lsector+512*n,512);//单个sector的读操作
memcpy(buf,sdio_data_buffer,512);
buf+=512;

}else
{
if(cnt==1)sta=sdio_sdcardreadblock(buf,lsector,512);    //单个sector的读操作
else sta=sdio_sdcardreadmultiblocks(buf,lsector,512,cnt);//多个sector  
}
return sta;
}
/*
函数功能:写sd卡 
函数参数:
        buf:写数据缓存区
        sector:扇区地址
        cnt:扇区个数
返回值:错误状态;0,正常;其他,错误代码;
*/
u8 sdio_sdcardwritedisksector(u8*buf,u32 sector,u8 cnt)
{
u8 sta=sd_ok;
u8 n;
long long lsector=sector;
lsector<<=9;
if((u32)buf%4!=0)
{
for(n=0;n
{
memcpy(sdio_data_buffer,buf,512);
sta=sdio_sdcardwriteblock(sdio_data_buffer,lsector+512*n,512);//单个sector的写操作
buf+=512;

}else
{
if(cnt==1)sta=sdio_sdcardwriteblock(buf,lsector,512);    //单个sector的写操作
else sta=sdio_sdcardwritemultiblocks(buf,lsector,512,cnt); //多个sector  
}
return sta;
}
 (3)sdio.h#ifndef __sdio_sdcard_h
#define __sdio_sdcard_h    
#include stm32f10x.h
//sdio相关标志位
#define sdio_flag_ccrcfail                  ((uint32_t)0x00000001)
#define sdio_flag_dcrcfail                  ((uint32_t)0x00000002)
#define sdio_flag_ctimeout                  ((uint32_t)0x00000004)
#define sdio_flag_dtimeout                  ((uint32_t)0x00000008)
#define sdio_flag_txunderr                  ((uint32_t)0x00000010)
#define sdio_flag_rxoverr                   ((uint32_t)0x00000020)
#define sdio_flag_cmdrend                   ((uint32_t)0x00000040)
#define sdio_flag_cmdsent                   ((uint32_t)0x00000080)
#define sdio_flag_dataend                   ((uint32_t)0x00000100)
#define sdio_flag_stbiterr                  ((uint32_t)0x00000200)
#define sdio_flag_dbckend                   ((uint32_t)0x00000400)
#define sdio_flag_cmdact                    ((uint32_t)0x00000800)
#define sdio_flag_txact                     ((uint32_t)0x00001000)
#define sdio_flag_rxact                     ((uint32_t)0x00002000)
#define sdio_flag_txfifohe                  ((uint32_t)0x00004000)
#define sdio_flag_rxfifohf                  ((uint32_t)0x00008000)
#define sdio_flag_txfifof                   ((uint32_t)0x00010000)
#define sdio_flag_rxfifof                   ((uint32_t)0x00020000)
#define sdio_flag_txfifoe                   ((uint32_t)0x00040000)
#define sdio_flag_rxfifoe                   ((uint32_t)0x00080000)
#define sdio_flag_txdavl                    ((uint32_t)0x00100000)
#define sdio_flag_rxdavl                    ((uint32_t)0x00200000)
#define sdio_flag_sdioit                    ((uint32_t)0x00400000)
#define sdio_flag_ceataend                  ((uint32_t)0x00800000)
//用户配置区   
//sdio时钟计算公式:sdio_ck时钟=sdioclk/[clkdiv+2];其中,sdioclk一般为72mhz
//使用dma模式的时候,传输速率可以到24mhz,不过如果你的卡不是高速卡,可能也会出错
//出错就请降低时钟,使用查询模式的话,推荐sdio_transfer_clk_div设置为3或者更大
#define sdio_init_clk_div        0xb2 //sdio初始化频率,最大400kh  
#define sdio_transfer_clk_div    0x04 //sdio传输频率,该值太小可能会导致读写文件出错
//sdio工作模式定义,通过sdio_sdcardsetdevicemode函数设置.
#define sd_polling_mode    0  //查询模式,该模式下,如果读写有问题,建议增大sdio_transfer_clk_div的设置.
#define sd_dma_mode    1 //dma模式,该模式下,如果读写有问题,建议增大sdio_transfer_clk_div的设置.
//sdio 各种错误枚举定义
typedef enum
{  
//特殊错误定义 
sd_cmd_crc_fail                    = (1), /*!< command response received (but crc check failed) */
sd_data_crc_fail                   = (2), /*!< data bock sent/received (crc check failed) */
sd_cmd_rsp_timeout                 = (3), /*!< command response timeout */
sd_data_timeout                    = (4), /*!< data time out */
sd_tx_underrun                     = (5), /*!< transmit fifo under-run */
sd_rx_overrun                      = (6), /*!< receive fifo over-run */
sd_start_bit_err                   = (7), /*!< start bit not detected on all data signals in wide bus mode */
sd_cmd_out_of_range                = (8), /*!< cmd's argument was out of range.*/
sd_addr_misaligned                 = (9), /*!< misaligned address */
sd_block_len_err                   = (10), /*!< transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
sd_erase_seq_err                   = (11), /*!< an error in the sequence of erase command occurs.*/
sd_bad_erase_param                 = (12), /*!< an invalid selection for erase groups */
sd_write_prot_violation            = (13), /*!< attempt to program a write protect block */
sd_lock_unlock_failed              = (14), /*!< sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */
sd_com_crc_failed                  = (15), /*!< crc check of the previous command failed */
sd_illegal_cmd                     = (16), /*!< command is not legal for the card state */
sd_card_ecc_failed                 = (17), /*!< card internal ecc was applied but failed to correct the data */
sd_cc_error                        = (18), /*!< internal card controller error */
sd_general_unknown_error           = (19), /*!< general or unknown error */
sd_stream_read_underrun            = (20), /*!< the card could not sustain data transfer in stream read operation. */
sd_stream_write_overrun            = (21), /*!< the card could not sustain data programming in stream mode */
sd_cid_csd_overwrite               = (22), /*!< cid/csd overwrite error */
sd_wp_erase_skip                   = (23), /*!< only partial address space was erased */
sd_card_ecc_disabled               = (24), /*!< command has been executed without using internal ecc */
sd_erase_reset                     = (25), /*!< erase sequence was cleared before executing because an out of erase sequence command was received */
sd_ake_seq_error                   = (26), /*!< error in sequence of authentication. */
sd_invalid_voltrange               = (27),
sd_addr_out_of_range               = (28),
sd_switch_error                    = (29),
sd_sdio_disabled                   = (30),
sd_sdio_function_busy              = (31),
sd_sdio_function_failed            = (32),
sd_sdio_unknown_function           = (33),
//标准错误定义
sd_internal_error, 
sd_not_configured,
sd_request_pending, 
sd_request_not_applicable, 
sd_invalid_parameter,  
sd_unsupported_feature,  
sd_unsupported_hw,  
sd_error,  
sd_ok = 0 
} sdio_sd_error_info;
//sd卡csd寄存器数据   
typedef struct
{
u8  csdstruct;            /*!< csd structure */
u8  sysspecversion;       /*!< system specification version */
u8  reserved1;            /*!< reserved */
u8  taac;                 /*!< data read access-time 1 */
u8  nsac;                 /*!< data read access-time 2 in clk cycles */
u8  maxbusclkfrec;        /*!< max. bus clock frequency */
u16 cardcomdclasses;      /*!< card command classes */
u8  rdblocklen;           /*!< max. read data block length */
u8  partblockread;        /*!< partial blocks for read allowed */
u8  wrblockmisalign;      /*!< write block misalignment */
u8  rdblockmisalign;      /*!< read block misalignment */
u8  dsrimpl;              /*!< dsr implemented */
u8  reserved2;            /*!< reserved */
u32 devicesize;           /*!< device size */
u8  maxrdcurrentvddmin;   /*!< max. read current @ vdd min */
u8  maxrdcurrentvddmax;   /*!< max. read current @ vdd max */
u8  maxwrcurrentvddmin;   /*!< max. write current @ vdd min */
u8  maxwrcurrentvddmax;   /*!< max. write current @ vdd max */
u8  devicesizemul;        /*!< device size multiplier */
u8  erasegrsize;          /*!< erase group size */
u8  erasegrmul;           /*!< erase group size multiplier */
u8  wrprotectgrsize;      /*!< write protect group size */
u8  wrprotectgrenable;    /*!< write protect group enable */
u8  mandeflecc;           /*!< manufacturer default ecc */
u8  wrspeedfact;          /*!< write speed factor */
u8  maxwrblocklen;        /*!< max. write data block length */
u8  writeblockpapartial;  /*!< partial blocks for write allowed */
u8  reserved3;            /*!< reserded */
u8  contentprotectappli;  /*!< content protection application */
u8  fileformatgrouop;     /*!< file format group */
u8  copyflag;             /*!< copy flag (otp) */
u8  permwrprotect;        /*!< permanent write protection */
u8  tempwrprotect;        /*!< temporary write protection */
u8  fileformat;           /*!< file format */
u8  ecc;                  /*!< ecc code */
u8  csd_crc;              /*!< csd crc */
u8  reserved4;            /*!< always 1*/
} sd_csd;
//sd卡cid寄存器数据
typedef struct
{
u8  manufacturerid;       /*!< manufacturerid */
u16 oem_appliid;          /*!< oem/application id */
u32 prodname1;            /*!< product name part1 */
u8  prodname2;            /*!< product name part2*/
u8  prodrev;              /*!< product revision */
u32 prodsn;               /*!< product serial number */
u8  reserved1;            /*!< reserved1 */
u16 manufactdate;         /*!< manufacturing date */
u8  cid_crc;              /*!< cid crc */
u8  reserved2;            /*!< always 1 */
} sd_cid;
//sd卡状态
typedef enum
{
sd_card_ready                  = ((uint32_t)0x00000001),
sd_card_identification         = ((uint32_t)0x00000002),
sd_card_standby                = ((uint32_t)0x00000003),
sd_card_transfer               = ((uint32_t)0x00000004),
sd_card_sending                = ((uint32_t)0x00000005),
sd_card_receiving              = ((uint32_t)0x00000006),
sd_card_programming            = ((uint32_t)0x00000007),
sd_card_disconnected           = ((uint32_t)0x00000008),
sd_card_error                  = ((uint32_t)0x000000ff)
}sdcardstate;
//sd卡信息,包括csd,cid等数据
typedef struct
{
  sd_csd sd_csd;
  sd_cid sd_cid;
  long long cardcapacity;  //sd卡容量,单位:字节,最大支持2^64字节大小的卡.
  u32 cardblocksize; //sd卡块大小
  u16 rca; //卡相对地址
  u8 cardtype; //卡类型
} sd_cardinfo;
extern sd_cardinfo sdcardinfo;//sd卡信息
//sdio 指令集
#define sd_cmd_go_idle_state                       ((u8)0)
#define sd_cmd_send_op_cond                        ((u8)1)
#define sd_cmd_all_send_cid                        ((u8)2)
#define sd_cmd_set_rel_addr                        ((u8)3) /*!< sdio_send_rel_addr for sd card */
#define sd_cmd_set_dsr                             ((u8)4)
#define sd_cmd_sdio_sen_op_cond                    ((u8)5)
#define sd_cmd_hs_switch                           ((u8)6)
#define sd_cmd_sel_desel_card                      ((u8)7)
#define sd_cmd_hs_send_ext_csd                     ((u8)8)
#define sd_cmd_send_csd                            ((u8)9)
#define sd_cmd_send_cid                            ((u8)10)
#define sd_cmd_read_dat_until_stop                 ((u8)11) /*!< sd card doesn't support it */
#define sd_cmd_stop_transmission                   ((u8)12)
#define sd_cmd_send_status                         ((u8)13)
#define sd_cmd_hs_bustest_read                     ((u8)14)
#define sd_cmd_go_inactive_state                   ((u8)15)
#define sd_cmd_set_blocklen                        ((u8)16)
#define sd_cmd_read_single_block                   ((u8)17)
#define sd_cmd_read_mult_block                     ((u8)18)
#define sd_cmd_hs_bustest_write                    ((u8)19)
#define sd_cmd_write_dat_until_stop                ((u8)20) 
#define sd_cmd_set_block_count                     ((u8)23) 
#define sd_cmd_write_single_block                  ((u8)24)
#define sd_cmd_write_mult_block                    ((u8)25)
#define sd_cmd_prog_cid                            ((u8)26)
#define sd_cmd_prog_csd                            ((u8)27)
#define sd_cmd_set_write_prot                      ((u8)28)
#define sd_cmd_clr_write_prot                      ((u8)29)
#define sd_cmd_send_write_prot                     ((u8)30)
#define sd_cmd_sd_erase_grp_start                  ((u8)32) /*!< to set the address of the first write
                                                                  block to be erased. (for sd card only) */
#define sd_cmd_sd_erase_grp_end                    ((u8)33) /*!< to set the address of the last write block of the
                                                                  continuous range to be erased. (for sd card only) */
#define sd_cmd_erase_grp_start                     ((u8)35) /*!< to set the address of the first write block to be erased.
                                                                  (for mmc card only spec 3.31) */
#define sd_cmd_erase_grp_end                       ((u8)36) /*!< to set the address of the last write block of the
                                                                  continuous range to be erased. (for mmc card only spec 3.31) */
#define sd_cmd_erase                               ((u8)38)
#define sd_cmd_fast_io                             ((u8)39) /*!< sd card doesn't support it */
#define sd_cmd_go_irq_state                        ((u8)40) /*!< sd card doesn't support it */
#define sd_cmd_lock_unlock                         ((u8)42)
#define sd_cmd_app_cmd                             ((u8)55)
#define sd_cmd_gen_cmd                             ((u8)56)
#define sd_cmd_no_cmd                              ((u8)64)
/** 
  * @brief following commands are sd card specific commands.
  *        sdio_app_cmd :cmd55 should be sent before sending these commands. 
  */
#define sd_cmd_app_sd_set_buswidth                 ((u8)6)  /*!< for sd card only */
#define sd_cmd_sd_app_staus                        ((u8)13) /*!< for sd card only */
#define sd_cmd_sd_app_send_num_write_blocks        ((u8)22) /*!< for sd card only */
#define sd_cmd_sd_app_op_cond                      ((u8)41) /*!< for sd card only */
#define sd_cmd_sd_app_set_clr_card_detect          ((u8)42) /*!< for sd card only */
#define sd_cmd_sd_app_send_scr                     ((u8)51) /*!< for sd card only */
#define sd_cmd_sdio_rw_direct                      ((u8)52) /*!< for sd i/o card only */
#define sd_cmd_sdio_rw_extended                    ((u8)53) /*!< for sd i/o card only */
/** 
  * @brief following commands are sd card specific security commands.
  *        sdio_app_cmd should be sent before sending these commands. 
  */
#define sd_cmd_sd_app_get_mkb                      ((u8)43) /*!< for sd card only */
#define sd_cmd_sd_app_get_mid                      ((u8)44) /*!< for sd card only */
#define sd_cmd_sd_app_set_cer_rn1                  ((u8)45) /*!< for sd card only */
#define sd_cmd_sd_app_get_cer_rn2                  ((u8)46) /*!< for sd card only */
#define sd_cmd_sd_app_set_cer_res2                 ((u8)47) /*!< for sd card only */
#define sd_cmd_sd_app_get_cer_res1                 ((u8)48) /*!< for sd card only */
#define sd_cmd_sd_app_secure_read_multiple_block   ((u8)18) /*!< for sd card only */
#define sd_cmd_sd_app_secure_write_multiple_block  ((u8)25) /*!< for sd card only */
#define sd_cmd_sd_app_secure_erase                 ((u8)38) /*!< for sd card only */
#define sd_cmd_sd_app_change_secure_area           ((u8)49) /*!< for sd card only */
#define sd_cmd_sd_app_secure_write_mkb             ((u8)48) /*!< for sd card only */
//支持的sd卡定义
#define sdio_std_capacity_sd_card_v1_1             ((u32)0x00000000)
#define sdio_std_capacity_sd_card_v2_0             ((u32)0x00000001)
#define sdio_high_capacity_sd_card                 ((u32)0x00000002)
#define sdio_multimedia_card                       ((u32)0x00000003)
#define sdio_secure_digital_io_card                ((u32)0x00000004)
#define sdio_high_speed_multimedia_card            ((u32)0x00000005)
#define sdio_secure_digital_io_combo_card          ((u32)0x00000006)
#define sdio_high_capacity_mmc_card                ((u32)0x00000007)
//sdio相关参数定义
#define null 0
#define sdio_static_flags               ((u32)0x000005ff)
#define sdio_cmd0timeout                ((u32)0x00010000)   
#define sdio_datatimeout                ((u32)0xffffffff)   
#define sdio_fifo_address               ((u32)0x40018080)
//mask for errors card status r1 (ocr register)  
#define sd_ocr_addr_out_of_range        ((u32)0x80000000)
#define sd_ocr_addr_misaligned          ((u32)0x40000000)
#define sd_ocr_block_len_err            ((u32)0x20000000)
#define sd_ocr_erase_seq_err            ((u32)0x10000000)
#define sd_ocr_bad_erase_param          ((u32)0x08000000)
#define sd_ocr_write_prot_violation     ((u32)0x04000000)
#define sd_ocr_lock_unlock_failed       ((u32)0x01000000)
#define sd_ocr_com_crc_failed           ((u32)0x00800000)
#define sd_ocr_illegal_cmd              ((u32)0x00400000)
#define sd_ocr_card_ecc_failed          ((u32)0x00200000)
#define sd_ocr_cc_error                 ((u32)0x00100000)
#define sd_ocr_general_unknown_error    ((u32)0x00080000)
#define sd_ocr_stream_read_underrun     ((u32)0x00040000)
#define sd_ocr_stream_write_overrun     ((u32)0x00020000)
#define sd_ocr_cid_csd_overwriete       ((u32)0x00010000)
#define sd_ocr_wp_erase_skip            ((u32)0x00008000)
#define sd_ocr_card_ecc_disabled        ((u32)0x00004000)
#define sd_ocr_erase_reset              ((u32)0x00002000)
#define sd_ocr_ake_seq_error            ((u32)0x00000008)
#define sd_ocr_errorbits                ((u32)0xfdffe008)
//masks for r6 response 
#define sd_r6_general_unknown_error     ((u32)0x00002000)
#define sd_r6_illegal_cmd               ((u32)0x00004000)
#define sd_r6_com_crc_failed            ((u32)0x00008000)
#define sd_voltage_window_sd            ((u32)0x80100000)
#define sd_high_capacity                ((u32)0x40000000)
#define sd_std_capacity                 ((u32)0x00000000)
#define sd_check_pattern                ((u32)0x000001aa)
#define sd_voltage_window_mmc           ((u32)0x80ff8000)
#define sd_max_volt_trial               ((u32)0x0000ffff)
#define sd_allzero                      ((u32)0x00000000)
#define sd_wide_bus_support             ((u32)0x00040000)
#define sd_single_bus_support           ((u32)0x00010000)
#define sd_card_locked                  ((u32)0x02000000)
#define sd_card_programming             ((u32)0x00000007)
#define sd_card_receiving               ((u32)0x00000006)
#define sd_datatimeout                  ((u32)0xffffffff)
#define sd_0to7bits                     ((u32)0x000000ff)
#define sd_8to15bits                    ((u32)0x0000ff00)
#define sd_16to23bits                   ((u32)0x00ff0000)
#define sd_24to31bits                   ((u32)0xff000000)
#define sd_max_data_length              ((u32)0x01ffffff)
#define sd_halffifo                     ((u32)0x00000008)
#define sd_halffifobytes                ((u32)0x00000020)
//command class supported  
#define sd_cccc_lock_unlock             ((u32)0x00000080)
#define sd_cccc_write_prot              ((u32)0x00000040)
#define sd_cccc_erase                   ((u32)0x00000020)
//cmd8指令
#define sdio_send_if_cond               ((u32)0x00000008)
//相关函数定义
sdio_sd_error_info sdio_sdcardinit(void);
void sdio_clockset(u8 clkdiv);
void sdio_sendcmd(u8 cmdindex,u8 waitrsp,u32 arg);
void sdio_senddataconfig(u32 datatimeout,u32 datalen,u8 blksize,u8 dir);
sdio_sd_error_info sdio_sdpoweron(void);    
sdio_sd_error_info sd_poweroff(void);
sdio_sd_error_info sdio_sdcardinitializecards(void);
sdio_sd_error_info sdio_sdcardgetinfo(sd_cardinfo *cardinfo);   
sdio_sd_error_info sdio_sdcardenablewidebusoperation(u32 wmode);
sdio_sd_error_info sdio_sdcardsetdevicemode(u32 mode);
sdio_sd_error_info sdio_sdcardselectaddr(u32 addr); 
sdio_sd_error_info sdio_sdcardsendstatus(uint32_t *pcardstatus);
sdcardstate sdio_sdcardgetstate(void);
sdio_sd_error_info sdio_sdcardreadblock(u8 *buf,long long addr,u16 blksize);  
sdio_sd_error_info sdio_sdcardreadmultiblocks(u8 *buf,long long  addr,u16 blksize,u32 nblks);  
sdio_sd_error_info sdio_sdcardwriteblock(u8 *buf,long long addr,  u16 blksize);
sdio_sd_error_info sdio_sdcardwritemultiblocks(u8 *buf,long long addr,u16 blksize,u32 nblks);
sdio_sd_error_info sdio_sdcardprocessirqsrc(void);
sdio_sd_error_info sdio_cmderrorcheck(void);  
sdio_sd_error_info sdio_cmdresp7error(void);
sdio_sd_error_info sdio_cmdresp1error(u8 cmd);
sdio_sd_error_info sdio_cmdresp3error(void);
sdio_sd_error_info sdio_cmdresp2error(void);
sdio_sd_error_info sdio_cmdresp6error(u8 cmd,u16*prca);  
sdio_sd_error_info sdio_sdcardenwidebus(u8 enx);   
sdio_sd_error_info sdio_sdcardprogrammingstate(u8 *pstatus); 
sdio_sd_error_info sdio_sdcardfindscr(u16 rca,u32 *pscr);
u8 convert_from_bytes_to_power_of_two(u16 numberofbytes); 
void sdio_sdcard_dmaconfig(u32*mbuf,u32 bufsize,u8 dir); 
u8 sdio_sdcardreaddisksector(u8*buf,u32 sector,u8 cnt); //读sd卡,fatfs/usb调用
u8 sdio_sdcardwritedisksector(u8*buf,u32 sector,u8 cnt); //写sd卡,fatfs/usb调用
#endif

废气vocs在线监测仪正宗生产厂家
dfrobot记忆合金肌肉驱动器 介绍
瑞佑科技推出支持文字与绘图模式的TFT彩屏控制器
数控电源电路的工作原理、功能及故障分析
扫地机器人中的灰尘识别感应器用到了哪些技术
基于STM32采用CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试(中篇)
5G真的来了 这些问题你一定想问!
2017三大领域展望:物联网(IoT)、VR/AR和机器学习
ST推出一款新的高集成度系统级芯片
光缆故障的主要产生原因及解决方案
电阻器的基本介绍和作用
基于四路同步水声信号记录仪设计方案
Redmi Note 8 Pro的首销破30万台,Redmi与荣耀的竞争已趋向白热化
摩托罗拉Moto Z2 Play手机更新到Android 9.0操作系统
德思特分享 | V2X在做什么?连接未来智能出行的车联网(上)
华为正在通过ICT技术来推动智能网联汽车行业的发展
变速齿轮怎么用 变速齿轮加速器原理
探讨深度学习在自动驾驶中的应用
空气负氧离子监测站价格是怎么定的?
小米6最新消息:小米6首次销售,京东预约142万一秒售罄