当前位置:文档之家› mini2440SD卡读写驱动程序分析

mini2440SD卡读写驱动程序分析

断断续续的把2440test的sdi.c程序看完了,顺带着写上自己的注释,主要参考2440中文手册第19章SDI部分,还有SD卡读写规范,按照上面的一步一步来做,完成SD卡读取。

SD操作(这个是SD卡读取的核心思想,所有的工作都按照这个最高指示来进行)
串行时钟线同步在五根数据线上的信息移位和采样。传输频率通过设定 SDIPRE 寄存器的相应位的设定来控制。你可以修改频率来调节波特率数据寄存器值。
编程过程(普通)
对 SDI 模块编程,按以下基本步骤:
(1)设置 SDICON 寄存器来配置适当的时钟及中断使能
(2)设置 SDIPRE 寄存器配置适当的值。
(3)等待 74个SDCLK 时钟以初始化卡。

CMD 路径编程
(1)写命令参数 32位到SDICmdArg
(2)决定命令类型并通过设置 SDICmdCon开始命令传输
(3)当 SDICmdSta 的特殊标志被置位,确认 SDICMD 路径操作的结束。
(4)如果命令类型是不相应,标志是 CmdSent。
(5)如果命令类型是相应,标志是 RspFin。
(6)通过对相应位写 1,清除 SDICmdStaD的标志。
数据路径编程
(1)写数据超时期间到 SDIDTimer
(2)写模块大小(模块长度)到 SDIBSize(通常是 0x80字)
(3)确定模块模式,宽总线,DMA等且通过社子 SDIDatCon来开始数据传输
(4)发送数据->写数据到数据寄存器(SDIDAT),当发送 FIFO 有效(TFDET 置位),或一半(TFHalf置位),或空(TFEmpty置位)。
(5)接收数据->从数据寄存器(SDIDAT)读数据,当接收 FIFO 有效(RFDET 置位),或满(RFFull置位)。或一半(RFHalf置位),或准备最后数据(RFLast 置位)。
(6)当 SDIDatSta寄存器的 DatFin标志置位,确认SDIDAT路径操作结束。
(7)通过对相应位写 1,清除 SDIDatSta 的标志。

代码比较长,一篇日志贴不完,贴两篇。

下面先写一下我对SD_Card_Init()的理解。

在Test_SDI()中,先设置rGpEup(设置SD卡读取的波特率),--->rGpECON(设置E口为特殊功能)--->SD_Card_Init(),SD_Card_Init()中,设置rSDIPPE(预分频器)--->字节序B型,SDCLK输出使能,SDIFIFO复位,模块大小设置为512byte,--->再设置rSDIDTIMER(数据/忙定时寄存器),再等待74个SDCLK周期。--->发送CMD0(),CMD0()的作用是使得卡处于IDLE状态,--->chk_SD_OCR(),先发送CMD55(),表明下个命令为特殊命令ACMD,而不是普通的CMD。由ACMD41()协商SD卡读取电压范围。--->发送CMD2()获取每一个卡的唯一标识CID号,--->发送CMD3(),给卡分配RCA,--->发送CMD7(),选中卡,使得卡处于传输状态,--->发送ACMD6(),宽总线选择,选择传输位宽为1位或者4位。

至此,卡的初始化SD_Card_Init()完成。

下面贴上我自己注释的代码。

C CODE :mini2440的2440test程

序中的SD卡读取程序注解(上)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#include
#include
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "sdi.h"

#define INICLK 300000
#define SDCLK 24000000 //PCLK=49.392MHz
#define MMCCLK 15000000 //PCLK=49.392MHz

#define POL 0
#define INT 1
#define DMA 2

int CMD13(void); // Send card status
int CMD9(void);

unsigned int *Tx_buffer; //128[word]*16[blk]=8192[byte]
unsigned int *Rx_buffer; //128[word]*16[blk]=8192[byte]
volatile unsigned int rd_cnt;
volatile unsigned int wt_cnt;
volatile unsigned int block;
volatile unsigned int TR_end=0;

