您的位置:首页 > 编程语言

基于S3C2440——SD/MMC

2012-04-20 20:40 357 查看
下面内容是转载一为网友的内容:http://blog.163.com/zhouhui_1102/blog/static/1504807482011513724255/
之前在http://blog.163.com/zhouhui_1102/blog/static/1504807482011429115933380/,也就是我的SD卡笔记上说了一些需要主要的地方。在这里关于SD和MMC的基础概念我就不提了。一般百科会有相关的知识,可以自行搜索。

这里就笔记上提出来的那两个编程流程图来进行编程。如果还不了解的可以自行查阅我的笔记,或者自己下载SD的datasheet。里面有很详细的说明。

这里说明下我的硬件配置是:2440板子,2G Kingston SD卡。

废话不多说,直接看源码。

###########################################
//------------------------SDI.h------------------------

#ifndef __SDI_H__
#define __SDI_H__

#define U32 unsigned int
#define U16 unsigned short
#define U8  unsigned char
#define PCLK  50000000
typedef struct SD_STRUCT
{
U8 sdiWide; // 0:1bit, 1:4bit
U8 sdiType;  // 0:SD  , 1:MMC
U16 sdiRCA;
U8 cCardCID[16]; // 卡的CID信息
U32 lCardCSD[4]; // 卡的CSD信息
U32 lSectorSize; /* 一次可擦除的块个数 */
U32 lCardSize; //卡容量(单位:字节)
}sdi_set;  //卡的信息结构体

void test_sdi();
U8 sdi_init();
U32 SDI_Check_CMD_End(int cmd, int be_resp);
void CMD0(void);
U8 CMD1(void);
U8 CMD2(U8 *cCID_Info);
U8 CMD3(U16 iCardType,U16 *iRCA);
U8 CMD7(U8 cSorD,U16 iRCA);
U8 CMD9(U16 iRCA,U32 *lCSD);
U8 CMD12(void);
U16 CMD13(U16 iRCA);
U8 CMD17(U32 Addr);
U8 CMD18(U32 Addr);
U8 CMD24(U32 Addr);
U8 CMD25(U32 Addr);
U8 CMD55(U16 iRCA);
U8 ACMD6(U8 BusWidth,U16 iRCA);
U8 ACMD41(U16 iRCA);
U32 SDI_MMC_OCR(void);
U32 SDI_SD_OCR(void);
U8 select_or_deselect(U8 cSelDesel,U16 iCardRCA);
U8 Set_bus_Width(U8 cCardType,U8 cBusWidth,U16 iRCA);
U8 Read_Block(U32 Addr,U32* RxBuffer,U32 block_num);
U8 Write_Block(U32 Addr,U32* TxBuffer,U32 block_num);
void Delay(U32 i);
#endif

##############################################


########################################
//------------------------SDI.c------------------------

#define _SD_DEBUG_
#define SDCARD_BUFF_SIZE 512

U8 cTxBuffer[SDCARD_BUFF_SIZE];
U8 cRxBuffer[SDCARD_BUFF_SIZE];
sdi_set SDCard;

void test_sdi()  //测试函数
{
U32 i;
if(sdi_init())
{
#ifdef _SD_DEBUG_
printf("SDI初始化结束!\r\n");
#endif
}
else
{
#ifdef _SD_DEBUG_
printf("SDI初始化出错,终止!\r\n");
#endif
return;
}
for(i=0;i<512;i++)
{
cTxBuffer[i]=i+1;
cRxBuffer[i]=0;
}

if(Write_Block(0,(U32 *)cTxBuffer,1))
{
#ifdef _SD_DEBUG_
printf("\r\n写入SD卡0地址数据成功!");
#endif
}
else
{
#ifdef _SD_DEBUG_
printf("\r\n写入SD卡0地址数据出错,终止!");
#endif
return;
}
if(Read_Block(0,(U32 *)cRxBuffer,1))
{
#ifdef _SD_DEBUG_
printf("\r\n读出SD卡0地址数据成功!");
#endif
printf("\r\n读出的数据:\r\n");
for(i=0;i<512;i+=4)
{
if(i%32)
printf("\r\n");
printf("0x%x ",cRxBuffer[i]);
printf("0x%x ",cRxBuffer[i+1]);
printf("0x%x ",cRxBuffer[i+2]);
printf("0x%x ",cRxBuffer[i+3]);

}
}
else
{
#ifdef _SD_DEBUG_
printf("\r\n读出SD卡0地址数据出错,终止!");
#endif
return;
}
select_or_deselect(0,SDCard.sdiRCA);
}

