×
嵌入式 > 嵌入式开发 > 详情

ARM含SD控制器的SD卡的SDIO模式驱动解析

发布时间:2020-09-24 发布时间:
|

SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制。

SD卡的结构能保证数字文件传送的安全性,也很容易重新格式化,因此越来越多的被应用的嵌入式系统中。

SD卡的使用非常方便,常见的有两种工作模式:SPI和SDIO。SPI是串行的工作模式,速度相对较低,但是使用方便,只要MCU含有SPI接口均可使用。SDIO模式,可以最多4线传输,因此速度比较快,由于SD卡的普及,越来越多的MCU内部集成了SDIO控制器,简化了我们的工作。本文以三星s3c2410为例介绍。

1.xa0SD卡的接口电路

xa0xa0

xa0

2.xa0SD卡的协议

SD卡的控制指令非常强大,支持SPI,SDIO模式,兼容MMC等。而且不同的

指令有不同的响应(3种),这在我们使用指令是要注意的。我在附件里面放了一个SD卡的中文协议,包括数据包介绍,指令索引介绍,反馈介绍等。

3.xa0S3C2410xa0SD卡控制器的介绍

SD卡控制器帮我们完成了协议上的很多工作,我们只需要按照协议配置寄存器

以及按照协议流程对SD卡操作就可以完成SD卡的功能了。

SDICON:完成SD卡基础配置,包括大小端,中断允许,模式选择,时钟使能等。

SDIPRE:对SDCLK的配置。

SDICARG:指令的参数存放在这里

SDICCON:控制指令形式的寄存器,配置SPI还是SDI指令,指令的反馈长度,是否等待反馈,是否运行指令,指令的索引等

SDICSTA:指令状态寄存器,指令是否超时,传送,结束,CRC是否正确等

SDIRSPO:反映SD的状态

SDITIMER:设置超时时间

SDIBSIZE:block的大小

SDIDCON:数据控制寄存器,配置是几线传输,数据发送方向,数据传送方式等。

SDIDSTA:xa0数据状态寄存器,数据是否发送完,CRC效验,超时等

SDIFSTA:xa0FIFO状态积存器,DMA传输时否判断FIFO

SDIMSK:中断屏蔽

4.xa0SD卡SDIO模式的驱动分析

4.1xa0SD卡的初始化

步骤是: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数据传输模式

代码如下:

intxa0SD_card_init(void)

{

intxa0i;

charxa0key;

rSDIPRE=PCLK/(2*INICLK)-1;xa0//时钟xa0400KHz

rSDICON=(1<<4)|(1<<1)|1;xa0//xa0Typexa0B,xa0FIFOxa0reset,xa0clkxa0enable

rSDIBSIZE=0x200;xa0//xa0512byte(128word)

rSDIDTIMER=0xffff;xa0//xa0Setxa0timeoutxa0count

for(i=0;i<0x1000;i++);xa0//xa0Waitxa074SDCLKxa0forxa0MMCxa0card

CMD0();xa0//进入idle

//--xa0Checkxa0SDxa0cardxa0OCR

if(Chk_SD_OCR())xa0//发送AM41,判断电压正确否

;

else

{

;

returnxa00;

}

RECMD2:

rSDICARG=0x0;

//xa0CMD2(stuffxa0bit),判断连接

rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42;

//lng_resp,xa0wait_resp,xa0start,xa0CMD2

//--xa0Checkxa0endxa0ofxa0CMD2

if(!Chk_CMDend(2,xa01))xa0//查询反馈是否正确

gotoxa0RECMD2;

RECMD3:

//--Sendxa0RCA,得到SD卡的地址

rSDICARG=MMC<<16;

//xa0CMD3(MMC:Setxa0RCA,xa0SD:Askxa0RCA-->SBZ)

rSDICCON=(0x1<<9)|(0x1<<8)|0x43;

//xa0sht_resp,xa0wait_resp,xa0start,xa0CMD3

//--xa0Checkxa0endxa0ofxa0CMD3

if(!Chk_CMDend(3,xa01))

gotoxa0RECMD3;

//--Publishxa0RCA

RCA=(xa0rSDIRSP0xa0&xa00xffff0000xa0)>>16;

//--State(stand-by)xa0check

if(xa0rSDIRSP0xa0&xa00x1e00!=0x600xa0)

//xa0CURRENT_STATExa0checkxa0验证反馈

gotoxa0RECMD3;

rSDIPRE=PCLK/(2*NORCLK)-1;

//xa0设置高速时钟Normalxa0clock="25MHz"

Card_sel_desel(1);xa0//xa0Selectxa0SD

Set_4bit_bus();xa0//设置为4bit模式

}