int Wide=0; // 0:1bit, 1:4bit
int MMC=0; // 0:SD , 1:MMC

int Maker_ID;
char Product_Name[7];
int Serial_Num;

volatile int RCA;

void Test_SDI(void)
{
U32 save_rGPEUP, save_rGPECON;

RCA=0;
MMC=0;
block=3072; //3072Blocks=1.5MByte, ((2Block=1024Byte)*1024Block=1MByte)

save_rGPEUP=rGPEUP;
save_rGPECON=rGPECON;


/* SD 分别使用 S3C2440 的复用 IO 端口 GPE7-10 作为 4根数据信号线、使用 GPE6 作命令信号线、
使用 GPE5 作时钟信号线,使用复用端口 GPG8的外部中断功能来作 SD 卡的插拔检测,
使用 GPH8 端口来判断 SD 卡是否写有保护。*/

// SDCMD, SDDAT[3:0] => PU En. 1111 1000 0011 1111 设为0时使能上拉电阻,设为1禁止上拉电阻

rGPEUP = 0xf83f;

rGPECON = 0xaaaaaaaa; //SDCMD, SDDAT[3:0] P143,设置为10,相应

功能定义

Uart_Printf("\nSDI Card Write and Read Test\n");

if(!SD_card_init())
return;

TR_Buf_new(); //发送数据缓冲区初始化(其中也完成了接收缓冲区清0的工作),且发送,接收数据缓冲区都放在内存中

Wt_Block(); //写数据块

Rd_Block(); //读数据块

View_Rx_buf();

if(MMC)
TR_Buf_new();

if(MMC)
{
rSDICON |=(1<<5); // YH 0519, MMC Type SDCLK

Wt_Stream();
Rd_Stream();
View_Rx_buf();
}

Card_sel_desel(0); // Card deselect

if(!CMD9())
Uart_Printf("Get CSD fail!!!\n");

rSDIDCON=0;//tark???
rSDICSTA=0xffff;
rGPEUP=save_rGPEUP;
rGPECON=save_rGPECON;
}

void TR_Buf_new(void) //发送数据缓冲区初始化
{
//-- Tx & Rx Buffer initialize
int i, j;

Tx_buffer=(unsigned int *)0x31000000;

j=0;
for(i=0;i<2048;i++) //128[word]*16[blk]=8192[byte]
*(Tx_buffer+i)=i+j;
Flush_Rx_buf(); //接收数据缓冲区清0

}

void Flush_Rx_buf(void) //接收数据缓冲区清0
{
//-- Flushing Rx buffer
int i;

Rx_buffer=(unsigned int *)0x31800000;

for(i=0;i<2048;i++) //128[word]*16[blk]=8192[byte]
*(Rx_buffer+i)=0;
Uart_Printf("End Rx buffer flush\n");
}

void View_Rx_buf() //查看接收缓冲区数据
{
//-- Display Rx buffer
int i,error=0;

Tx_buffer=(unsigned int *)0x31000000;
Rx_buffer=(unsigned int *)0x31800000;

Uart_Printf("Check Rx data\n");

for(i=0;i<128*block;i++)
{
if(Rx_buffer[i] != Tx_buffer[i])
{
Uart_Printf("\nTx/Rx error\n");
Uart_Printf("%d:Tx-0x%08x, Rx-0x%08x\n",i,Tx_buffer[i], Rx_buffer[i]);
error=1;
break;
}
//Uart_Printf(".");
}

if(!error)
{
Uart_Printf("\nThe Tx_buffer is same to Rx_buffer!\n");
Uart_Printf("SD CARD Write and Read test is OK!\n");
}
}

void View_Tx_buf(void)
{

}