U8 sdi_init()
{
int i;
#ifdef _SD_DEBUG_
printf("\r\nSDI初始化开始!");
#endif
GPEUP  = 0xf83f;     // The pull up  1111 1000 0011 1111  必须上拉
GPECON = 0xaaaaaaaa;  // 1010 1010 1010 1010 1010 1010 1010 1010
SDICSTA = 0xffff;   //SDI指令状态
SDIDSTA = 0xffff;//SDI数据状态

SDIPRE = 124; // 400KHz  波特率设置 频率 PCLK/400K -1
SDICON=(1<<4)|1; // Type B,  clk enable SDI控制
SDIFSTA|=1<<16; //FIFO reset
SDIBSIZE=0x200; // 512byte(128word)  SDI块大小
SDIDTIMER=0x7fffff; // Set timeout count 数据传输超时时间
//等待74个CLK
for(i=0;i<0x1000;i++);

CMD0(); //先执行CMD0,复位
//判断卡的类型
if(SDI_MMC_OCR())
{
SDCard.sdiType = 1;  //卡为MMC
}
else
{
SDCard.sdiType = 0;  //卡为SD
}
//检测SD卡
if(SDI_SD_OCR())  //检测SD
{
#ifdef _SD_DEBUG_
printf("SD is ready\r\n");
#endif
} else{
#ifdef _SD_DEBUG_
printf("Initialize fail\r\nNo Card assertion\r\n");
#endif
return 0;
}
//读CID
if(CMD2(SDCard.cCardCID))
{
#ifdef _SD_DEBUG_
printf("CID\r\n");
printf("MID = %d\r\n",SDCard.cCardCID[0]);
printf("OLD = %d\r\n",(SDCard.cCardCID[1]*0X100)+SDCard.cCardCID[2]);
printf("生产厂家:%s\r\n",(SDCard.cCardCID+3));
printf("生产日期:20%d,%d\r\n",((SDCard.cCardCID[13]&0x0f)<<4)+((SDCard.cCardCID[14]&0xf0)>>4),(SDCard.cCardCID[14]&0x0f));
#endif
}
else
{
#ifdef _SD_DEBUG_
printf("Read Card CID is fail!\r\n");
#endif
return 0;
}
//设置RCA  MMC的RCA=1   SD的RCA=0
if(SDCard.sdiType==1)  //MMC
{
if(CMD3(1,&SDCard.sdiRCA))
{
SDCard.sdiRCA = 1;
SDIPRE = 2;  //16MHZ
#ifdef _SD_DEBUG_
printf("MMC Card RCA = 0x%x\r\n",SDCard.sdiRCA);
printf("MMC Frequency is %dHz\r\n",(PCLK/(SDIPRE+1)));
#endif
}
else
{
#ifdef _SD_DEBUG_
printf("Read MMC RCA is fail!\r\n");
#endif
return 0;
}
}
else   //SD
{
if(CMD3(0,&SDCard.sdiRCA))
{
SDIPRE = 1; // Normal clock=25MHz
#ifdef _SD_DEBUG_
printf("SD Card RCA = 0x%x\r\n",SDCard.sdiRCA);
printf("SD Frequency is %dHz\r\n",(PCLK/(SDIPRE+1)));
#endif
}
else
{
#ifdef _SD_DEBUG_
printf("Read SD RCA is fail!\r\n");
#endif
return 0;
}
}
//读CSD
if(CMD9(SDCard.sdiRCA,SDCard.lCardCSD))
{
SDCard.lCardSize = (((SDCard.lCardCSD[1]&0x0000003f)<<16)+((SDCard.lCardCSD[2]&0xffff0000)>>16)+1)*512;
SDCard.lSectorSize = ((SDCard.lCardCSD[2]>>6)&0x0000007f)+1;
#ifdef _SD_DEBUG_
printf("Read Card CSD OK!\r\n");
printf("0x%08x\r\n",SDCard.lCardCSD[0]);
printf("0x%08x\r\n",SDCard.lCardCSD[1]);
printf("0x%08x\r\n",SDCard.lCardCSD[2]);
printf("0x%08x\r\n",SDCard.lCardCSD[3]);
printf(
4000
"卡容量为:%dKB,%dMB\r\n",SDCard.lCardSize,SDCard.lCardSize/1024);
#endif
}
else
{
#ifdef _SD_DEBUG_
printf("Read Card CSD Fail!\r\n");
#endif
return 0;
}
//选中卡  CMD7  进入传输状态
if(select_or_deselect(1,SDCard.sdiRCA))//1表示选中卡
{
#ifdef _SD_DEBUG_
printf("Card sel desel OK!\r\n");
#endif
}
else
{
#ifdef _SD_DEBUG_
printf("Card sel desel fail!\r\n");
#endif
return 0;
}
//CMD13 查询是否为传输状态
while((CMD13(SDCard.sdiRCA)&0x1e00) != 0x800);
//设置总线带宽 ACMD6
if(Set_bus_Width(SDCard.sdiType,1,SDCard.sdiRCA))
{
SDCard.sdiWide = 1;
#ifdef _SD_DEBUG_
printf("Bus Width is 4bit\r\n");
#endif
}
else
{
SDCard.sdiWide = 0;
#ifdef _SD_DEBUG_
printf("Bus Width is 1bit\r\n");
#endif
}
return 1;
}

