SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研发。
SD卡的结构能确保数字文件传送的安全性,也很简单从头格式化,因而越来越多的被运用的嵌入式体系中。
SD卡的运用十分便利,常见的有两种作业方法:SPI和SDIO。SPI是串行的作业方法,速度相对较低,可是运用便利,只需MCU含有SPI接口均可运用。SDIO方法,能够最多4线传输,因而速度比较快,因为SD卡的遍及,越来越多的MCU内部集成了SDIO操控器,简化了咱们的作业。本文以三星s3c2410为例介绍。
1.SD卡的接口电路
2.SD卡的协议
SD卡的操控指令十分强壮,支撑SPI,SDIO方法,兼容MMC等。并且不同的
指令有不同的呼应(3种),这在咱们运用指令是要注意的。我在附件里边放了一个SD卡的中文协议,包含数据包介绍,指令索引介绍,反应介绍等。
3.S3C2410 SD卡操控器的介绍
SD卡操控器帮咱们完结了协议上的许多作业,咱们只需要依照协议装备寄存器
以及依照协议流程对SD卡操作就能够完结SD卡的功用了。
SDICON:完结SD卡根底装备,包含巨细端,中止答应,方法挑选,时钟使能等。
SDIPRE:对SDCLK的装备。
SDICARG:指令的参数寄存在这儿
SDICCON:操控指令方法的寄存器,装备SPI仍是SDI指令,指令的反应长度,是否等候反应,是否运转指令,指令的索引等
SDICSTA:指令状况寄存器,指令是否超时,传送,完毕,CRC是否正确等
SDIRSPO:反映SD的状况
SDITIMER:设置超时时刻
SDIBSIZE:block的巨细
SDIDCON:数据操控寄存器,装备是几线传输,数据发送方向,数据传送方法等。
SDIDSTA:数据状况寄存器,数据是否发送完,CRC效验,超时等
SDIFSTA:FIFO状况积存器,DMA传输时否判别FIFO
SDIMSK:中止屏蔽
4.SD卡SDIO方法的驱动剖析
4.1SD卡的初始化
过程是:1)装备时钟,慢速一般为400K,设置作业方法
2)发送CMD0,进入闲暇态,该指令没有反应
3)发送CMD55+ACMD41,判别SD卡的上电是否正确,短反应
4)发送CMD2,验证SD卡是否接入,长反应
5)发送CMD3,读取SD卡的RCA(地址),短反应
6)发送CMD7,使能SD卡
7)装备高速时钟,预备数据传输,一般20M~25M
8)发送CMD55+ACMD6装备为4bit数据传输方法
代码如下:
int SD_card_init(void)
{
int i;
char key;
rSDIPRE=PCLK/(2*INICLK)-1;//时钟400KHz
rSDICON=(1<<4)|(1<<1)|1;// Type B, FIFO reset, clk enable
rSDIBSIZE=0x200;// 512byte(128word)
rSDIDTIMER=0xffff;// Set timeout count
for(i=0;i<0x1000;i++);// Wait 74SDCLK for MMC card
CMD0();//进入idle
//–CheckSDcard OCR
if(Chk_SD_OCR())//发送AM41,判别电压正确否
;
else
{
;
return 0;
}
RECMD2:
rSDICARG=0x0;
// CMD2(stuff bit),判别衔接
rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42;
//lng_resp, wait_resp, start, CMD2
//– Check end of CMD2
if(!Chk_CMDend(2, 1))//查询反应是否正确
goto RECMD2;
RECMD3:
//–Send RCA,得到SD卡的地址
rSDICARG=MMC<<16;
// CMD3(MMC:SetRCA,SD:Ask RCA–>SBZ)
rSDICCON=(0x1<<9)|(0x1<<8)|0x43;
// sht_resp, wait_resp, start, CMD3
//– Check end of CMD3
if(!Chk_CMDend(3, 1))
goto RECMD3;
//–Publish RCA
RCA=( rSDIRSP0 & 0xffff0000 )>>16;
//–State(stand-by) check
if( rSDIRSP0 & 0x1e00!=0x600 )
// CURRENT_STATE check验证反应
goto RECMD3;
rSDIPRE=PCLK/(2*NORCLK)-1;
//设置高速时钟Normal clock=”25MHz”
Card_sel_desel(1);// Select SD
Set_4bit_bus();//设置为4bit方法
}
void Set_4bit_bus(void)
{
Wide=1;
SetBus();
}
void SetBus(void)
{
SET_BUS:
CMD55();
// Make ACMD
//– CMD6 implement
rSDICARG=Wide<<1;
//Wide 0: 1bit, 1: 4bit
rSDICCON=(0x1<<9)|(0x1<<8)|0x46;
//sht_resp, wait_resp, start, CMD55
if(!Chk_CMDend(6, 1))// ACMD6
goto SET_BUS;
}
4.2SD卡的读与写
读写便是正反向的问题,这儿只剖析读
过程:1)读单block CMD17多block CMD18
(写单block CMD24多block CMD25)
2)发送CMD12,停止数据传输
程序如下:选用DMA方法
void Rd_Block(void)
{
int status;
rd_cnt=0;
rSDICON |= rSDICON|(1<<1);// FIFO reset
rSDICARG=0x0;// CMD17/18(addr参数)
RERDCMD:
pISR_DMA0=(unsigned)DMA_end;//DMA的相关装备
rINTMSK = ~(BIT_DMA0);
rDISRC0=(int)(SDIDAT);// SDIDAT
rDISRCC0=(1<<1)+(1<<0);// APB, fix
rDIDST0=(U32)(Rx_buffer);// Rx_buffer
rDIDSTC0=(0<<1)+(0<<0);// AHB, inc
rDCON0=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;
//handshake, sync PCLK, TC int, single tx, single service, SDI, H/W request,
//auto-reload off, word, 128blk*num
rDMASKTRIG0=(0<<2)+(1<<1)+0;
//no-stop, DMA2 channel on, no-sw trigger
rSDIDCON=(1<<19)|(1<<17)|(Wide<<16)|(1<<15)|(2<<12)|(block<<0);
// Rx after rsp, blk, 4bit bus, dma enable, Rx start, blk num
if(block<2)// SINGLE_READ
{
rSDICCON=(0x1<<9)|(0x1<<8)|0x51;
// sht_resp, wait_resp, dat, start, CMD17
if(!Chk_CMDend(17, 1))
//– Check end of CMD17
goto RERDCMD;
}
else// MULTI_READ
{
rSDICCON=(0x1<<9)|(0x1<<8)|0x52;
// sht_resp, wait_resp, dat, start, CMD18
if(!Chk_CMDend(18, 1))
//– Check end of CMD18
goto RERDCMD;
}
while(!TR_end);
rINTMSK |= (BIT_DMA0);
TR_end=0;
rDMASKTRIG0=(1<<2);//DMA0 stop
break;
default:
break;
}
//– Check end of DATA
if(!Chk_DATend())
;
rSDIDSTA=0x10;// Clear data Tx/Rx end
if(block>1)
{
RERCMD12:
//–Stop cmd(CMD12)
rSDICARG=0x0;//CMD12(stuff bit)
rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;
//sht_resp, wait_resp, start, CMD12
//– Check end of CMD12
if(!Chk_CMDend(12, 1))
goto RERCMD12;
}
}
4.3上面用到的呼应判别函数
首要完结对反应状况的剖析。
函数如下:
int Chk_CMDend(int cmd, int be_resp)//指令反应判别函数
{
int finish0;
if(!be_resp)// No response
{
finish0=rSDICSTA;
while((finish0&0x800)!=0x800)//验证指令是不是发送
finish0=rSDICSTA;
rSDICSTA=finish0;// Clear cmd end state
return 1;
}
else// With response
{
finish0=rSDICSTA;
while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x400) ))
//验证反应呼应完结
finish0=rSDICSTA;
if(cmd==1 | cmd==9 | cmd==41)// CRC no check
{
if( (finish0&0xf00) != 0xa00 )// CRC是否过错
{
rSDICSTA=finish0;// Clear error state
if(((finish0&0x400)==0x400))//验证超时
return 0;}
rSDICSTA=finish0;
// Clear cmd & rsp end state
}
else// CRC check
{
if( (finish0&0x1f00) != 0xa00 )// Check error
{
;
rSDICSTA=finish0;// Clear error state
if(((finish0&0x400)==0x400))
return 0;// Timeout error
}
rSD%&&&&&%STA=finish0;
}
return 1;
}
}
int Chk_DATend(void)
{
int finish;
finish=rSDIDSTA;
while( !( ((finish&0x10)==0x10) | ((finish&0x20)==0x20) ))
// Chek timeout or data end
finish=rSDIDSTA;
if( (finish&0xfc) != 0x10 )
{
rSDIDSTA=0xec;// Clear error state
return 0;
}
return 1;
}
int Chk_BUSYend(void)//数据反应判别函数
{
int finish;
finish=rSDIDSTA;
while( !( ((finish&0x08)==0x08) | ((finish&0x20)==0x20) ))
finish=rSDIDSTA;//等候数据发送完结或超时
if( (finish&0xfc) != 0x08 )
{
rSD
IDSTA=0xf4;//clear error state
return 0;
}
return 1;
}