int SD_card_init(void)
{
//-- SD controller & card initialize
int i;

/* Important notice for MMC test condition */
/* Cmd & Data lines must be enabled by pull up resister */

rSDIPRE=PCLK/(INICLK)-1; // 300KHz
Uart_Printf("Init. Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));



/*看2440中文手册,SDI部分,SDICON[8:0] =0b 10001
[4] 当你使用字边界读(写)数据从(到)主FIFO决定字节顺序类型 0:A型 1:B型
[0] 确定是否SDCLK输出使能 0:无效(预定标器关闭)1:时钟使能 */

rSDICON=(1<<4)|1; // Type B, clk enable

/* rSDIFSTA SDI FIFO状态寄存器
[16] FIFO值复位。该位会自动清除 0:正常模式 1:FIFO复位 */

rSDIFSTA=rSDIFSTA|(1<<16); //YH 040223 FIFO reset

/*rSDIBSIZE SDI模块大小寄存器 0x200=0b 0010 0000 0000=512
[11:0] 模块数(0~4095),当流模式时不考虑 */

rSD

IBSIZE=0x200; // 512byte(128word)

/* rSDIDTIMER SDI数据/忙定时器寄存器
[22:0] 数据/忙定时器定时溢出周期 */

rSDIDTIMER=0x7fffff; // Set timeout count

for(i=0;i<0x1000;i++); // Wait 74SDCLK for MMC card

CMD0();
Uart_Printf("In idle\n");

//-- Check MMC card OCR OCR(Operating Conditions Register) 32位的操作条件寄存器存储了VDD电压范围
if(Chk_MMC_OCR())
{
Uart_Printf("In MMC ready\n");
MMC=1;
goto RECMD2;
}

Uart_Printf("MMC check end!!\n"); /*如果检测MMC状态,得出所插入的卡不是MMC,则输出check end*/
//-- Check SD card OCR
if(Chk_SD_OCR())
Uart_Printf("In SD ready\n");

else
{
Uart_Printf("Initialize fail\nNo Card assertion\n");
return 0;
}

/*。ACMD41 命令的响应是卡的操作条件寄存器。相同的命令将发送给系统中所有的卡。
不兼容的卡将进入Inactive状态。

主机然后发送命令 ALL_SEND_CID(CMD2)到每个卡以获取每个卡的唯一标
识 CID号。未识别的卡通过 CMD线发送 CID 号作为响应。当卡发送 CID号后,
进入识别状态(Identification State)*/

RECMD2:
//-- Check attaced cards, it makes card identification state
rSDICARG=0x0; // CMD2(stuff bit)

/* rSDICCON:SDI命令控制寄存器
[10]确定命令类型是否是带数据命令 0: 否,无数据 1:带数据 CMD2为长命令等待应答
[9]确定主机是否等待响应 0: 不等待 1:等待
[8]确定命令是否开始操作 0: 命令就绪 1:命令开始
[7:0]带 2 个开始位的命令索引 设置为:0x42(CMD2) */


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;
rSDICSTA=0xa00; // Clear cmd_end(with rsp)

Uart_Printf("End id\n");

RECMD3:
//--Send RCA
rSDICARG=MMC<<16; // CMD3(MMC:Set RCA, SD:Ask RCA-->SBZ)
/* rSDICCON:SDI命令控制寄存器
[10]确定命令类型是否是带数据命令 0: 否,无数据 1:带数据 CMD2为长命令等待应答
[9]确定主机是否等待响应 0: 不等待 1:等待
[8]确定命令是否开始操作 0: 命令就绪 1:命令开始
[7:0]带 2 个开始位的命令索引 设置为:0x43(CMD3) */

rSDICCON=(0x1<<9)|(0x1<<8)|0x43; // sht_resp, wait_resp, start, CMD3

//-- Check end of CMD3
if(!Chk_CMDend(3, 1))
goto RECMD3;
rSDICSTA=0xa00; // Clear cmd_end(with rsp)

//--Publish RCA
if(MMC)
{
RCA=1;
rSDIPRE=(PCLK/MMCCLK)-1;
Uart_Printf("MMC Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));
}
else
{
/*根据 SD 规范,rSDIRSP0 高 16 位存储 RCA,低 16 位存储 CARD 的状态*/
RCA=( rSDIR

SP0 & 0xffff0000 )>>16;

Uart_Printf("RCA=0x%x\n",RCA);

rSDIPRE=PCLK/(SDCLK)-1; // Normal clock=25MHz

Uart_Printf("SD Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));
} //--State(stand-by) check
if( rSDIRSP0 & 0x1e00!=0x600 ) // CURRENT_STATE check
goto RECMD3;

Uart_Printf("In stand-by\n");


Card_sel_desel(1); // Select

if(!MMC)
Set_4bit_bus();
else
Set_1bit_bus();

return 1;
}



void Card_sel_desel(char sel_desel)
{
//-- Card select or deselect

/*CMD7 用来选择一个卡并将它置于传输状态(Transfer state),
在任何时间只能有一个卡处于传输状态。*/


if(sel_desel)
{
RECMDS7:

/*CMD7:[31:16]用RCA作为填充位,[15:0]无用*/
rSDICARG=RCA<<16; // CMD7(RCA,stuff bit)

/* rSDICCON:SDI命令控制寄存器
[9]确定主机是否等待响应 0: 不等待 1:等待
[8]确定命令是否开始操作 0: 命令就绪 1:命令开始
[7:0]带 2 个开始位的命令索引 设置为:0x47(CMD7) */

rSDICCON= (0x1<<9)|(0x1<<8)|0x47; // sht_resp, wait_resp, start, CMD7

//-- Check end of CMD7
if(!Chk_CMDend(7, 1))
goto RECMDS7;
rSDICSTA=0xa00; // Clear cmd_end(with rsp)

//--State(transfer) check
if( rSDIRSP0 & 0x1e00!=0x800 )
goto RECMDS7;
}
else
{
RECMDD7:
rSDICARG=0<<16; //CMD7(RCA,stuff bit)
rSDICCON=(0x1<<8)|0x47; //no_resp, start, CMD7

//-- Check end of CMD7
if(!Chk_CMDend(7, 0))
goto RECMDD7;
rSDICSTA=0x800; // Clear cmd_end(no rsp)
}
}

//**********************【Rd_Int】**********************************************************************************

void __irq Rd_Int(void)
{
U32 i,status;

status=rSDIFSTA;
if( (status&0x200) == 0x200 ) // Check Last interrupt?
{
for(i=(status & 0x7f)/4;i>0;i--)
{
*Rx_buffer++=rSDIDAT;
rd_cnt++;
}
rSDIFSTA=rSDIFSTA&0x200; //Clear Rx FIFO Last data Ready, YH 040221
}
else if( (status&0x80) == 0x80 ) // Check Half interrupt?
{
for(i=0;i<8;i++)
{
*Rx_buffer++=rSDIDAT;
rd_cnt++;
}
}

ClearPending(BIT_SDI);
}

//*************************【Wt_Int】****************************************************************************************

void __irq Wt_Int(void)
{
ClearPending(BIT_SDI);

rSDIDAT=*Tx_buffer++;
wt_cnt++;

if(wt_cnt==128*block)
{
rINTMSK |= BIT_SDI;
rSDIDAT=*Tx_buffer;
TR_end=1;
}
}

//***************************【DMA_end】******************************************************************************

void __irq DMA_end(void)
{
ClearPending(BIT_DMA0);

TR_end=1;
}

//***************************

【Rd_Block】******************************************************************************
void Rd_Block(void)
{
U32 mode;
int status;

rd_cnt=0;
Uart_Printf("Block read test[ Polling read ]\n");

mode = 0 ;

rSDIFSTA=rSDIFSTA|(1<<16); // FIFO reset FIFO复位

if(mode!=2)

/*rSDIDCON SDI数据控制寄存器
[20]:确定是否在接收到响应后开始数据传输0: DatMode设置后开始 1:接收到响应后开始(假设DatMode设置为11)
[17]:数据传输模式 0: 流模式 1:块模式
[16]:使能宽总线 0:标准总线(只使用SDIDAT[0]) 1:宽总线模式(使用SDIDAT[3:0] )
[14]:确定是否允许强制停止 0:标准(normal) 1:强制停止
[12]:数据传输方向 00=ready 01=only busy check start
10=data receive start 11=data transmit start
[11:0]:块数目(0~4095),在流模式中无用

//设置数据控制寄存器:字传输,块数据传输,4bit 数据传输,开始数据传输,
数据发送模式,共写 block 个块 */

rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)|(2<<12)|(block<<0); //YH 040220

rSDICARG=0x0; // CMD17/18(addr)

RERDCMD:
switch(mode)
{
case POL:
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;
}

rSDICSTA=0xa00; // Clear cmd_end(with rsp)

while(rd_cnt<128*block) // 512*block bytes
{
if((rSDIDSTA&0x20)==0x20) // Check timeout
{
rSDIDSTA=(0x1<<0x5); // Clear timeout flag
break;
}
status=rSDIFSTA;
/*rSDIFSTA:SDI FIFO状态寄存器
[12]:该位指出FIFO数据对接收有效,当DatMode是数据接收模式,
如果DMA模式有效,SD主设备请求DMA操作。
0:不侦测(FIFO空)1:侦测(1if((status&0x1000)==0x1000) // Is Rx data?
{
*Rx_buffer++=rSDIDAT;
rd_cnt++;
}
}
break;

case INT:
pISR_SDI=(unsigned)Rd_Int;
rINTMSK = ~(BIT_SDI);
/* rSDIIMSK:SDI中断屏蔽寄存器
[3]:如果发送FIFO空,决定SDI产生中断。 0=无效,1= 中断使能
[0]:如果接收FIFO半满,决定SDI产生中断。0=无效,1= 中断使能*/
rSDIIMSK=5; // Last & Rx FIFO half int.

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;
}

rSDICSTA=0xa00; // Clear cmd_end(with rsp)

while(rd_cnt<128*block);

rINTMSK |= (BIT_SDI);
rSDIIMSK=0; // All mask
break;

case DMA:
pISR_DMA0=(unsigned)DMA_end;
rINTMSK = ~(BIT_DMA0);
rSDIDCON=rSDIDCON|(1<<24); //YH 040227, Burst4 Enable

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;

rDMASKTRIG0=(0<<2)+(1<<1)+0; //no-stop, DMA2 channel on, no-sw trigger

rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<15)|(1<<14)|(2<<12)|(block<<0);
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;
}

rSDICSTA=0xa00; // Clear cmd_end(with rsp)
while(!TR_end);
//Uart_Printf("rSDIFSTA=0x%x\n",rSDIFSTA);
rINTMSK |= (BIT_DMA0);
TR_end=0;
rDMASKTRIG0=(1<<2); //DMA0 stop
break;

default:
break;
}
//-- Check end of DATA
if(!Chk_DATend())
Uart_Printf("dat error\n");