U32 SDI_Check_CMD_End(int cmd, int be_resp)  //检查CMD是否结束
{
int finish0;

if(!be_resp)    // No response
{
finish0=SDICSTA;
while((finish0&0x800)!=0x800) // Check cmd end
finish0=SDICSTA;

SDICSTA=finish0;// Clear cmd end state

#ifdef _SD_DEBUG_
printf("%x\r\n", finish0);
#endif

return 1;
}
else // With response
{
finish0=SDICSTA;
while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x400) ))    // Check cmd/rsp end
finish0=SDICSTA;

#ifdef _SD_DEBUG_
printf("CMD%d:SDICSTA=0x%x, SDIRSP0=0x%x\r\n",cmd, SDICSTA, SDIRSP0);
#endif

if(cmd==1 | cmd==9 | cmd==41) // CRC no check
{
if( (finish0&0xf00) != 0xa00 )  // Check error
{
SDICSTA=finish0;   // Clear error state

if(((finish0&0x400)==0x400))
{
#ifdef _SD_DEBUG_
printf("CMD%d Time out!\r\n", cmd);
#endif
return 0; // Timeout error
}

}
SDICSTA=finish0; // Clear cmd & rsp end state
// printf("%x\r\n", finish0);
}
else // CRC check
{
if( (finish0&0x1f00) != 0xa00 ) // Check error
{
SDICSTA=finish0;   // Clear error state

if(((finish0&0x400)==0x400))
{
#ifdef _SD_DEBUG_
printf("CMD%d Time out!\r\n", cmd);
#endif
return 0; // Timeout error
}
}
SDICSTA=finish0;
}
return 1;
}
}

//复位,使卡进入IDEL状态
void CMD0(void)
{
SDICARG = 0x0;
SDICCON = (1<<8)|0x40; // No_resp, start

SDI_Check_CMD_End(0, 0);
SDICSTA = 0x800; // Clear cmd_end(no rsp)
}

