基于S3C2440——SD/MMC

来源:互联网 发布:车铣复合加工编程书 编辑:程序博客网 时间:2024/06/05 14:33

下面内容是转载一为网友的内容: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  50000000typedef struct SD_STRUCT{U8 sdiWide; // 0:1bit, 1:4bitU8 sdiType;  // 0:SD  , 1:MMCU16 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 512U8 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");#endifreturn;}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地址数据出错,终止!");#endifreturn;}if(Read_Block(0,(U32 *)cRxBuffer,1)){#ifdef _SD_DEBUG_printf("\r\n读出SD卡0地址数据成功!");#endifprintf("\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地址数据出错,终止!");#endifreturn;}select_or_deselect(0,SDCard.sdiRCA);}U8 sdi_init(){int i;#ifdef _SD_DEBUG_printf("\r\nSDI初始化开始!");#endifGPEUP  = 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 resetSDIBSIZE=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;    }     //读CIDif(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");#endifreturn 0;}//设置RCA  MMC的RCA=1   SD的RCA=0if(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");#endifreturn 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");#endifreturn 0;}}//读CSDif(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("卡容量为:%dKB,%dMB\r\n",SDCard.lCardSize,SDCard.lCardSize/1024);#endif}else{#ifdef _SD_DEBUG_printf("Read Card CSD Fail!\r\n");#endifreturn 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");#endifreturn 0;}//CMD13 查询是否为传输状态while((CMD13(SDCard.sdiRCA)&0x1e00) != 0x800);//设置总线带宽 ACMD6if(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);#endifreturn 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 stateif(((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, startSDI_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}elsereturn 0;}return 0;}//请求设备在CMD上传送CIDU8 CMD2(U8 *cCID_Info) {SDICARG = 0x0;SDICCON = (0x1<<10)|(0x1<<9)|(0x1<<8)|0x42; //lng_resp, wait_resp, startif(!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, startif(!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 checkreturn 0;elsereturn 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, startif(!SDI_Check_CMD_End(7, 1))return 0;SDICSTA = 0xa00; // Clear cmd_end(with rsp)//--State(transfer) checkif( SDIRSP0 & 0x1e00!=0x800 )return 0;elsereturn 1;}else{SDICARG = 0<<16; //(RCA,stuff bit)SDICCON = (0x1<<8)|0x47; //no_resp, startif(!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, startif(!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;elseSDICSTA = 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, startif(!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必须先执行CMD55U8 CMD55(U16 iRCA) {SDICARG = iRCA<<16;SDICCON = (0x1<<9)|(0x1<<8)|0x77; //sht_resp, wait_resp, startif(!SDI_Check_CMD_End(55, 1)) return 0;SDICSTA = 0xa00; // Clear cmd_end(with rsp)return 1;}// ACMD6命令为设置总线带宽 [1:0] 00为1bit  10为4bitU8 ACMD6(U8 BusWidth,U16 iRCA) {if(!CMD55(iRCA))return 0;SDICARG = BusWidth<<1;     //Wide 0: 1bit, 1: 4bitSDICCON = (0x1<<9)|(0x1<<8)|0x46; //sht_resp, wait_resp, startif(!SDI_Check_CMD_End(6, 1)) return 0;SDICSTA=0xa00;     // Clear cmd_end(with rsp)return 1;}//检测是否为SD卡及类型 =0应答错误或者卡正忙  =1标准SD卡 =2SDHC V2.0U8 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, ACMD41if(SDI_Check_CMD_End(41, 1)) {if(SDIRSP0==0xc0ff8000)cReturn = 2; //SDHCelse if(SDIRSP0==0x80ff8000)cReturn = 1; //标准SDelsecReturn = 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;elsereturn 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 countSDIBSIZE=0x200; // 512byte(128word)SDIFSTA=SDIFSTA|(1<<16); // FIFO resetSDIDCON=(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 countSDIBSIZE=0x200; // 512byte(128word)SDIFSTA = SDIFSTA|(1<<16); // FIFO resetSDIDCON = (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--);}###########################################


原创粉丝点击