rSDIDCON=rSDIDCON&~(7<<12);
rSDIFSTA=rSDIFSTA&0x200; //Clear Rx FIFO Last data Ready, YH 040221
rSDIDSTA=0x10; // Clear data Tx/Rx end detect

if(block>1)
{
RERCMD12: //当数据读取完毕之后,通过调用CMD12来停止数据的读取
//--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;
rSDICSTA=0xa00; // Clear cmd_end(with rsp)
}
}



int Chk_CMDend(int cmd, int be_resp) //判断命令cmd是否发送完毕
//0: Timeout
{
int finish0;

if(!be_resp) // No response
{


/* rSDICSTA SDI命令状态寄存器
[11] 命令发送(不包括响应)。通过对该位置 1,该标志被清除。0:不侦测 1:命令结束
(finish0&0x800)!=0x800,判断rSDICSTA 第11位是否为1,不为1,一直循环,直到为1,退出循环 */

finish0=rSDICSTA;
while((finish0&0x800)!=0x800) // Check cmd end
finish0=rSDICSTA;

rSDICSTA=finish0;// Clear cmd end state 对该位置 1,该标志被清除。

return 1;
}
else // With response
{
finish0=rSDICSTA;

/*rSDICSTA SDI命令状态寄存器
[9]响应接收结束,该位通过写1清0 0: 无 1:响应结束

[10]命令响应超时(64clk),该位通过写 1 清 0 0: 无 1:超时
(finish0&0x200)==0x200)当rSDICSTA第9位为0,且(finish0&0x400)==0x400)rSDICSTA第10位也为0时,一直循环,
直到这两者中有一个为1,退出循环。
*/
while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x400) )) // Check cmd/rsp end