voidxa0Set_4bit_bus(void)

{

Wide=1;

SetBus();

}

voidxa0SetBus(void)

{

SET_BUS:

CMD55();

//xa0Makexa0ACMD

//--xa0CMD6xa0implement

rSDICARG=Wide<<1;

//Widexa00:xa01bit,xa01:xa04bit

rSDICCON=(0x1<<9)|(0x1<<8)|0x46;

//sht_resp,xa0wait_resp,xa0start,xa0CMD55

if(!Chk_CMDend(6,xa01))xa0//xa0ACMD6

gotoxa0SET_BUS;

}

4.2SD卡的读与写

读写就是正反向的问题,这里只分析读

步骤:1)读单blockxa0CMD17xa0多blockxa0CMD18

(写单blockxa0CMD24xa0多blockxa0CMD25)

2)发送CMD12,终止数据传输

程序如下:采用DMA模式

voidxa0Rd_Block(void)

{

intxa0status;

rd_cnt=0;

rSDICONxa0|=xa0rSDICON|(1<<1);xa0//xa0FIFOxa0reset

rSDICARG=0x0;xa0//xa0CMD17/18(addr参数)

RERDCMD:

pISR_DMA0=(unsigned)DMA_end;xa0//DMA的相关配置

rINTMSKxa0=xa0~(BIT_DMA0);

rDISRC0=(int)(SDIDAT);xa0//xa0SDIDAT

rDISRCC0=(1<<1)+(1<<0);xa0//xa0APB,xa0fix

rDIDST0=(U32)(Rx_buffer);xa0//xa0Rx_buffer

rDIDSTC0=(0<<1)+(0<<0);xa0//xa0AHB,xa0inc

rDCON0=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;

//handshake,xa0syncxa0PCLK,xa0TCxa0int,xa0singlexa0tx,xa0singlexa0service,xa0SDI,xa0H/Wxa0request,

//auto-reloadxa0off,xa0word,xa0128blk*num

rDMASKTRIG0=(0<<2)+(1<<1)+0;

//no-stop,xa0DMA2xa0channelxa0on,xa0no-swxa0trigger

rSDIDCON=(1<<19)|(1<<17)|(Wide<<16)|(1<<15)|(2<<12)|(block<<0);

//xa0Rxxa0afterxa0rsp,xa0blk,xa04bitxa0bus,xa0dmaxa0enable,xa0Rxxa0start,xa0blkxa0num

if(block<2)xa0//xa0SINGLE_READ

{

rSDICCON=(0x1<<9)|(0x1<<8)|0x51;

//xa0sht_resp,xa0wait_resp,xa0dat,xa0start,xa0CMD17

if(!Chk_CMDend(17,xa01))

//--xa0Checkxa0endxa0ofxa0CMD17

gotoxa0RERDCMD;

}

elsexa0//xa0MULTI_READ

{

rSDICCON=(0x1<<9)|(0x1<<8)|0x52;

//xa0sht_resp,xa0wait_resp,xa0dat,xa0start,xa0CMD18

if(!Chk_CMDend(18,xa01))

//--xa0Checkxa0endxa0ofxa0CMD18

gotoxa0RERDCMD;

}

while(!TR_end);

rINTMSKxa0|=xa0(BIT_DMA0);

TR_end=0;

rDMASKTRIG0=(1<<2);xa0//DMA0xa0stop

break;

default:

break;

}