//设置工作电压是根据SD的OCR寄存器来设置
U8 CMD1(void)
{
SDICARG = 0xff8000; //(SD OCR:2.7V~3.6V)
SDICCON = (0x1<<9)|(0x1<<8)|0x41; //sht_resp, wait_resp, start,

if(SDI_Check_CMD_End(1, 1)) //[31]:Card Power up status bit (busy)
{
if((SDIRSP0>>16)==0x80ff)
{
SDICSTA = 0xa00; // Clear cmd_end(with rsp)
return 1; // Success
}
else
return 0;
}
return 0;
}
//请求设备在CMD上传送CID
U8 CMD2(U8 *cCID_Info)
{
SDICARG = 0x0;
SDICCON = (0x1<<10)|(0x1<<9)|(0x1<<8)|0x42; //lng_resp, wait_resp, start

if(!SDI_Check_CMD_End(2, 1))
return 0;
*(cCID_Info+0) = SDIRSP0>>24;
*(cCID_Info+1) = SDIRSP0>>16;
*(cCID_Info+2) = SDIRSP0>>8;
*(cCID_Info+3) = SDIRSP0;
*(cCID_Info+4) = SDIRSP1>>24;
*(cCID_Info+5) = SDIRSP1>>16;
*(cCID_Info+6) = SDIRSP1>>8;
*(cCID_Info+7) = SDIRSP1;
*(cCID_Info+8) = SDIRSP2>>24;
*(cCID_Info+9) = SDIRSP2>>16;
*(cCID_Info+10) = SDIRSP2>>8;
*(cCID_Info+11) = SDIRSP2;
*(cCID_Info+12) = SDIRSP3>>24;
*(cCID_Info+13) = SDIRSP3>>16;
*(cCID_Info+14) = SDIRSP3>>8;
*(cCID_Info+15) = SDIRSP3;
SDICSTA = 0xa00; // Clear cmd_end(with rsp)
return 1;
}
//给SD卡设定一个相对地址,也就是寻址的地址 = 0:SD卡,=1:MMC卡 =0 失败 =1 成功
U8 CMD3(U16 iCardType,U16 *iRCA)
{
SDICARG = iCardType<<16;     // (MMC:Set RCA, SD:Ask RCA-->SBZ)
SDICCON = (0x1<<9)|(0x1<<8)|0x43; // sht_resp, wait_resp, start

if(!SDI_Check_CMD_End(3, 1))
return 0;
SDICSTA=0xa00; // Clear cmd_end(with rsp)

if(iCardType)
{
*iRCA = 1;
}
else
{
*iRCA =( SDIRSP0 & 0xffff0000 )>>16;
}
if( SDIRSP0 & 0x1e00!=0x600 )   // CURRENT_STATE check
return 0;
else
return 1;
}

//选中卡或者解除选中 cSorD=1为选中 为0则解除选中
U8 CMD7(U8 cSorD,U16 iRCA)
{
if(cSorD)
{
SDICARG = iRCA<<16; // (RCA,stuff bit)
SDICCON = (0x1<<9)|(0x1<<8)|0x47;   // sht_resp, wait_resp, start
if(!SDI_Check_CMD_End(7, 1))
return 0;
SDICSTA = 0xa00; // Clear cmd_end(with rsp)
//--State(transfer) check
if( SDIRSP0 & 0x1e00!=0x800 )
return 0;
else
return 1;
}
else
{
SDICARG = 0<<16; //(RCA,stuff bit)
SDICCON = (0x1<<8)|0x47; //no_resp, start

if(!SDI_Check_CMD_End(7, 0))
return 0;
SDICSTA = 0x800; //Clear cmd_end(no rsp)
return 1;
}
}
//获取卡的CSD寄存器的值
U8 CMD9(U16 iRCA,U32 *lCSD)
{
SDICARG = iRCA<<16; // (RCA,stuff bit)
SDICCON = (0x1<<10)|(0x1<<9)|(0x1<<8)|0x49; // long_resp, wait_resp, start

if(!SDI_Check_CMD_End(9, 1))
return 0;

*(lCSD+0) = SDIRSP0;
*(lCSD+1) = SDIRSP1;
*(lCSD+2) = SDIRSP2;
*(lCSD+3) = SDIRSP3;
return 1;
}