finish0=rSDICSTA;

if(cmd==1 | cmd==41) // CRC no check, CMD9 is a long Resp. command.

{
/* rSDICSTA SDI命令状态寄存器
[12] 当接收到命令响应时 CRC 校验是否失败,该位通过写 1 清 0 0: 无 1:失败
(finish0&0xf00) != 0xa00意思是:当位[12]=1时,使得(finish0&0xf00) != 0xa00,即crc校验失败。

*/
if( (finish0&0xf00) != 0xa00 ) // Check error
{
rSDICSTA=finish0; // Clear error state

if(((finish0&0x400)==0x400))
return 0; // Timeout error
}
rSDICSTA=finish0; // Clear cmd & rsp end state
}
else // CRC check
{
if( (finish0&0x1f00) != 0xa00 ) // Check error
{
Uart_Printf("CMD%d:rSDICSTA=0x%x, rSDIRSP0=0x%x\n",cmd, rSDICSTA, rSDIRSP0);
rSDICSTA=finish0; // Clear error state

if(((finish0&0x400)==0x400))
return 0; // Timeout error
}
rSDICSTA=finish0;
}
return 1;
}
}

int Chk_DATend(void) //判断数据是否发送完毕
{
int finish;
/*rSDIDSTA: SDI数据状态寄存器
((finish&0x10)==0x10) | ((finish&0x20)==0x20) )只要有一个满足为1,则推出while循环,
[5]:数据/忙接收超时。通过对该位置 1清除标志 0:不侦测 1:超时
[4]:数据传输结束(数据计数器为 0)。通过对该位置 1清除标志。
0:不侦测 1:数据完成侦测. */
finish=rSDIDSTA;
while( !( ((finish&0x10)==0x10) | ((finish&0x20)==0x20) ))
// Chek timeout or data end
finish=rSDIDSTA;
/*rSDIDSTA: SDI数据状态寄存器
(finish&0xfc) != 0x10),用来确定[4]是否为1
[4]:数据传输结束(数据计数器为 0)。通过对该位置 1清除标志。
0:不侦测 1:数据完成侦测
*/
if( (finish&0xfc) != 0x10 )
{
Uart_Printf("DATA:finish=0x%x\n", finish);
rSDIDSTA=0xec; // Clear error state
return 0;
}
return 1;
}