//--xa0Checkxa0endxa0ofxa0DATA

if(!Chk_DATend())

;

rSDIDSTA=0x10;xa0//xa0Clearxa0dataxa0Tx/Rxxa0end

if(block>1)

{

RERCMD12:

//--Stopxa0cmd(CMD12)

rSDICARG=0x0;xa0//CMD12(stuffxa0bit)

rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;

//sht_resp,xa0wait_resp,xa0start,xa0CMD12

//--xa0Checkxa0endxa0ofxa0CMD12

if(!Chk_CMDend(12,xa01))

gotoxa0RERCMD12;

}

}

4.3上面用到的响应判断函数

主要完成对反馈状态的分析。

函数如下:

intxa0Chk_CMDend(intxa0cmd,xa0intxa0be_resp)xa0//指令反馈判断函数

{

intxa0finish0;

if(!be_resp)xa0//xa0Noxa0response

{

finish0=rSDICSTA;

while((finish0&0x800)!=0x800)xa0//xa0验证指令是不是发送

finish0=rSDICSTA;

rSDICSTA=finish0;xa0//xa0Clearxa0cmdxa0endxa0state

returnxa01;

}

elsexa0//xa0Withxa0response

{

finish0=rSDICSTA;

while(xa0!(xa0((finish0&0x200)==0x200)xa0|xa0((finish0&0x400)==0x400)xa0))

//xa0验证反馈响应完成

finish0=rSDICSTA;

if(cmd==1xa0|xa0cmd==9xa0|xa0cmd==41)xa0//xa0CRCxa0noxa0check

{

if(xa0(finish0&0xf00)xa0!=xa00xa00xa0)xa0//xa0CRC是否错误

{

rSDICSTA=finish0;xa0//xa0Clearxa0errorxa0state

if(((finish0&0x400)==0x400))xa0//xa0验证超时

returnxa00;xa0}

rSDICSTA=finish0;

//xa0Clearxa0cmdxa0&xa0rspxa0endxa0state

}

elsexa0//xa0CRCxa0check

{

if(xa0(finish0&0x1f00)xa0!=xa00xa00xa0)xa0//xa0Checkxa0error

{

;

rSDICSTA=finish0;xa0//xa0Clearxa0errorxa0state

if(((finish0&0x400)==0x400))

returnxa00;xa0//xa0Timeoutxa0error

}

rSDICSTA=finish0;

}

returnxa01;

}

}

intxa0Chk_DATend(void)

{

intxa0finish;

finish=rSDIDSTA;

while(xa0!(xa0((finish&0x10)==0x10)xa0|xa0((finish&0x20)==0x20)xa0))

//xa0Chekxa0timeoutxa0orxa0dataxa0end

finish=rSDIDSTA;

if(xa0(finish&0xfc)xa0!=xa00x10xa0)

{

rSDIDSTA=0xec;xa0//xa0Clearxa0errorxa0state

returnxa00;

}

returnxa01;

}

intxa0Chk_BUSYend(void)xa0//数据反馈判断函数

{

intxa0finish;

finish=rSDIDSTA;

while(xa0!(xa0((finish&0x08)==0x08)xa0|xa0((finish&0x20)==0x20)xa0))

finish=rSDIDSTA;xa0//等待数据发送完成或超时

if(xa0(finish&0xfc)xa0!=xa00x08xa0)

{

rSD

IDSTA=0xf4;xa0//clearxa0errorxa0state

returnxa00;

}

returnxa01;

}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
瑞萨I3C总线扩展和SPD集线器产品通过基板管理控制器认证