//停止数据传输
U8 CMD12(void)
{
SDICARG = 0x0;
SDICCON = (0x1<<9)|(0x1<<8)|0x4c; //sht_resp, wait_resp, start,

if(!SDI_Check_CMD_End(12, 1))
return 0;
else
SDICSTA = 0xa00; //Clear cmd_end(with rsp)
return 1;
}
//获取卡内状态
U16 CMD13(U16 iRCA)
{
SDICARG = iRCA<<16; // (RCA,stuff bit)
SDICCON = (0x1<<9)|(0x1<<8)|0x4d; // sht_resp, wait_resp, start

if(!SDI_Check_CMD_End(13, 1))
return 0;

SDICSTA=0xa00; // Clear cmd_end(with rsp)
return SDIRSP0;
}

//读取一个数据块
U8 CMD17(U32 Addr)
{
//STEP1:发送指令
SDICARG = Addr; //设定指令参数
SDICCON = (1<<9)|(1<<8)|0x51; //发送CMD17指令

if(SDI_Check_CMD_End(17,1))
return 1;
else
return 0;
}

//读取多个数据块
U8 CMD18(U32 Addr)
{
//STEP1:发送指令
SDICARG = Addr; //设定指令参数
SDICCON = (1<<9)|(1<<8)|0x52; //发送CMD18指令

if(SDI_Check_CMD_End(18,1))
return 1;
else
return 0;
}

//写入一个数据块
U8 CMD24(U32 Addr)
{
//STEP1:发送指令
SDICARG = Addr; //设定指令参数
SDICCON = (1<<9)|(1<<8)|0x58; //发送CMD24指令

if(SDI_Check_CMD_End(24,1))
return 1;
else
return 0;
}
//写入多个数据块
U8 CMD25(U32 Addr)
{
//STEP1:发送指令
SDICARG = Addr; //设定指令参数
SDICCON = (1<<9)|(1<<8)|0x59; //发送CMD25指令

if(SDI_Check_CMD_End(25,1))
return 1;
else
return 0;
}
//检测是否有卡,执行ACMD必须先执行CMD55
U8 CMD55(U16 iRCA)
{
SDICARG = iRCA<<16;
SDICCON = (0x1<<9)|(0x1<<8)|0x77; //sht_resp, wait_resp, start

if(!SDI_Check_CMD_End(55, 1))
return 0;
SDICSTA = 0xa00; // Clear cmd_end(with rsp)
return 1;
}
// ACMD6命令为设置总线带宽 [1:0] 00为1bit  10为4bit
U8 ACMD6(U8 BusWidth,U16 iRCA)
{
if(!CMD55(iRCA))
return 0;

SDICARG = BusWidth<<1;     //Wide 0: 1bit, 1: 4bit
SDICCON = (0x1<<9)|(0x1<<8)|0x46; //sht_resp, wait_resp, start

if(!SDI_Check_CMD_End(6, 1))
return 0;
SDICSTA=0xa00;     // Clear cmd_end(with rsp)
return 1;
}

//检测是否为SD卡及类型 =0应答错误或者卡正忙  =1标准SD卡 =2SDHC V2.0
U8 ACMD41(U16 iRCA)
{
U8 cReturn;
if(!CMD55(iRCA))
return 0;
SDICARG=0x40ff8000; //ACMD41(SD OCR:2.7V~3.6V)
SDICCON=(0x1<<9)|(0x1<<8)|0x69;//sht_resp, wait_resp, start, ACMD41

if(SDI_Check_CMD_End(41, 1))
{
if(SDIRSP0==0xc0ff8000)
cReturn = 2; //SDHC
else if(SDIRSP0==0x80ff8000)
cReturn = 1; //标准SD
else
cReturn = 0; //应答错误
SDICSTA = 0xa00; // Clear cmd_end(with rsp)
return cReturn; // Success
}
SDICSTA = 0xa00; // Clear cmd_end(with rsp)
return 0;
}
//检测MMC卡
U32 SDI_MMC_OCR(void)
{
int i;
//-- Negotiate operating condition for MMC, it makes card ready state
for(i=0;i<10;i++)
{
if(CMD1())
return 1;
}
return 0; // Fail
}
//检测SD卡
U32 SDI_SD_OCR(void)
{
int i;

SDCard.sdiRCA = 0;
for(i=0;i<50;i++)
{
if(ACMD41(SDCard.sdiRCA))
return 1;
Delay(1000);
}
return 0;  //fail
}
//运用CMD7来选中或解除选中卡,返回1则成功,0失败
U8 select_or_deselect(U8 cSelDesel,U16 iCardRCA)
{
if(CMD7(cSelDesel,iCardRCA))
return 1;
else
return 0;
}
//设置总线带宽
U8 Set_bus_Width(U8 cCardType,U8 cBusWidth,U16 iRCA)
{
if(cCardType==1) //MMC,返回0不需要设置 默认为1bit总线带宽
return 0;
return ACMD6(cBusWidth,iRCA);
}