int Chk_BUSYend(void)
{
int finish;

finish=rSDIDSTA;

/*rSDIDSTA: SDI数据状态寄存器
((finish&0x08)==0x08) | ((finish&0x20)==0x20) )只要有一个满足为1,则推出while循环,
[3]:仅忙检查完成。通过对该位置 1清除标志。
0:不检测 1:侦测忙完成
[4]:数据传输结

束(数据计数器为 0)。通过对该位置 1清除标志。
0:不侦测 1:数据完成侦测. */

while( !( ((finish&0x08)==0x08) | ((finish&0x20)==0x20) ))
finish=rSDIDSTA;

if( (finish&0xfc) != 0x08 )
{
Uart_Printf("DATA:finish=0x%x\n", finish);
rSDIDSTA=0xf4; //clear error state
return 0;
}
return 1;
}

void CMD0(void) /*CMD0的作用是使得卡处在空闲状态 */
{
//-- Make card idle state
rSDICARG=0x0; // CMD0(stuff bit)填充位


/* rSDICCON SDI命令控制寄存器,
[8]:决定命令操作是否开始。该位自动清零。0= 命令准备好,1= 命令开始
[7:0] 有开始两位的命令索引(8bit) 0x40=0b0100 0000 */


rSDICCON=(1<<8)|0x40; // No_resp, start, CMD0

//-- Check end of CMD0
Chk_CMDend(0, 0);
rSDICSTA=0x800; // Clear cmd_end(no rsp)
}

int Chk_MMC_OCR(void)
{
int i;

//-- Negotiate operating condition for MMC, it makes card ready state
for(i=0;i<100;i++) //Negotiation time is dependent on CARD Vendors.
{
//rSDICARG=0xffc000; //CMD1(MMC OCR:2.6V~3.6V)

/* rSDICARG SDI命令参数寄存器
0xff8000:1111 1111 1000 0000 0000 0000
3.6------2.7V */


rSDICARG=0xff8000; //CMD1(SD OCR:2.7V~3.6V)

/* rSDICCON:SDI命令控制寄存器
[9]确定主机是否等待响应 0: 不等待 1:等待
[8]确定命令是否开始操作 0: 命令就绪 1:命令开始
[7:0]带 2 个开始位的命令索引 设置为:0x41(CMD1) */

rSDICCON=(0x1<<9)|(0x1<<8)|0x41; //sht_resp, wait_resp, start, CMD1

//-- Check end of CMD1
//if(Chk_CMDend(1, 1) & rSDIRSP0==0x80ffc000) //[31]:Card Power up status bit (busy)
//0xffc000 is Voltage window

if(Chk_CMDend(1, 1) && (rSDIRSP0>>16)==0x80ff) //YH 0903 [31]:Card Power up status bit (busy)
//if(Chk_CMDend(1, 1) & rSDIRSP0==0x80ff8000)
{
rSDICSTA=0xa00; // Clear cmd_end(with rsp)
return 1; // Success
}
}
rSDICSTA=0xa00; // Clear cmd_end(with rsp)
return 0; // Fail
}

int Chk_SD_OCR(void)
{
int i;

//-- Negotiate operating condition for SD, it makes card ready state
for(i=0;i<50;i++) //If this time is short, init. can be fail.
{
CMD55(); // Make ACMD 送 CMD55,表示下个命令将是特殊功能命令 acmd,而非一般命令 cmd

/* rSDICARG SDI命令参数寄存器
0xff8000:1111 1111 1000 0000 0000 0000
3.6------2.7V */
rSDICARG=0xff8000; //ACMD41(SD OCR:2.7V~3.6V)

/* rSDICCON:SDI命令控制寄存器
[9]确定主机是否等待响应 0: 不等待 1:等待
[8]确定命令是否开始操作 0: 命令就绪 1:命令开始
[7:0]带 2 个开始位的命令

索引 设置为:0x69 ACMD41 */
/*关于ACMD41:。ACMD41 命令是一个特殊的同步命令,用来协商操作电压范围,并轮询所有的卡。
除了操作电压信息,ACMD41 的响应还包括一个忙标志,表明卡还在 power-up 过程工作,
还没有准备好识别操作,即告诉主机卡还没有就绪。主机等待(继续轮询)直到忙标志清除。*/


rSDICCON=(0x1<<9)|(0x1<<8)|0x69;//sht_resp, wait_resp, start, ACMD41


//-- Check end of ACMD41


/*rSDIRSP0 SDI响应寄存器 0
[31:0]卡状态[31:0](短格式);卡状态[127:96](长格式) */

if( Chk_CMDend(41, 1) & rSDIRSP0==0x80ff8000 )
{
rSDICSTA=0xa00; // Clear cmd_end(with rsp)

return 1; // Success
}
Delay(200); // Wait Card power up status
}
//Uart_Printf("SDIRSP0=0x%x\n",rSDIRSP0);
rSDICSTA=0xa00; // Clear cmd_end(with rsp)
return 0; // Fail
}