/**********************************************************************************
功  能:该函数用于从SD卡中读出指定块起始地址的单个或多个数据块
参  数:
U32  Addr  被读块的起始地址
U32* RxBuffer 用于接收读出数据的缓冲区
U32 block_num 读的块数
返回值:
0 读块操作不成功
1 读块操作成功
**********************************************************************************/
U8 Read_Block(U32 Addr,U32* RxBuffer,U32 block_num)
{
U32 i=0;
U32 status=0;

SDIDTIMER=0x7fffff; // Set timeout count
SDIBSIZE=0x200; // 512byte(128word)
SDIFSTA=SDIFSTA|(1<<16); // FIFO reset
SDIDCON=(block_num<<0)|(2<<12)|(1<<14)|(SDCard.sdiWide<<16)|(1<<17)|(1<<19)|(2<<22);
while(CMD18(Addr)!=1)//发送读多个块指令
{
SDICSTA=0xF<<9;
}

while(i<block_num*128)
{ //开始接收数据到缓冲区
if(SDIDSTA&0x60)
{ //检查是否超时和CRC校验是否出错
SDIDSTA=(0x3<<0x5); //清除超时标志和CRC错误标志
return 0;
}
status=SDIFSTA;
if((status&0x1000)==0x1000)
{ //如果接收FIFO中有数据
*RxBuffer=SDIDAT;
RxBuffer++;
i++;
}
}

SDIDCON=SDIDCON&~(7<<12);
SDIFSTA = SDIFSTA&0x200;//Clear Rx FIFO Last data Ready
SDIDSTA = 0x10;//Clear data Tx/Rx end detect
while(CMD12()!=1)//发送结束指令
{
SDICSTA=0xF<<9;
}

return 1;
}

/**********************************************************************************
功  能:该函数用于向SD卡的一个或多个数据块写入数据
参  数:
U32  Addr  被写块的起始地址
U32* TxBuffer 用于发送数据的缓冲区
U32 block_num  块数
返回值:
0 数据写入操作失败
1 数据写入操作成功
**********************************************************************************/
U8 Write_Block(U32 Addr,U32* TxBuffer,U32 block_num)
{
U16 i=0;
U32 status = 0;

SDIDTIMER=0x7fffff; // Set timeout count
SDIBSIZE=0x200; // 512byte(128word)
SDIFSTA = SDIFSTA|(1<<16); // FIFO reset
SDIDCON = (block_num<<0)|(3<<12)|(1<<14)|(1<<16)|(1<<17)|(1<<20)|(2<<22);

while(CMD25(Addr)!=1)//发送写多个块指令
{
SDICSTA=0xF<<9;
}
while(i<block_num*128)
{ //开始传递数据到缓冲区
status=SDIFSTA;
if((status&0x2000)==0x2000)
{ //如果发送FIFO可用,即FIFO未满
SDIDAT=*TxBuffer;
TxBuffer++;
i++;
}
}
SDIDCON = SDIDCON&~(7<<12);

while(CMD12()!=1)//发送结束指令
{
SDICSTA=0xF<<9;
}
do
{ //等待数据发送结束
status=SDIDSTA;
}while((status&0x2)==0x2);
SDIDSTA = status;

SDIDSTA=0xf4;
return 1;
}

void Delay(U32 i)
{
while(i--);
}

###########################################
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c cmd delay byte struct 编程