int CMD55(void)
{
//--Make ACMD CMD55,表示下个命令将是特殊功能 acmd,而非一般命令 cmd
rSDICARG=RCA<<16; //CMD7(RCA,stuff bit)

/* rSDICCON:SDI命令控制寄存器
[9]确定主机是否等待响应 0: 不等待 1:等待
[8]确定命令是否开始操作 0: 命令就绪 1:命令开始
[7:0]带 2 个开始位的命令索引 设置为:0x77 CMD55 */
rSDICCON=(0x1<<9)|(0x1<<8)|0x77; //sht_resp, wait_resp, start, CMD55

//-- Check end of CMD55
if(!Chk_CMDend(55, 1))
return 0;

rSDICSTA=0xa00; // Clear cmd_end(with rsp)
return 1;
}

int CMD13(void)//SEND_STATUS
{
int response0;

rSDICARG=RCA<<16; // CMD13(RCA,stuff bit)
rSDICCON=(0x1<<9)|(0x1<<8)|0x4d; // sht_resp, wait_resp, start, CMD13

//-- Check end of CMD13
if(!Chk_CMDend(13, 1))
return 0;
//Uart_Printf("rSDIRSP0=0x%x\n", rSDIRSP0);
if(rSDIRSP0&0x100)
//Uart_Printf("Ready for Data\n");
// else
//Uart_Printf("Not Ready\n");
response0=rSDIRSP0;
response0 &= 0x3c00;
response0 = response0 >> 9;
//Uart_Printf("Current Status=%d\n", response0);
if(response0==6)
Test_SDI();

rSDICSTA=0xa00; // Clear cmd_end(with rsp)
return 1;
}

int CMD9(void)//SEND_CSD
{
rSDICARG=RCA<<16; // CMD9(RCA,stuff bit)
rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x49; // long_resp, wait_resp, start, CMD9

Uart_Printf("\nCSD register :\n");
//-- Check end of CMD9
if(!Chk_CMDend(9, 1))
return 0;

Uart_Printf("SDIRSP0=0x%x\nSDIRSP1=0x%x\nSDIRSP2=0x%x\nSDIRSP3=0x%x\n", rSDIRSP0,rSDIRSP1,rSDIRSP2,rSDIRSP3);
return 1;
}

void Set_1bit_bus(void)
{
Wide=0;
if(!MMC)
SetBus();
//Uart_Printf("\n****1bit bus****\n");
}

void Set_4bit_bus(void)
{
Wide=1;
SetBus();
//Uart_Printf("\n****4bit bus****\n");
}

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;
rSDICSTA=0xa00; // Clear cmd_end(with rsp)
}

void Set_Prt(void)
{
//-- Set protection addr.0 ~ 262144(32*16*512)
Uart_Printf("[Set protection(addr.0 ~ 262144) test]\n");

RECMD28:
//--Make ACMD
rSDICARG=0; // CMD28(addr)
rSDICCON=(0x1<<9)|(0x1<<8)|0x5c; //sht_resp, wait_resp, start, CMD28

//-- Check end of CMD28
if(!Chk_CMDend(28, 1))
goto RECMD28;
rSDICSTA=0xa00; // Clear cmd_end(with rsp)
}

void Clr_Prt(void)
{
//-- Clear protection addr.0 ~ 262144(32*16*512)
//Uart_Printf("[Clear protection(addr.0 ~ 262144) test]\n");

RECMD29:
//--Make ACMD
rSDICARG=0; // CMD29(addr)
rSDICCON=(0x1<<9)|(0x1<<8)|0x5d; //sht_resp, wait_resp, start, CMD29

//-- Check end of CMD29
if(!Chk_CMDend(29, 1))
goto RECMD29;
rSDICSTA=0xa00; // Clear cmd_end(with rsp)
}

相关主题
文本预览
相关文档 最新文档