SD卡读写的方式(用SD模式)
SD卡模式分析

∙浅谈SD/MMC卡的SD模式和SPI模式
∙HANNY 发表于2009-10-24 15:15 | 分类:嵌入芯得| 浏览:7164
SD/MMC卡的读写模式分两种。
一种是利用SD总线来进行数据传输,这里称为SD模式;
另外一种是利用SPI总线来进行数据传输,这里称之为SPI模式。
最初接触SD/MMC卡时,Hanny一直觉得很奇怪,为什么SD/MMC卡要提供两种模式进行访问呢?比较完这两种模式的区别,分析其运用场合,就会明白答案了。
SD卡主要工作于4BIT SD模式下(MMC可能工作在8BIT SD模式下)。
其读写最高时钟可达50MHz,因此,市面上的卡的读取速度能到达20MB/s以上,已经算极限了。
SD模式也是SD卡的主要工作模式。
而SPI模式只有1BIT的带宽,而且时钟最高只能到25MHz,因此读取速度通常低于3MB/s。
但是SPI模式对硬件要求较低,一般广泛用于MP3等对读卡速度要求不高的低端场合。
Hanny当时还有一个疑问:SD模式不是也同样支持1BIT模式吗?为什么不直接用SD的1BIT 模式呢?
后来才明白:1、SPI总线是一个通用总线,大部份芯片都用硬件模块;2、SPI模式支持不带CRC校验的传输方式,可以降低硬件要求;3、SD的CMD线与DATA线之间有可能同时产生数据,对没有SD硬件模块的主机支持起来难度较高
CDMO对应MCU_MOSI第28个腿PB15,CDMI对应MCU_MISO第27个腿PB14。
SD卡读写包括两种模式

SD卡读写包括两种模式:SD模式和SPI模式。
其中SD模式又可以分为1bit 和4bit两种传输模式。
SD卡缺省使用专有的SD模式。
SD卡规范中主要讲了一些命令,响应和CRC效验等等,整个规范的内容还是很多的。
SD卡上电后,卡处于空闲状态,主机发送CMD0复位SD卡,然后通过CMD55和ACMD41判断当前电压是否在卡的工作范围内。
在得到了正确的响应后,主机可以继续通过CMD10读取SD卡的CID寄存器,通过CMD16设置数据块长度,通过CMD9读取卡的CSD寄存器。
从CSD寄存器中,主机可以获知卡容量,支持的命令集等重要参数。
此时,卡以进入了传输状态,主机就可以通过CMD17/18和CMD24/25对卡进行读写。
CRC校验是为了防止SD卡的命令,应答,数据传输出现错误。
每个命令和应答信号都会产生CRC效验码,每个数据块的传输也会长生CRC效验码。
这段程序是友善之臂推出的mini2440开发板中带的ADS测试源码。
整个阅读代码的过程是对这S3C2440的芯片手册和SD卡规范来看的,对于MMC卡没有给出注释,其实和SD卡是大同小异。
由于是初次接触ARM,对SD规范的认识也不是很深入,再加上自己水平有限,还不能完全读懂源代码,其中的肯定存在一些错误,欢迎大家一起交流讨论。
#define INT 1#define DMA 2int CMD13(void);// Send card statusint 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:4bitint MMC=0;// 0:SD , 1:MMCint 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/MMC控制器rGPEUP = 0xf83f;// SDCMD, SDDAT[3:0] => PU En. rGPECON = 0xaaaaaaaa;//SDCMD, SDDAT[3:0]Uart_Printf("\nSDI Card Write and Read Test\n");if(!SD_card_init())//等待SD卡初始化完成return;TR_Buf_new();//发送数据缓冲区初始化Wt_Block();//写卡Rd_Block();//读卡View_Rx_buf();if(MMC)TR_Buf_new();if(MMC){rSDICON |=(1<<5);// YH 0519, MMC Type SDCLKWt_Stream();Rd_Stream();View_Rx_buf();}Card_sel_desel(0);// Card deselectif(!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 initializeint 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();}void Flush_Rx_buf(void)//接收数据缓冲区清0{//-- Flushing Rx bufferint 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 bufferint 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;}}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卡初始化{//-- SD controller & card initializeint i;/* Important notice for MMC test condition *//* Cmd & Data lines must be enabled by pull up resister */rSDIPRE=PCLK/(INICLK)-1;// 400KHzUart_Printf("Init. Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));rSDICON=(1<<4)|1;//先传高位,再传低位,使能CLKrSDIFSTA=rSDIFSTA|(1<<16);//SDI FIFO status register,FIFO复位rSDIBSIZE=0x200;// SDI block size register,设置每块大小为512byte(128word)rSDIDTIMER=0x7fffff;// SDI data / busy timer register,设置超时周期for(i=0;i<0x1000;i++);// 延时,CARD自身初始化需要74个CLKCMD0();//发送CMD0Uart_Printf("In idle\n");//-- Check MMC card OCRif(Chk_MMC_OCR()){Uart_Printf("In MMC ready\n");MMC=1;goto RECMD2;}Uart_Printf("MMC check end!!\n");//-- Check SD card OCRif(Chk_SD_OCR())Uart_Printf("In SD ready\n");else{Uart_Printf("Initialize fail\nNo Card assertion\n");return 0;}RECMD2://检查连接的卡,识别卡的状态rSDICARG=0x0;// CMD2(stuff bit)rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42;//CMD2为长应答并等待应答,开始发//送CMD2,命令卡发回CID寄存器(保存了生产厂家/时间/批号等等),产生RSP2//检查CMD2是否成功发送并收到响应if(!Chk_CMDend(2, 1))goto RECMD2;//CMD2出错,重新发送rSDICSTA=0xa00;// 清除命令和应答结束标志位Uart_Printf("End id\n");RECMD3://--发送CMD3,给卡分配RCA,rSDICARG=MMC<<16;//CMD3参数, MMC:设置 RCA, SD:请求发RCArSDICCON=(0x1<<9)|(0x1<<8)|0x43;//CMD3为短应答并等待应答,开始发//送CMD3, MMC(设置RCA,产生RSP1),SD(设置RCA,产生RSP6)//检查CMD3是否成功发送并收到响应if(!Chk_CMDend(3, 1))goto RECMD3;//CMD3出错,重新发送rSDICSTA=0xa00;// 清除命令和应答结束标志位//--Publish RCAif(MMC){RCA=1;rSDIPRE=(PCLK/MMCCLK)-1;Uart_Printf("MMC Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));}else{RCA=( rSDIRSP0 & 0xffff0000 )>>16;//回读RCA,卡被分配RCA后进入//TransferMODE,准备读写Uart_Printf("RCA=0x%x\n",RCA);rSDIPRE=PCLK/(SDCLK)-1;// Normal clock=25MHzUart_Printf("SD Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));}//--State(stand-by) check//根据SD规范,rSDIRSP0高16位存储RCA,低16位存储CARD的状态if(rSDIRSP0 &0x1e00!=0x600 )// 检查CARD状态,不是处于stand-by 状态goto RECMD3;////未就绪,重新发送CMD3Uart_Printf("In stand-by\n");Card_sel_desel(1);// Selectif(!MMC)//若位SD卡,设置4bit的数据传输模式Set_4bit_bus();else//若位MMC卡,设置1bit的数据传输模式Set_1bit_bus();return 1;}void Card_sel_desel(char sel_desel){//-- Card select or deselectif(sel_desel)//选择该卡{RECMDS7://送CMD7表示选择该卡,准备读写,产生RSP1.rSDICARG=RCA<<16;// CMD7参数(RCA,stuff bit),其中高16位为RCA rSDICCON=(0x1<<9)|(0x1<<8)|0x47;//CMD7为短应答并等待应答,开始发//送CMD7选择该卡,准备读写,产生RSP1//检查CMD7是否成功发送并收到响应if(!Chk_CMDend(7, 1))goto RECMDS7;//出错,重新发送rSDICSTA=0xa00;//清除命令和应答结束标志位//检查是否处于transfer modeif( rSDIRSP0 & 0x1e00!=0x800 )goto RECMDS7;//不处于transfer mode,重新发送CMD7}else//卸载该卡{RECMDD7:rSDICARG=0<<16;// CMD7参数(RCA,stuff bit),其中高16位为RCA rSDICCON=(0x1<<8)|0x47;// 无应答并,并开始发送CMD7//检查CMD7是否成功if(!Chk_CMDend(7, 0))goto RECMDD7;//失败,重新卸载rSDICSTA=0x800;// //清除命令结束标志位}}void __irq Rd_Int(void)//读中断函数U32 i,status;status=rSDIFSTA;if((status&0x200)== 0x200 )//检查接收FIFO最后是否有数据到来{for(i=(status & 0x7f)/4;i>0;i--){*Rx_buffer++=rSDIDAT;rd_cnt++;}rSDIFSTA=rSDIFSTA&0x200;//清 Rx FIFO Last data Ready标志位}else if((status&0x80)== 0x80 )// 检查Half FULL interrupt标志,只要大于31个字节,就会将该标志置1{for(i=0;i<8;i++){*Rx_buffer++=rSDIDAT;rd_cnt++;}}ClearPending(BIT_SDI);//清零源中断挂起寄存器和中断挂起寄存器}void __irq Wt_Int(void)//写中断函数ClearPending(BIT_SDI);//清零源中断挂起寄存器和中断挂起寄存器rSDIDAT=*Tx_buffer++;wt_cnt++;if(wt_cnt==128*block){rINTMSK |= BIT_SDI;//屏蔽BIT_SDI中断rSDIDAT=*Tx_buffer;TR_end=1;}}void __irq DMA_end(void){ClearPending(BIT_DMA0);//清零源中断挂起寄存器和中断挂起寄存器TR_end=1;}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);// 复位FIFOif(mode!=2)rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)|(2<<12)|(block <<0);//YH 040220//设置数据控制寄存器:字传输,块数据传输,4bit数据传输,开始数据传输,数据发送模//式,共读block个块rSDICARG=0x0;// CMD17/18地址参数RERDCMD:switch(mode){case POL:if(block<2)// SINGLE_READ写单块{rSDICCON=(0x1<<9)|(0x1<<8)|0x51;//CMD17为短应答并等待应答,开始发//送CMD17单块读命令,开始读,产生RSP1if(!Chk_CMDend(17, 1))//-- Check end of CMD17goto RERDCMD;//失败,继续发送}else// MULTI_READ,读多块{rSDICCON=(0x1<<9)|(0x1<<8)|0x52;//CMD18为短应答并等待应答,开始发//送CMD18多块读命令,开始读,产生RSP1if(!Chk_CMDend(18, 1))//-- Check end of CMD18goto RERDCMD;//失败,继续发送}rSDICSTA=0xa00;// 清命令和应答结束标志while(rd_cnt<128*block)// 512块个字节{if((rSDIDSTA&0x20)==0x20)// 是否超时{rSDIDSTA=(0x1<<0x5);// 清超时标志位break;}status=rSDIFSTA;if((status&0x1000)==0x1000)// FIFO非空{*Rx_buffer++=rSDIDAT;rd_cnt++;}}break;case INT:pISR_SDI=(unsigned)Rd_Int;rINTMSK =~(BIT_SDI);//屏蔽除所有其他中断rSDIIMSK=5;// 开启Last & Rx FIFO half 中断.if(block<2)// SINGLE_READ{rSDICCON=(0x1<<9)|(0x1<<8)|0x51;//CMD17为短应答并等待应答,开始发//送CMD17单块读命令,开始读,产生RSP1if(!Chk_CMDend(17, 1))//-- Check end of CMD17goto RERDCMD;//失败,继续发送}else// MULTI_READ{rSDICCON=(0x1<<9)|(0x1<<8)|0x52;//CMD18为短应答并等待应答,开始发//送CMD18多块读命令,开始读,产生RSP1if(!Chk_CMDend(18, 1))//-- Check end of CMD18goto RERDCMD;//失败,继续发送}rSDICSTA=0xa00;// 清命令和应答结束标志while(rd_cnt<128*block);rINTMSK |=(BIT_SDI);//屏蔽BIT_SDI中断rSDIIMSK=0;//屏蔽所有中断break;case DMA:pISR_DMA0=(unsigned)DMA_end;rINTMSK =~(BIT_DMA0);rSDIDCON=rSDIDCON|(1<<24);//YH 040227, Burst4 EnablerDISRC0=(int)(SDIDAT);// SDIDATrDISRCC0=(1<<1)+(1<<0);// APB, fixrDIDST0=(U32)(Rx_buffer);// Rx_bufferrDIDSTC0=(0<<1)+(0<<0);// AHB, incrDCON0=(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-swtriggerrSDIDCON=(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, CMD17if(!Chk_CMDend(17, 1))//-- Check end of CMD17goto RERDCMD;}else// MULTI_READ{rSDICCON=(0x1<<9)|(0x1<<8)|0x52;// sht_resp, wait_resp, dat, start, CMD18if(!Chk_CMDend(18, 1))//-- Check end of CMD18goto 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 stopbreak;default:break;}//-- Check end of DATAif(!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 detectif(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 CMD12if(!Chk_CMDend(12, 1))goto RERCMD12;rSDICSTA=0xa00;// Clear cmd_end(with rsp)}}void Rd_Stream(void)// only for MMC, 3blk read{int status, rd_cnt=0;if(MMC!=1){Uart_Printf("Stream read command supports only MMC!\n"); return;}Uart_Printf("\n[Stream read test]\n");RECMD11:rSDIDCON=(2<<22)|(1<<19)|(0<<17)|(0<<16)|(1<<14)|(2<<12);rSDICARG=0x0;// CMD11(addr)rSDICCON=(0x1<<9)|(0x1<<8)|0x4b;//sht_resp, wait_resp, dat, start, CMD11while(rd_cnt<128*block){if((rSDIDSTA&0x20)== 0x20 ){Uart_Printf("Rread timeout error");return;}status=rSDIFSTA;if((status&0x1000)==0x1000){//*Rx_buffer++=rSDIDAT;//rd_cnt++;Rx_buffer[rd_cnt++]=rSDIDAT;}}//-- Check end of CMD11if(!Chk_CMDend(11, 1))goto RECMD11;rSDICSTA=0xa00;// Clear cmd_end(with rsp)//-- Check end of DATArSDIDCON=(2<<22)|(1<<19)|(0<<17)|(0<<16);//YH 040220rSDIDCON=rSDIDCON&~(7<<12);//YH 040220, no operation, data readywhile( rSDIDSTA&0x3 !=0x0 );if(rSDIDSTA!=0)Uart_Printf("rSDIDSTA=0x%x\n", rSDIDSTA);rSDIDSTA=0xff;//YH 040221STRCMD12://--Stop cmd(CMD12)rSDICARG=0x0;//CMD12(stuff bit)rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;//sht_resp, wait_resp, start, CMD12//-- Check end of CMD12if(!Chk_CMDend(12, 1))goto STRCMD12;rSDICSTA=0xa00;// Clear cmd_end(with rsp)rSDIFSTA=rSDIFSTA&0x200;//Clear Rx FIFO Last data Ready, YH 040221 Uart_Printf("rSDIFSTA1=0x%x\n", rSDIFSTA);//YH 040221rSDIFSTA=rSDIFSTA&0x200;//Clear Rx FIFO Last data Ready, YH 040221Uart_Printf("rSDIFSTA2=0x%x\n", rSDIFSTA);//YH 040221Uart_Printf("\n--End stream read test\n");}void Wt_Block(void){U32 mode;int status;wt_cnt=0;Uart_Printf("Block write test[ Polling write ]\n");mode = 0 ;rSDIFSTA=rSDIFSTA|(1<<16);//复位FIFOif(mode!=2)rSDIDCON=(2<<22)|(1<<20)|(1<<17)|(Wide<<16)|(1<<14)|(3<<12)|(block <<0);//设置数据控制寄存器:字传输,块数据传输,4bit数据传输,开始数据传输,数据发送模//式,共写block个块rSDICARG=0x0;// CMD24/25地址参数REWTCMD:switch(mode){case POL:if(block<2)// SINGLE_WRITE,写单块{rSDICCON=(0x1<<9)|(0x1<<8)|0x58;//CMD24为短应答并等待应答,开始发//送CMD24单块写命令,开始写,产生RSP1if(!Chk_CMDend(24, 1))//-- Check end of CMD24goto REWTCMD;//命令发送失败}else// MULTI_WRITE,写多块{rSDICCON=(0x1<<9)|(0x1<<8)|0x59;//CMD25为短应答并等待应答,开发//送CMD25多块写命令,开始读写,产生RSP1if(!Chk_CMDend(25, 1))//-- Check end of CMD25goto REWTCMD;//命令发送失败}rSDICSTA=0xa00;// 清命令和应答结束标志while(wt_cnt<128*block){status=rSDIFSTA;if((status&0x2000)==0x2000)//FIFO未满{rSDIDAT=*Tx_buffer++;wt_cnt++;//Uart_Printf("Block No.=%d, wt_cnt=%d\n",block,wt_cnt);}}break;case INT:pISR_SDI=(unsigned)Wt_Int;rINTMSK =~(BIT_SDI);rSDIIMSK=0x10;// Tx FIFO half int.if(block<2)// SINGLE_WRITE{rSDICCON=(0x1<<9)|(0x1<<8)|0x58;//sht_resp, wait_resp, dat, start, CMD24if(!Chk_CMDend(24, 1))//-- Check end of CMD24goto REWTCMD;}else// MULTI_WRITE{rSDICCON=(0x1<<9)|(0x1<<8)|0x59;//sht_resp, wait_resp, dat, start, CMD25if(!Chk_CMDend(25, 1))//-- Check end of CMD25goto REWTCMD;}rSDICSTA=0xa00;// Clear cmd_end(with rsp)while(!TR_end);//while(wt_cnt<128);rINTMSK |=(BIT_SDI);TR_end=0;rSDIIMSK=0;// All maskbreak;case DMA:pISR_DMA0=(unsigned)DMA_end;rINTMSK =~(BIT_DMA0);rSDIDCON=rSDIDCON|(1<<24);//YH 040227, Burst4 EnablerDISRC0=(int)(Tx_buffer);// Tx_bufferrDISRCC0=(0<<1)+(0<<0);// AHB, incrDIDST0=(U32)(SDIDAT);// SDIDATrDIDSTC0=(1<<1)+(1<<0);// APB, fixrDCON0=(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*numrDMASKTRIG0=(0<<2)+(1<<1)+0;//no-stop, DMA0 channel on, no-swtriggerrSDIDCON=(2<<22)|(1<<20)|(1<<17)|(Wide<<16)|(1<<15)|(1<<14)|(3<<1 2)|(block<<0);//YH 040220// Word Tx, Tx after rsp, blk, 4bit bus, dma enable, Tx start, blk numif(block<2)// SINGLE_WRITE{rSDICCON=(0x1<<9)|(0x1<<8)|0x58;//sht_resp, wait_resp, dat, start, CMD24if(!Chk_CMDend(24, 1))//-- Check end of CMD24goto REWTCMD;}else// MULTI_WRITE{rSDICCON=(0x1<<9)|(0x1<<8)|0x59;//sht_resp, wait_resp, dat, start, CMD25if(!Chk_CMDend(25, 1))//-- Check end of CMD25goto REWTCMD;}rSDICSTA=0xa00;// Clear cmd_end(with rsp)while(!TR_end);rINTMSK |=(BIT_DMA0);TR_end=0;rDMASKTRIG0=(1<<2);//DMA0 stopbreak;default:break;}//-- Check end of DATAif(!Chk_DATend())Uart_Printf("dat error\n");rSDIDCON=rSDIDCON&~(7<<12);//YH 040220, Clear Data Transfer mode => no operation, Cleata Data Transfer startrSDIDSTA=0x10;// Clear data Tx/Rx endif(block>1){//--Stop cmd(CMD12)REWCMD12:rSDIDCON=(1<<18)|(1<<17)|(0<<16)|(1<<14)|(1<<12)|(block<<0);//YH 040220rSDICARG=0x0;//CMD12(stuff bit)rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;//sht_resp, wait_resp, start, CMD12 //-- Check end of CMD12if(!Chk_CMDend(12, 1))goto REWCMD12;rSDICSTA=0xa00;// Clear cmd_end(with rsp)//-- Check end of DATA(with busy state)if(!Chk_BUSYend())Uart_Printf("error\n");rSDIDSTA=0x08;//! Should be cleared by writing '1'.}}void Wt_Stream(void)// only for MMC, 3blk write{int status, wt_cnt=0;if(MMC!=1){Uart_Printf("Stream write command supports only MMC!\n");return;}Uart_Printf("\n[Stream write test]\n");RECMD20:rSDIDCON=(2<<22)|(1<<20)|(0<<17)|(0<<16)|(1<<14)|(3<<12);// stream moderSDICARG=0x0;// CMD20(addr)rSDICCON=(0x1<<9)|(0x1<<8)|0x54;//sht_resp, wait_resp, dat, start, CMD20//-- Check end of CMD25if(!Chk_CMDend(20, 1))goto RECMD20;rSDICSTA=0xa00;// Clear cmd_end(with rsp)while(wt_cnt<128*block){status=rSDIFSTA;if((status&0x2000)==0x2000)rSDIDAT=Tx_buffer[wt_cnt++];}//-- Check end of DATAwhile( rSDIFSTA&0x400 );Delay(10);// for the empty of DATA line(Hardware)rSDIDCON=(1<<20)|(0<<17)|(0<<16);//YH 040220rSDIDCON=rSDIDCON&~(7<<12);//YH 040220, no operation, data readywhile((rSDIDSTA&0x3)!=0x0 );if(rSDIDSTA!=0x0)Uart_Printf("rSDIDSTA=0x%x\n", rSDIDSTA);rSDIDSTA=0xff;//Clear rSDIDSTASTWCMD12://--Stop cmd(CMD12)rSDIDCON=(1<<18)|(1<<17)|(0<<16)|(1<<14)|(1<<12);rSDICARG=0x0;//CMD12(stuff bit)rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;//sht_resp, wait_resp, start, CMD12//-- Check end of CMD12if(!Chk_CMDend(12, 1))goto STWCMD12;rSDICSTA=0xa00;// Clear cmd_end(with rsp)//-- Check end of DATA(with busy state)if(!Chk_BUSYend())Uart_Printf("error\n");rSDIDSTA=0x08;Uart_Printf("\n--End Stream write test\n");}int Chk_CMDend(int cmd,int be_resp)//0: Timeout{int finish0;if(!be_resp)// 没有应答信号{finish0=rSDICSTA;//读取SDI command status register,while((finish0&0x800)!=0x800)// 等待命令结束finish0=rSDICSTA;rSDICSTA=finish0;// 清命令结束标志return 1;//成功,返回1}else// 有应答信号{finish0=rSDICSTA;//读取SDI command status register,while(!(((finish0&0x200)==0x200)|((finish0&0x400)==0x400)))//检查超时和应答信号finish0=rSDICSTA;if(cmd==1 | cmd==41)// CRC no check, CMD9 is a long Resp. command.{if((finish0&0xf00)!= 0xa00 )// 命令,应答有错,或超时{rSDICSTA=finish0;// 清错误标志if(((finish0&0x400)==0x400))// 若超时,返回0return 0;}rSDICSTA=finish0;// 清命令和应答结束标志}else// 进行CRC效验{if((finish0&0x1f00)!= 0xa00 )// CRC效验出错{Uart_Printf("CMD%d:rSDICSTA=0x%x, rSDIRSP0=0x%x\n",cmd, rSDICSTA, rSDIRSP0);//输出对应寄存器的值rSDICSTA=finish0;// 清除错误标志位if(((finish0&0x400)==0x400))// 若超时,返回0return 0;}rSDICSTA=finish0;}return 1;}}int Chk_DATend(void){int finish;finish=rSDIDSTA;while(!(((finish&0x10)==0x10)|((finish&0x20)==0x20)))// 检查数据结束和超时位finish=rSDIDSTA;if((finish&0xfc)!= 0x10 )//数据传输结束{Uart_Printf("DATA:finish=0x%x\n", finish);rSDIDSTA=0xec;//清除错误标志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 ){Uart_Printf("DATA:finish=0x%x\n", finish);rSDIDSTA=0xf4;//清除错误标志return 0;}return 1;}void CMD0(void)//CMD0用于对SD实现软件复位,不论卡处于何种状态,使SD卡处于//空闲状态,等待下一个命令的到来{//-- Make card idle staterSDICARG=0x0;// ,CMD0(stuff bit)rSDICCON=(1<<8)|0x40;// 不等待应答信号,命令开始//并再次发送CMD0 关于cmd0定义:0(start_bit)1(cmd标志)000000(6位cmd编//码)后面是参数(无参数就全0)//-- Check end of CMD0Chk_CMDend(0, 0);// 检查命令是否成功发送rSDICSTA=0x800;// 清除命令结束标志}int Chk_MMC_OCR(void){int i;//-- MMC卡识别的等待操作, 使卡处于空闲状态for(i=0;i<100;i++)//等待的时间取决于厂商{// rSDICARG=0xffc000; //CMD1(MMC OCR:2.6V~3.6V),设置工作电压rSDICARG=0xff8000;//CMD1(SD OCR:2.7V~3.6V),设置工作电压rSDICCON=(0x1<<9)|(0x1<<8)|0x41;//CMD1为短应答并等待应答,开始发送CMD1//-- 检查CMD1是否发送成功,并检查卡状态// if(Chk_CMDend(1, 1) & rSDIRSP0==0x80ffc000) //31:忙状态标志位,0表示忙//0xffc000为卡的正常工作电压范围if(Chk_CMDend(1, 1)&&(rSDIRSP0>>16)==0x80ff)//卡处于空闲// if(Chk_CMDend(1, 1) & rSDIRSP0==0x80ff8000)rSDICSTA=0xa00;// 清除命令和应答结束标志位return 1;// 成功}}rSDICSTA=0xa00;//清除命令和应答结束标志位return 0;// 失败}int Chk_SD_OCR(void){int i;//-- SD卡识别的等待操作, 使卡处于空闲状态for(i=0;i<50;i++)// 如果这段时间太短,SD卡的初始化可能会失败{CMD55();//送CMD55,表示下个命令将是特殊功能命令acmd,而非一般命令cmdrSDICARG=0xff8000;//ACMD41(SD OCR:2.7V~3.6V) ,设置工作电压// rSDICARG=0xffc000;//ACMD41(MMC OCR:2.6V~3.6V)设置工作电压rSDICCON=(0x1<<9)|(0x1<<8)|0x69;// ACMD41为短应答并等待应答,开始发//送ACMD41,命令卡发回OCR寄存器(保存了电压参数/busy信号等等),产生//-- 检查ACMD41是否发送成功,并检查卡状态if( Chk_CMDend(41, 1)& rSDIRSP0==0x80ff8000 )//发送成功并且卡处于空闲状态{rSDICSTA=0xa00;//清除命令和应答结束标志位return 1;//成功}Delay(200);//等待卡上电后处于空闲状态}//Uart_Printf("SDIRSP0=0x%x\n",rSDIRSP0);rSDICSTA=0xa00;//清除命令和应答结束标志位return 0;// 失败}int CMD55(void){//CMD55,表示下个命令将是特殊功能acmd,而非一般命令cmdrSDICARG=RCA<<16;//CMD55(RCA,stuff bit)rSDICCON=(0x1<<9)|(0x1<<8)|0x77;//CMD55为短应答(R1)并等待应答,并开始发送CMD55//-- 检查CMD55是成功发送if(!Chk_CMDend(55, 1))return 0;//出错,返回rSDICSTA=0xa00;////清除命令和应答结束标志位return 1;}int CMD13(void)//送CMD13,命令卡的当前状态{int response0;rSDICARG=RCA<<16;// CMD13(RCA,stuff bit),高16位为RCArSDICCON=(0x1<<9)|(0x1<<8)|0x4d;//CMD13为短应答(R1)并等待应答,并开始发送CMD13//-- Check end of CMD13if(!Chk_CMDend(13, 1))//-- 检查CMD13是成功发送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)//卡处于receive data stateTest_SDI();rSDICSTA=0xa00;//清除命令和应答结束标志位return 1;}int CMD9(void)//送CMD9,命令卡发回CSD寄存器(保存了读写参数/卡的容量等内容),产生RSP2{rSDICARG=RCA<<16;// CMD9参数,高16位为RCArSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x49;//CMD9为长应答并等待应答,开始发//送CMD9,产生RSP2Uart_Printf("\nCSD register :\n");//-- Check end of CMD9if(!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)//设置1位数据线{Wide=0;if(!MMC)SetBus();//Uart_Printf("\n****1bit bus****\n");}void Set_4bit_bus(void)//设置4位数据线{Wide=1;SetBus();//Uart_Printf("\n****4bit bus****\n");}void SetBus(void)//设置数据线宽度{SET_BUS:CMD55();//CMD55,表示下个命令将是特殊功能acmd,而非一般命令cmdrSDICARG=Wide<<1;//数据宽度00: 1bit, 10: 4bitrSDICCON=(0x1<<9)|(0x1<<8)|0x46;//ACMD6为短应答(R1)并等待应答,并开始发送// ACMD6设置数据线宽度位4bitif(!Chk_CMDend(6, 1))// 设置失败,则重新设置goto SET_BUS;rSDICSTA=0xa00;//清除命令和应答结束标志位}void Set_Prt(void)//写保护{//-- Set protection addr.0 ~ 262144(32*16*512)Uart_Printf("[Set protection(addr.0 ~ 262144) test]\n"); RECMD28://--Make ACMDrSDICARG=0;// CMD28(addr)rSDICCON=(0x1<<9)|(0x1<<8)|0x5c;//sht_resp, wait_resp, start, CMD28//-- Check end of CMD28if(!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 ACMDrSDICARG=0;// CMD29(addr)rSDICCON=(0x1<<9)|(0x1<<8)|0x5d;//sht_resp, wait_resp, start, CMD29//-- Check end of CMD29。
sd卡数据读写流程

SD卡数据读写流程引言SD卡(Secure Digital Card)是一种常用的存储设备,通常用于移动设备、相机等电子产品中。
在使用SD卡时,数据的读写是一个非常重要的过程。
本文将详细介绍SD卡的数据读写流程,包括初始化、文件操作和数据传输等环节。
初始化SD卡初始化SD卡是数据读写的第一步,确保SD卡可以被正确地识别和使用。
下面是SD卡数据读写的初始化流程:1.插入SD卡:将SD卡插入目标设备的SD卡插槽中。
2.电源供给:为SD卡提供稳定的电源,通常通过连接电源线或使用内置电池来实现。
3.延时等待:等待SD卡稳定,一般为几毫秒的时间。
4.发送命令:通过SPI或SDIO等接口向SD卡发送特定的命令,以初始化SD卡。
5.接收响应:SD卡将返回初始化成功与否的响应,如果初始化成功,则可以进行后续的数据读写操作。
SD卡文件系统在进行数据读写之前,需要先设置SD卡的文件系统。
常用的文件系统包括FAT16、FAT32和exFAT等。
下面是SD卡文件系统的设置流程:1.格式化SD卡:使用格式化工具对SD卡进行格式化,以清除原有的文件系统和数据。
2.创建分区:根据需求,可以将SD卡分为一个或多个分区,并设置每个分区的大小。
3.创建文件系统:选择合适的文件系统类型,在分区上创建文件系统,并分配文件系统的容量。
4.分配文件表:文件系统会维护一个文件表,记录文件的位置、大小等信息。
在创建文件系统时,会分配一块空间来存储文件表。
5.设置文件权限:根据需要,可以设置文件的读写、执行权限,以保证文件的安全性。
SD卡数据读写操作SD卡的数据读写操作包括文件的创建、打开、读取、写入和关闭等。
下面是SD卡数据读写操作的详细流程:1.创建文件:通过文件系统接口,调用相关函数创建一个新的文件,并指定文件的名称和路径。
2.打开文件:使用文件系统的函数打开已经存在的文件,以便后续的读取和写入操作。
3.读取文件:通过文件系统提供的函数,在已经打开的文件中进行读取操作。
SD卡读写包括两种模式

SD卡读写包括两种模式SD卡读写包括两种模式:SD模式和SPI模式。
其中SD模式又可以分为1bit 和4bit两种传输模式。
SD卡缺省使用专有的SD模式。
SD卡规范中主要讲了一些命令,响应和CRC效验等等,整个规范的内容还是很多的。
SD卡上电后,卡处于空闲状态,主机发送CMD0复位SD卡,然后通过CMD55和ACMD41判断当前电压是否在卡的工作范围内。
在得到了正确的响应后,主机可以继续通过CMD10读取SD卡的CID寄存器,通过CMD16设置数据块长度,通过CMD9读取卡的CSD寄存器。
从CSD寄存器中,主机可以获知卡容量,支持的命令集等重要参数。
此时,卡以进入了传输状态,主机就可以通过CMD17/18和CMD24/25对卡进行读写。
CRC校验是为了防止SD卡的命令,应答,数据传输出现错误。
每个命令和应答信号都会产生CRC效验码,每个数据块的传输也会长生CRC效验码。
这段程序是友善之臂推出的mini2440开发板中带的ADS测试源码。
整个阅读代码的过程是对这S3C2440的芯片手册和SD卡规范来看的,对于MMC卡没有给出注释,其实和SD卡是大同小异。
由于是初次接触ARM,对SD规范的认识也不是很深入,再加上自己水平有限,还不能完全读懂源代码,其中的肯定存在一些错误,欢迎大家一起交流讨论。
#define INT 1#define DMA 2int CMD13(void);// Send card statusint 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:4bitint MMC=0;// 0:SD , 1:MMCint 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/MMC控制器rGPEUP = 0xf83f;// SDCMD, SDDAT[3:0] => PU En. rGPECON = 0xaaaaaaaa;//SDCMD, SDDAT[3:0]Uart_Printf("\nSDI Card Write and Read Test\n");if(!SD_card_init())//等待SD卡初始化完成return;TR_Buf_new();//发送数据缓冲区初始化Wt_Block();//写卡Rd_Block();//读卡View_Rx_buf();if(MMC)TR_Buf_new();if(MMC){rSDICON |=(1<<5);// YH 0519, MMC Type SDCLKWt_Stream();Rd_Stream();View_Rx_buf();}Card_sel_desel(0);// Card deselectif(!CMD9())Uart_Printf("Get CSD fail\n");rSDIDCON=0;//tarkrSDICSTA=0xffff;rGPEUP=save_rGPEUP;rGPECON=save_rGPECON;}void TR_Buf_new(void)//发送数据缓冲区初始化{//-- Tx & Rx Buffer initializeint 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();}void Flush_Rx_buf(void)//接收数据缓冲区清0{//-- Flushing Rx bufferint 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 bufferint 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;}}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卡初始化{//-- SD controller & card initializeint i;/* Important notice for MMC test condition *//* Cmd & Data lines must be enabled by pull up resister */rSDIPRE=PCLK/(INICLK)-1;// 400KHzUart_Printf("Init. Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));rSDICON=(1<<4)|1;//先传高位,再传低位,使能CLKrSDIFSTA=rSDIFSTA|(1<<16);//SDI FIFO status register,FIFO 复位rSDIBSIZE=0x200;// SDI block size register,设置每块大小为512byte(128word)rSDIDTIMER=0x7fffff;// SDI data / busy timer register,设置超时周期for(i=0;i<0x1000;i++);// 延时,CARD自身初始化需要74个CLKCMD0();//发送CMD0Uart_Printf("In idle\n");//-- Check MMC card OCRif(Chk_MMC_OCR()){Uart_Printf("In MMC ready\n");MMC=1;goto RECMD2;}Uart_Printf("MMC check end!!\n");//-- Check SD card OCRif(Chk_SD_OCR())Uart_Printf("In SD ready\n");else{Uart_Printf("Initialize fail\nNo Card assertion\n");return 0;}RECMD2://检查连接的卡,识别卡的状态rSDICARG=0x0;// CMD2(stuff bit)rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42;//CMD2为长应答并等待应答,开始发//送CMD2,命令卡发回CID寄存器(保存了生产厂家/时间/批号等等),产生RSP2//检查CMD2是否成功发送并收到响应if(!Chk_CMDend(2, 1))goto RECMD2;//CMD2出错,重新发送rSDICSTA=0xa00;// 清除命令和应答结束标志位Uart_Printf("End id\n");RECMD3://--发送CMD3,给卡分配RCA,rSDICARG=MMC<<16;//CMD3参数,MMC:设置RCA, SD:请求发RCArSDICCON=(0x1<<9)|(0x1<<8)|0x43;//CMD3为短应答并等待应答,开始发//送CMD3, MMC(设置RCA,产生RSP1),SD(设置RCA,产生RSP6)//检查CMD3是否成功发送并收到响应if(!Chk_CMDend(3, 1))goto RECMD3;//CMD3出错,重新发送rSDICSTA=0xa00;// 清除命令和应答结束标志位//--Publish RCAif(MMC){RCA=1;rSDIPRE=(PCLK/MMCCLK)-1;Uart_Printf("MMC Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));}else{RCA=( rSDIRSP0 & 0xffff0000 )>>16;//回读RCA,卡被分配RCA 后进入//TransferMODE,准备读写Uart_Printf("RCA=0x%x\n",RCA);rSDIPRE=PCLK/(SDCLK)-1;// Normal clock=25MHzUart_Printf("SD Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));}//--State(stand-by) check//根据SD规范,rSDIRSP0高16位存储RCA,低16位存储CARD的状态if(rSDIRSP0 &0x1e00!=0x600 )// 检查CARD状态,不是处于stand-by 状态goto RECMD3;////未就绪,重新发送CMD3Uart_Printf("In stand-by\n");Card_sel_desel(1);// Selectif(!MMC)//若位SD卡,设置4bit的数据传输模式Set_4bit_bus();else//若位MMC卡,设置1bit的数据传输模式Set_1bit_bus();return 1;}void Card_sel_desel(char sel_desel){//-- Card select or deselectif(sel_desel)//选择该卡{RECMDS7://送CMD7表示选择该卡,准备读写,产生RSP1.rSDICARG=RCA<<16;// CMD7参数(RCA,stuff bit),其中高16位为RCA rSDICCON=(0x1<<9)|(0x1<<8)|0x47;//CMD7为短应答并等待应答,开始发//送CMD7选择该卡,准备读写,产生RSP1//检查CMD7是否成功发送并收到响应if(!Chk_CMDend(7, 1))goto RECMDS7;//出错,重新发送rSDICSTA=0xa00;//清除命令和应答结束标志位//检查是否处于transfer modeif( rSDIRSP0 & 0x1e00!=0x800 )goto RECMDS7;//不处于transfer mode,重新发送CMD7}else//卸载该卡{RECMDD7:rSDICARG=0<<16;// CMD7参数(RCA,stuff bit),其中高16位为RCA rSDICCON=(0x1<<8)|0x47;// 无应答并,并开始发送CMD7 //检查CMD7是否成功if(!Chk_CMDend(7, 0))goto RECMDD7;//失败,重新卸载rSDICSTA=0x800;// //清除命令结束标志位}}void __irq Rd_Int(void)//读中断函数U32 i,status;status=rSDIFSTA;if((status&0x200)== 0x200 )//检查接收FIFO最后是否有数据到来{for(i=(status & 0x7f)/4;i>0;i--){*Rx_buffer++=rSDIDAT;rd_cnt++;}rSDIFSTA=rSDIFSTA&0x200;//清 Rx FIFO Last data Ready标志位}else if((status&0x80)== 0x80 )// 检查Half FULL interrupt标志,只要大于31个字节,就会将该标志置1{for(i=0;i<8;i++){*Rx_buffer++=rSDIDAT;rd_cnt++;}}ClearPending(BIT_SDI);//清零源中断挂起寄存器和中断挂起寄存器}void __irq Wt_Int(void)//写中断函数ClearPending(BIT_SDI);//清零源中断挂起寄存器和中断挂起寄存器rSDIDAT=*Tx_buffer++;wt_cnt++;if(wt_cnt==128*block){rINTMSK |= BIT_SDI;//屏蔽BIT_SDI中断rSDIDAT=*Tx_buffer;TR_end=1;}}void __irq DMA_end(void){ClearPending(BIT_DMA0);//清零源中断挂起寄存器和中断挂起寄存器TR_end=1;}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);// 复位FIFOif(mode!=2)rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)| (2<<12)|(block <<0);//YH 040220//设置数据控制寄存器:字传输,块数据传输,4bit数据传输,开始数据传输,数据发送模//式,共读block个块rSDICARG=0x0;// CMD17/18地址参数RERDCMD:switch(mode){case POL:if(block<2)// SINGLE_READ写单块{rSDICCON=(0x1<<9)|(0x1<<8)|0x51;//CMD17为短应答并等待应答,开始发//送CMD17单块读命令,开始读,产生RSP1if(!Chk_CMDend(17, 1))//-- Check end of CMD17goto RERDCMD;//失败,继续发送}else// MULTI_READ,读多块{rSDICCON=(0x1<<9)|(0x1<<8)|0x52;//CMD18为短应答并等待应答,开始发//送CMD18多块读命令,开始读,产生RSP1 if(!Chk_CMDend(18, 1))//-- Check end of CMD18goto RERDCMD;//失败,继续发送}rSDICSTA=0xa00;// 清命令和应答结束标志while(rd_cnt<128*block)// 512块个字节{if((rSDIDSTA&0x20)==0x20)// 是否超时{rSDIDSTA=(0x1<<0x5);// 清超时标志位break;}status=rSDIFSTA;if((status&0x1000)==0x1000)// FIFO非空{*Rx_buffer++=rSDIDAT;rd_cnt++;}}break;case INT:pISR_SDI=(unsigned)Rd_Int;rINTMSK =~(BIT_SDI);//屏蔽除所有其他中断rSDIIMSK=5;// 开启Last & Rx FIFO half 中断.if(block<2)// SINGLE_READ{rSDICCON=(0x1<<9)|(0x1<<8)|0x51;//CMD17为短应答并等待应答,开始发//送CMD17单块读命令,开始读,产生RSP1if(!Chk_CMDend(17, 1))//-- Check end of CMD17goto RERDCMD;//失败,继续发送}else// MULTI_READ{rSDICCON=(0x1<<9)|(0x1<<8)|0x52;//CMD18为短应答并等待应答,开始发//送CMD18多块读命令,开始读,产生RSP1 if(!Chk_CMDend(18, 1))//-- Check end of CMD18goto RERDCMD;//失败,继续发送}rSDICSTA=0xa00;// 清命令和应答结束标志while(rd_cnt<128*block);rINTMSK |=(BIT_SDI);//屏蔽BIT_SDI中断rSDIIMSK=0;//屏蔽所有中断break;case DMA:pISR_DMA0=(unsigned)DMA_end;rINTMSK =~(BIT_DMA0);rSDIDCON=rSDIDCON|(1<<24);//YH 040227, Burst4 Enable rDISRC0=(int)(SDIDAT);// SDIDATrDISRCC0=(1<<1)+(1<<0);// APB, fixrDIDST0=(U32)(Rx_buffer);// Rx_bufferrDIDSTC0=(0<<1)+(0<<0);// AHB, incrDCON0=(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-swtriggerrSDIDCON=(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, CMD17if(!Chk_CMDend(17, 1))//-- Check end of CMD17goto RERDCMD;}else// MULTI_READ{rSDICCON=(0x1<<9)|(0x1<<8)|0x52;// sht_resp, wait_resp, dat, start, CMD18if(!Chk_CMDend(18, 1))//-- Check end of CMD18goto 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 stopbreak;default:break;}//-- Check end of DATAif(!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 detectif(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 CMD12if(!Chk_CMDend(12, 1))。
SD卡的结构原理和基本读写操作方式

SD卡的结构原理和基本读写操作方式摘要:本文首先介绍了SD Memory Card ( Secure D ig ita l MemoryCard)的基本结构和原理,着重对SD 卡的命令字和操作流程进行介绍。
接着研究了三星32位嵌入式处理器S3C2410与SD 卡硬件接口电路及其对SD卡的基本读写操作方式。
1 引言SD卡( Secure DigitalMemory Card)是一种基于Flash的新一代存储器,它着重数据存储的安全、容量和性能,是许多便携式电子产品如数码相机、手提电话, PDA 等理想的外部存储介质。
2 SD的基本概念2. 1 SD的通信协议SD卡系统可以在两种通信协议下工作: SD协议和SP I协议。
用户可以在硬件初始化时自由选择SD卡系统的通信协议。
对于特定的硬件电路,用户只需使用一种通信协议即可。
本文根据笔者的硬件,仅讨论最常用的SD协议。
2. 2 SD数据传输方式SD支持两种数据传输方式: 1 - bit方式(标准总线)和4- bit方式(宽总线)。
在1 - bit方式下,数据仅仅在数据线0(DAT[ 0 ])上传输。
在4 - bit方式下,数据在4 根数据线(DAT[ 3: 0 ])上同时传输。
在4 - bit数据传输方式下,最高的数据传输速率可达100Mb / sec。
表1列出了在两种方式下SD接口信号的定义。
上电后,缺省状态下系统工作于1 - bit方式。
在SD卡处于传输状态时,用户可以自由地更改为1 - bit或4 - bit方式。
2. 3 SD 通信原理SD总线是一个星型的总线结构,系统中允许有一个主控器,最多可达十个从设备( SD卡)。
在系统初始化时,主控器分别为每一个设备分配一个设备地址,此后主控器就可以根据此设备地址独立操作该设备。
SD总线通信是基于命令和数据位流的,每一个数据流都包括一个起始位和一个结束位。
每一个SD命令表征一个卡操作的开始。
SD命令由命令线(CMD)进行传输。
SD卡读写操作详细说明

51单片机实现对SD卡的读写SD卡SPI模式下与单片机的连接图:22.23.//获得16位的回应24. Read_Byte_SD(); //read the first byte,ignore it.25.do26. { //读取后8位27. tmp = Read_Byte_SD();28. retry++;29. }30.while((tmp==0xff)&&(retry<100));31.return(tmp);32.}2)初始化SD卡的初始化是非常重要的,只有进行了正确的初始化,才能进行后面的各项操作。
在初始化过程中,SPI的时钟不能太快,否则会造初始化失败。
在初始化成功后,应尽量提高SPI的速率。
在刚开始要先发送至少74个时钟信号,这是必须的。
在很多读者的实验中,很多是因为疏忽了这一点,而使初始化不成功。
随后就是写入两个命令CMD0与CMD1,使SD卡进入SPI模式初始化时序图:初始化例程:1.//--------------------------------------------------------------------------2.初始化SD卡到SPI模式3.//--------------------------------------------------------------------------4.unsigned char SD_Init()5.{6.unsigned char retry,temp;7.unsigned char i;8.unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};9. SD_Port_Init(); //初始化驱动端口10.11. Init_Flag=1; //将初始化标志置112.13.for (i=0;i<0x0f;i++)14. {15. Write_Byte_SD(0xff); //发送至少74个时钟信号16. }17.18.//向SD卡发送CMD019. retry=0;20.do21. { //为了能够成功写入CMD0,在这里写200次22. temp=Write_Command_SD(CMD);23. retry++;24.if(retry==200)25. { //超过200次26.return(INIT_CMD0_ERROR);//CMD0 Error!27. }28. }29.while(temp!=1); //回应01h,停止写入30.31.//发送CMD1到SD卡32. CMD[0] = 0x41; //CMD133. CMD[5] = 0xFF;34. retry=0;35.do36. { //为了能成功写入CMD1,写100次37. temp=Write_Command_SD(CMD);38. retry++;39.if(retry==100)40. { //超过100次41.return(INIT_CMD1_ERROR);//CMD1 Error!4.unsigned char Read_CSD_SD(unsigned char *Buffer)5.{6.//读取CSD寄存器的命令7.unsigned char CMD[] = {0x49,0x00,0x00,0x00,0x00,0xFF};8.unsigned char temp;9. temp=SD_Read_Block(CMD,Buffer,16); //read 16 bytes10.return(temp);11.}4)读取SD卡信息综合上面对CID与CSD寄存器的读取,可以知道很多关于SD卡的信息,以下程序可以获取这些信息。
sd卡模块读写

#include <reg51.h>//============================================================================= =================================//SD卡驱动程序//============================================================================= ==================================//定义SD卡需要的4根信号线sbit SD_OUT = P2^2;sbit SD_SCK = P2^3;sbit SD_DIN = P2^1;sbit SD_CS = P2^0;#define uchar unsigned char#define uint unsigned int//===========================================================//定义256字节缓冲区,注意需要使用xdata关键字unsigned char xdata BUFFER[512];code uchar BUFFER1[512]={0x1C,0x0a,0x0c,0x0d,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };//===========================================================/*写一字节到SD卡,模拟SPI总线方式*/void SdWrite(uchar DATA){uchar i;for(i=0;i<8;i++){DATA<<=1;SD_SCK=0;SD_DIN=CY;SD_SCK=1;}SD_DIN=1;}//===========================================================/*从SD卡读一字节,模拟SPI总线方式*/unsigned char SdRead(){uchar DATA,i;SD_OUT=1;for(i=0;i<8;i++){DATA<<=1;SD_SCK=0;SD_SCK=1;DATA|=SD_OUT;}return DATA;}//============================================================/*检测SD卡的响应*/unsigned char SdResponse(){unsigned char i=0,response;while(i<=8){response = SdRead();if(response==0x00)break;if(response==0x01)break;i++;}return response;}//================================================================/*发命令到SD卡,SD的一个命令由6个字节组成,关于SD的命令介绍,请看本文件的PDF 的介绍command:第一字节:命令号;argument:第2-5字节;CRC:第6字节校验位;*/void SdCommand(unsigned char command, unsigned long argument, unsigned char CRC) //unsigned long :32位的变量,包含SD的第2-5字节{SdWrite(command|0x40);//发送命令号SdWrite(((unsigned char *)&argument)[0]);//发送第2字节SdWrite(((unsigned char *)&argument)[1]);//发送第3字节SdWrite(((unsigned char *)&argument)[2]);//发送第4字节SdWrite(((unsigned char *)&argument)[3]);//发送第5字节SdWrite(CRC); //发送CRC}//================================================================/*初始化SD卡*/unsigned char SdInit(void){int delay=0, trials=0;unsigned char i;unsigned char response=0x01;SD_CS=1;//上点完成后,先对SD卡发送74个以上的同步时钟!!这是必须的for(i=0;i<=9;i++)SdWrite(0xff);SD_CS=0;//发送CMD0命令:对SD进行复位操作SdCommand(0x00,0,0x95);//每发一次命令那个,都会对应着一个响应response=SdResponse();//CMD0对应的响应为0x01if(response!=0x01){return 0;}//SD卡默认的读写方式为SD模式,所以当SD复位完成后,要使SD进入SPI模式while(response==0x01){SD_CS=1;SdWrite(0xff);SD_CS=0;//发送CMD1指令,使SD卡进入SPI模式SdCommand(0x01,0x00ffc000,0xff);response=SdResponse();}//CS线拉高,在发送8个空时钟SD_CS=1;SdWrite(0xff);return 1;}//================================================================/*往SD卡指定地址写数据,一次最多512字节*/unsigned char SdWriteBlock(unsigned char *Block, unsigned long address,int len){unsigned int count;unsigned char response;//Block size is 512 bytes exactly//First Lower SSSD_CS=0;//发送写命令;CMD18:块写入命令;address:为写入的地址,必须是512的倍倍数SdCommand(0x18,address,0xff);//改命令对应的应答位0x00if(SdResponse()==00){//发送若干个空操作SdWrite(0xff);SdWrite(0xff);SdWrite(0xff);//写0xfe数据头,表示接下来要发送字节块SdWrite(0xfe);//开始输入数据for(count=0;count<len;count++) SdWrite(*Block++);/*检测语句,当len<512个字节时,用0去代替剩下的数,因为一次写入的字节长度必须是512的倍数*/for(;count<512;count++) SdWrite(0);/*两字节CRC校验, 为0XFFFF 表示不考虑CRC,SD在SPI模式下是不需要考虑CRC校验码的,但也可以发送0xff来代替*/ SdWrite(0xff);SdWrite(0xff);//读取校验码,此时对应的响应为xxx00101response=SdRead();while(SdRead()==0);//等待卡数据发送回应/*因为响应命令为xxx00101,它的最高三位是不能确定的所以让它与0x0f"与"一下,那么它的高三位就变为0了*/response=response&0x0f;SD_CS=1;SdWrite(0xff);if(response==0x0b)//判断是否为正确的响应{return 0;}if(response==0x05)return 1;///return 0;}return 0;}//======================================================================= /*从SD卡指定地址读取数据,一次最多512字节*/unsigned char SdReadBlock(unsigned char *Block, unsigned long address,int len){unsigned int count;SD_CS=0;//CMD11:数据块读命令,add:为要读块的地址SdCommand(0x11,address,0xff);if(SdResponse()==00){//0xfe:为块读出的头,由SD发送;后面紧跟512字节的块数据+2字节的CRC码while(SdRead()!=0xfe);for(count=0;count<len;count++)if(count<256)*Block++=SdRead();elseSdRead();for(;count<512;count++) SdRead();//发送空时钟SdRead();SdRead();//SD_CS拉高SD_CS=1;SdRead();return 1;}return 0;}//======================================================================= /*串口初始化*/void init(){/*波特率为9600;使用的晶振为:11.0592;*/TMOD=0X20;TH1=0XFD;TL1=0XFD;TR1=1;SCON=0X50;EA=1;ES=1;}//======================================================================= /*主函数*/void main(){unsigned char i;/*串口,SD卡的初始化*/init();SdInit();/*讲BUFFER1[512]数组的内容发送给SD卡,保存地址为512;注意地址最后不要太大,取决与SD本身;在读取SD卡的512地址的内容保存在BUFFER[]数组中*/ SdWriteBlock(BUFFER1,512,512);SdReadBlock(BUFFER,512,512);/*让串口发送BUFFER[]的内容,来检测数据是否成功写入SD卡内*/for(i=0;i<7;i++){SBUF=BUFFER[i];while(!TI);TI=0;}while(1);}。
SD卡读写的方式(用SD模式)

SD卡读写的方式(用SD模式)大家读写SD卡怎么不用SD模式方式读取,是SPI方式读取简单?下面贴一段代码,是在FPGA上程序,只能用SD模式进行读,没有文件系统,没有用AVR硬件实现,电路图:电路说明,SD_DAT3一直给高电平程序:#ifndef __SD_Card_H__#define __SD_Card_H__#define High 1#define Low 0//-------------------------------------------------------------------------// SD Card Set I/O Direction#define SD_CMD_IN DDRX.1 = Low#define SD_CMD_OUT DDRX.1 = High#define SD_DAT_IN DDRX.2 = Low#define SD_DAT_OUT DDRX.2 = High#define SD_CLK_OUT DDRX.3 = High#define SD_DAT3_OUT DDRX.0 = High// SD Card Output High/Low#define SD_CMD_LOW PORTX.1 = Low#define SD_CMD_HIGH PORTX.1 = High#define SD_DAT_LOW PORTX.2 = Low#define SD_DAT_HIGH PORTX.2 = High#define SD_CLK_LOW PORTX.3 = Low#define SD_CLK_HIGH PORTX.3 = High#define SD_DAT3_HIGH PORTX.0 = High// SD Card Input Read#define SD_TEST_CMD PINX.1#define SD_TEST_DAT PINX.2//------------------------------------------------------------------------- #define BYTE unsigned char#define UINT16 unsigned int#define UINT32 unsigned long//------------------------------------------------------------------------- void Ncr(void);void Ncc(void);BYTE response_R(BYTE);BYTE send_cmd(BYTE *);BYTE SD_read_lba(BYTE *,UINT32,UINT32);BYTE SD_card_init(void);//------------------------------------------------------------------------- BYTE read_status;BYTE response_buffer[20];BYTE RCA[2];BYTE cmd_buffer[5];const BYTE cmd0[5] = {0x40,0x00,0x00,0x00,0x00};const BYTE cmd55[5] = {0x77,0x00,0x00,0x00,0x00};const BYTE cmd2[5] = {0x42,0x00,0x00,0x00,0x00};const BYTE cmd3[5] = {0x43,0x00,0x00,0x00,0x00};const BYTE cmd7[5] = {0x47,0x00,0x00,0x00,0x00};const BYTE cmd9[5] = {0x49,0x00,0x00,0x00,0x00};const BYTE cmd16[5] = {0x50,0x00,0x00,0x02,0x00};const BYTE cmd17[5] = {0x51,0x00,0x00,0x00,0x00};const BYTE acmd6[5] = {0x46,0x00,0x00,0x00,0x02};const BYTE acmd41[5] = {0x69,0x0f,0xf0,0x00,0x00};const BYTE acmd51[5] = {0x73,0x00,0x00,0x00,0x00};//------------------------------------------------------------------------- void Ncr(void){SD_CMD_IN;SD_CLK_LOW;SD_CLK_HIGH;SD_CLK_LOW;SD_CLK_HIGH;}//------------------------------------------------------------------------- void Ncc(void){int i;for(i=0;i<8;i++){SD_CLK_LOW;SD_CLK_HIGH;}}//------------------------------------------------------------------------- BYTE SD_card_init(void){BYTE x,y;SD_CMD_OUT;SD_DAT_IN;SD_CLK_HIGH;SD_CMD_HIGH;SD_DAT_LOW;read_status=0;for(x=0;x<40;x++)Ncr();for(x=0;x<5;x++)cmd_buffer[x]=cmd0[x];y = send_cmd(cmd_buffer);do{for(x=0;x<40;x++);Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd55[x];y = send_cmd(cmd_buffer);Ncr();if(response_R(1)>1) //response too long or crc errorreturn 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=acmd41[x];y = send_cmd(cmd_buffer);Ncr();} while(response_R(3)==1); Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd2[x];y = send_cmd(cmd_buffer); Ncr();if(response_R(2)>1) return 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd3[x];y = send_cmd(cmd_buffer); Ncr();if(response_R(6)>1) return 1;RCA[0]=response_buffer[1]; RCA[1]=response_buffer[2]; Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd9[x]; cmd_buffer[1] = RCA[0]; cmd_buffer[2] = RCA[1];y = send_cmd(cmd_buffer); Ncr();if(response_R(2)>1) return 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd7[x]; cmd_buffer[1] = RCA[0];cmd_buffer[2] = RCA[1];y = send_cmd(cmd_buffer);Ncr();if(response_R(1)>1)return 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd16[x];y = send_cmd(cmd_buffer);Ncr();if(response_R(1)>1)return 1;read_status =1; //sd card readyreturn 0;}//------------------------------------------------------------------------- BYTE SD_read_lba(BYTE *buff,UINT32 lba,UINT32 seccnt) {BYTE c=0;UINT32 i,j;lba+=101;for(j=0;j<seccnt;j++)< p="">{{Ncc();cmd_buffer[0] = cmd17[0];cmd_buffer[1] = (lba>>15)&0xff; cmd_buffer[2] = (lba>>7)&0xff; cmd_buffer[3] = (lba<<1)&0xff; cmd_buffer[4] = 0;lba++;send_cmd(cmd_buffer); Ncr();}while(1){SD_CLK_LOW;SD_CLK_HIGH;if(!(SD_TEST_DAT)) break;}for(i=0;i<512;i++) {BYTE k;for(k=0;k<8;k++){SD_CLK_LOW;SD_CLK_HIGH;c <<= 1;if(SD_TEST_DAT)c |= 0x01;}*buff=c;buff++;}for(i=0; i<16; i++) {SD_CLK_LOW;SD_CLK_HIGH;}}read_status = 1; //SD data next inreturn 0;}//------------------------------------------------------------------------- BYTE response_R(BYTE s){BYTE a=0,b=0,c=0,r=0,crc=0;BYTE i,j=6,k;while(1){SD_CLK_LOW;SD_CLK_HIGH;if(!(SD_TEST_CMD))break;if(crc++ >100)return 2;}crc =0;if(s == 2)j = 17;for(k=0; k<="" p="">{c = 0;if(k > 0) //for crc culcarb = response_buffer[k-1];for(i=0; i<8; i++){SD_CLK_LOW;if(a > 0)c <<= 1;elsei++;a++;SD_CLK_HIGH;if(SD_TEST_CMD)c |= 0x01;if(k > 0){crc <<= 1;if((crc ^ b) & 0x80)crc ^= 0x09;b <<= 1;crc &= 0x7f;}}if(s==3){if( k==1 &&(!(c&0x80)))r=1;}response_buffer[k] = c;}if(s==1 || s==6){if(c != ((crc<<1)+1))r=2;}return r;}//------------------------------------------------------------------------- BYTE send_cmd(BYTE *in) {int i,j;BYTE b,crc=0;SD_CMD_OUT;for(i=0; i < 5; i++){b = in[i];for(j=0; j<8; j++){SD_CLK_LOW;if(b&0x80)SD_CMD_HIGH;elseSD_CMD_LOW;crc <<= 1;SD_CLK_HIGH;if((crc ^ b) & 0x80)crc ^= 0x09;b<<=1;}crc &= 0x7f;}crc =((crc<<1)|0x01);b = crc;for(j=0; j<8; j++){SD_CLK_LOW;if(crc&0x80)SD_CMD_HIGH;elseSD_CMD_LOW;SD_CLK_HIGH;crc<<=1;}return b;}//-------------------------------------------------------------------------#endif这些程序有些我也不明白,贴出来希望大家一起探讨交流,打破网站SD卡用SPI方式读写的垄断局面,哈哈sd模式下应该有4各data吧,怎么你的只用一个?SPI模式是1Bit的SD模式是1Bit或4BitSD卡确实也像USB一样分为全速(FULL-SPEED)卡和低速卡(LOW-SPEED)。
单片机读写SD卡

结束语
实验结果表明单片机使用12MHz的晶体振荡器时,读写速度和功耗都基本令人满意,可以应用于对读写速度要求不高的情况下。本文详细阐述了用AT89C52单片机对SD卡进行操作的过程,提出了一种不带SD卡控制器,MCU读写SD卡的方法,实现了SD卡在电能监测及无功补偿数据采集系统中的用途
SPI_TransferByte(0xff);
SPI_TransferByte(0xff);
retry=0;
do{ temp=Write_Command_SD(SD_INIT,0);
//发送初始化命令
retry++;
if(retry==100) //重试100次
{SD_Disable(); //关片选
return(INIT_CMD1_ERROR);
//如果重试100次失败返回错误号
}
}while(temp!=0);
SD_Disable(); //关片选
ቤተ መጻሕፍቲ ባይዱ return(TRUE); //返回成功
}
数据块的读写
本文的实现程序把SPI总线读写功能集成在一起,传递的val变量既是向SPI写的数据,也是从SPI读取的数据。具体程序如下:(程序是在Keil uVision2的编译环境下编写)
SD卡的读写和加解密

查看文章SD卡的读写和加解密2007-06-13 07:04SD卡的读写和加解密一、概述SD卡全称为Secrue Digital Memory Card,具有轻巧、可加密、传输速度高、适用于手持设备使用等优点。
二、总线接口SD需要高速读写,同时也要使手持等嵌入式设备能方便使用,特设有两个访问接口中:SD 模式接口和SPI接口。
SD卡在上电初期,卡主控通过检测引脚1(DA T3)来决定使用SD 模式还是SPI模式。
当此脚接50KOhm上拉电阻时,卡进入SD模式;当此脚为低电平,卡则工作于SPI模式。
SD引脚SD模式SPI模式1 DA T3 CS2 CMD DI3 VSS VSS4 VDD VDD5 CLK SCLK6 VSS VSS7 DA T0 DO8 DA T1 Resvered9 DA T2 Resvered表1:SD卡接口定义1、SPI接口SPI接口是为嵌入式和手持设备准备的,只使用普通的三线制SPI总线,即可对卡进行一般的慢速的读写等操作。
图一:SPI总线如上图,由读卡器到卡的数据,在每个时种的上升沿把DO的数据锁存到卡主控,而卡的数据则在每个CLK的上升沿把DI的数据读入读卡器。
2、SD接口SD接口是为高速专有设备而设计,使设备能对卡进行高速可靠的传输而设计,因SD模式在每个命令及数据转输时,都必须具有正确的CRC校验。
因此,此模式下主机一般需要专门设计的硬件模块以产生CRC校验。
在此模式下,SD卡具有四根数据线,且时种速度最大可达50MHz,所以此模式下数据传输速率比SPI模式快得多。
三、总线协议SD卡命令共分为12类,分别为class0到class11,不同的卡主控根据其功能,支持不同的命令集。
主要如下:class0:卡的识别、初始化命令集。
class2:读卡命令集class4:写卡命令集class7:卡的锁定,解锁功能命令集SD卡只有唯一的主机,所有命令是由主机发出。
总线上可传输三种类型数据,分别是命令帧、响应、数据。
SD卡文件系统读写

SD 文件系统U n R e g i st er ed32514Un R e gd一、SD 卡概述v 1、SD卡简介(1)nSD卡(Secure Digital Memory Card)是一种基于半导体快闪记忆器的新一代记忆设备。
nSD卡数据传送和物理规范由MMC发展而来Un Re gi st er ed一、SD 卡概述v 1、SD卡简介(2)n特点:大容量、高性能、安全性高。
n用途:可用在MP3、移动电话、PDA、数码相机、数码摄像机、电子图书、微型电脑、AV器材等领域。
n数据传输速率:SD卡读写速度比MMC卡要快四倍,最大速率可达到10MB/秒。
n几种SD卡的区分:普通SD,高速SD,SDHC。
Un Re gi st er ed2、SD卡内部结构SD卡由9线接口控制,数据线包括:CMD,CLK,DAT0-st er ed一、SD 卡概述v 3、SD通信模式n一个主机一般情况下可以挂多张SD卡,最大10个堆叠的卡。
n主机访问模式:SD模式;SPI模式Un Re gi st er ed一、SD 卡概述v 4、SD卡通信n主机和SD卡之间的通信是通过命令和数据流实现的,如下图所示:n命令发送/数据传输Un Re gi st er ed二、SD 卡通信协议v 1、SD卡接口可以支持两种操作模式1、SD卡模式2、SPI模式n主机系统可以选择以上其中任一模式,SD卡模式允许4线的高速数据传输。
SPI模式允许简单通用的SPI通道接口,这种模式相对于SD模式的不足之处是丧失了速度。
Un Re gi st er ed二、SD 卡通信协议nSD模式总线连接图n SD模式(1)Un Re gi st er ed二、SD 卡通信协议nSD模式针脚定义nSD总线允许1线和4线数据信号设置。
n SD模式(2)Un Re gi st er ed二、SD 卡通信协议nSPI模式连接图n SPI模式(1)Un Re gi st er ed二、SD 卡通信协议nSPI模式针脚定义n注意:SPI模式时,数据信号需要在主机端用10-100K欧的上拉电阻。
sd卡数据读写流程

sd卡数据读写流程SD卡是一种常见的存储媒介,它具有轻便、易携带、容量大、存储速度快等优势。
SD卡数据读写流程是指将数据从SD卡中读取出来或将数据写入SD卡中的整个过程。
一、SD卡的物理结构SD卡主要由控制器、记忆芯片和接口组成。
控制器负责管理SD卡的读写操作;记忆芯片是存储数据的核心部件,它采用闪存技术,可存储数据并保持数据不易丢失;接口是SD卡与主控制器进行通信的桥梁,一般采用SPI(串行外设接口)或SDIO(SD输入输出)接口。
二、SD卡读写流程1.初始化SD卡当主控制器接通SD卡电源时,首先要进行初始化操作。
初始化操作主要包括向SD卡发送复位命令、读取SD卡的OCR(操作条件寄存器)以及设置SPI或SDIO接口的工作参数等操作。
2.读取SD卡信息在SD卡初始化成功后,主控制器通过SPI或SDIO接口向SD 卡发送命令,读取SD卡ID信息、SD卡容量、SD卡速度等重要参数。
这些信息将在数据读写时起到重要作用。
3.读取文件SD卡上的文件存储在文件系统中,主控制器需要先读取文件系统,找到要读取的文件所在的位置。
一般情况下,文件系统采用FAT32格式,主控制器需要读取文件系统启动区扇区信息,从而找到文件所在扇区及其起始地址。
4.读取数据在找到文件所在位置后,主控制器就可以根据文件系统的信息,向SD卡发送读操作指令,读取文件数据。
读取数据时,主控制器需要根据SD卡的速度、数据传输模式等参数设置接口波特率、时序等参数。
5.写入数据SD卡写数据流程与读数据基本相同,只是主控制器需要向SD卡发送写操作指令,将数据写入SD卡中。
写入数据时,主控制器需要根据SD卡的容量、速度等参数设置写入数据的起始位置、写入数据的长度、写入数据的校验和等参数。
6.关闭SD卡当读写操作完成后,主控制器需要向SD卡发送停止指令,将SD卡彻底关闭。
关闭SD卡可以避免SD卡数据丢失、损坏等问题。
三、SD卡的数据保护SD卡存储的数据非常重要,因此在SD卡的读写过程中,需要采取一定的措施保护数据。
SPI通信与SD卡

SPI通信与SD卡一、前言SD 卡有两个可选的通讯协议:SD 模式和SPI模式SD 模式是SD 卡标准的读写方式,但是在选用SD 模式时,往往需要选择带有SD 卡控制器接口的MCU,或者必须加入额外的SD卡控制单元以支持SD 卡的读写然而,大多数MCU都没有集成SD 卡控制器接口,若选用SD 模式通讯就无形中增加了产品的硬件成本。
在SD卡数据读写时间要求不是很严格的情况下,选用SPI模式可以说是一种最佳的解决方案因为在SPI 模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多MCU都集成有现成的SPI接口电路,采用SPI模式对SD卡进行读写操作可大大简化硬件电路的设计二、硬件电路实现以NXP的LPC2210 ARM7MCU为例,下图是周立功开发的实现板电路这里,将LPC2210MCU的SPI0用于SD卡的控制和数据读写。
对SPI0的两个数据线加了上拉电阻以便于MMC卡兼容。
卡供电采用了可控方式,通过GPIO口控制MOS管对其进行供电。
卡检测电路也使用GPIO口实现。
通过读GPIO口数据,检查卡是否写保护和完全插入。
具体内容可以参考周立功的说明书,百度文库里边有三、SD卡物理接口我们看到的SD卡一包如下所示,包含9个引脚和一个写保护开关:其引脚定义如下:注:1. S:电源;I:输入;O:推挽输出;PP:推挽I/O。
2. 扩展的DAT线(DAT1 ~ DAT3)在上电后处于输入状态。
它们在执行SET_BUS_WIDTH命令后作为DAT线操作。
当不使用DAT1 ~ DAT3 线时,主机应使自己的DAT1~DAT3线处于输入模式。
这样定义是为了与MMC卡保持兼容。
3. 上电后,这条线为带50KΩ上拉电阻的输入线(可以用于检测卡是否存在或选择SPI 模式)。
用户可以在正常的数据传输中用SET_CLR_CARD_DETECT(ACMD42)命令断开上拉电阻的连接。
MMC卡的该引脚在SD模式下为保留引脚,在SD模式下无任何作用。
SD卡总结

1、SD 卡支持两种总线方式:SD 方式与 SPI 方式。
SD 方式采用6线制,使用 CLK、CMD、DAT0、DAT1、DAT2、DAT3 进行数据通信,其特点是数据位数宽(4 位)、速度快。
SPI 方式采用4线制,使用 CS、CLK、DataIn、DataOut这4个端口进行数据通信,其特点是速度要比 SD 方式慢,但总线简单、不需要进行 CRC 校验,因而比较适合单片机采用这种方式对SD卡进行读写操作。
3、电路4、SD 卡的命令字由 6 个字节组成命令字的第1个字节为命令号(CMD0、CMD1 等),命令号的最高位始终为 0,次高位(位 7)为1,表示命令是由主机向 SD 卡发送的命令。
命令字的第2、3、4、5字节为命令参数表,传送随命令附带的参数,如地址信息等。
命令字的最后一个字节为 CRC 校验字节,其中该字节的高7位为 CRC 码,最后一位为结束位,始终为1。
当主机向 SD 卡发送一个命令后,SD 卡会首先向主机发送一个相应码,如果指令没有错误 SD 卡接下来便会执行主机发来的命令。
5、SD 卡复位至 SPI 方式SD 卡默认的读写方式为 SD 模式,要使用 SPI 模式对 SD 卡进行读写,需要在 SD 卡上电后对 SD 卡写入 CMD0 和 CMD1 命令。
在两条命令写入 SD 卡后,如果一切正常,SD 卡会进入 SPI 模式,从而可以方便地采用单片机对 SD 卡进行 SPI 方式的读写操作。
当 SD 卡完成上电后,先对 SD 卡发送 74 个以上的同步时钟。
然后向 SD 卡发送 CMD0 命令(因命令号的最高位始终为 0,次高位为 1,因此发送给 SD 卡的命令是 0 与 0x40 进行或运算的结果)。
命令字的第 2、3、4、5 字节皆为 0x00。
命令字的第 6 字节为 CRC 校验字节,固定为 0x95。
命令字发送完成后,发送若干个 8 位的同步时钟,直至 SD 卡发出响应字节0x01。
SPI模式下SD卡的读写

SPI模式下SD卡的读写李书巳【摘要】SD卡具有移动性、体积小、容量大、易保存等许多优点,如今越来越多的被用于生产控制装置。
SD卡支持两种总线模式:SD模式与SPI模式。
SD模式时的数据传输速度与SPI模式要快,但是SD模式的协议复杂,采用单片机对SD 卡进行读写时一般都采用SPI模式。
采用不同的初始化方式可以使SD卡工作于SD模式或SPI模式。
本文以STC12C5A60S2单片机为例详细的介绍了SD卡在SPI模式下的读写操作过程。
【期刊名称】《数字技术与应用》【年(卷),期】2015(000)001【总页数】1页(P76-76)【关键词】SD卡读写;SPI模式;STC12C5A60S2单片机【作者】李书巳【作者单位】沈阳市苏家屯区职业教育中心辽宁沈阳 110102【正文语种】中文【中图分类】TP333.5随着科技的发展SD卡在人们的生活中被广泛的使用,由于SD卡具有移动性、体积小、容量大、易保存等许多优点如今越来越多的被用于生产控制装置。
一些设计开发人员会经常利用单片机对SD卡进行读写操作,下面就本人在SPI模式下SD 卡读写过程中遇到的一些问题与各位读者交流。
以STC12C5A60S2单片机为例,SPI模式下连接方法如图1,其中CS是片选端口为低电平有效,DI是SD卡写入数据端口即单片机输出数据,DO是单片机从SD卡读数据端口,CLK是同步时钟脉冲信号。
通常SD具有两种读写模式,一种是SD模式,SD卡被接通电源后就自动进入SD 模式,SD模式利用四条数据线可以实现数据并行传输,具有较高的传输速率。
但是其通讯协议比较复杂,并且多数单片机没提供专门的接口,如果用软件编写协议会使程序变得繁琐复杂,甚至影响数据传输效率。
另一种是SPI模式,我们在通电后将CS置“1”向SD卡CLK端发送至少74个时钟周期然后将CS置“0”向DI 端发送CMD0复位指令,然后向CLK发送时钟信号等待DO端回复“01H”表示复位成功,此时SD卡已进入SPI模式,并处在空闲状态。
SD卡基础知识学习笔记

SD 学习笔记一、SD卡基础知识1. SD卡概念与种类SD卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪记忆器的新一代记忆设备。
SD卡的物理规格、管脚功能和数据传输协议是与MMC(Multimedia Card)前向兼容的。
它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器。
SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制。
大小犹如一张邮票的SD记忆卡,重量只有2克,但却拥有高记忆容量、快速数据传输率、极大的移动灵活性以及很好的安全性。
MicroSD卡。
SD卡标准时SD卡协会针对可移动存储设备设计专利并授权的一种标准,主要用于制定卡的外型尺寸、电气接口和通信协议。
1.1SD卡的外型尺寸图1:SD卡外型尺寸1.2SD卡的引脚SD卡有9个引脚。
SD卡支持两种模式工作,SD模式与SPI模式。
不同的模式选择,SD卡引脚的功能不同。
MicroSD卡有8个引脚。
SD 卡和MicroSD 的卡套内部结构。
因为卡套的pin3(gnd)空缺,所以MicroSD 插入SD 卡套后,操作应该是和标准的SD 是一样的。
图2:MicroSD 卡的8个管脚表:MicroSD 卡管脚功能图3:MicroSD 转SD 卡套内部结构2. SD卡的协议与工作模式2.1 SD卡协议:点击下图标。
1E:\-S tud yS ou rce\卡协议中文M Y\sd().d oc2.2 SD卡工作模式:SD模式是SD卡标准的读写方式,但是在选用SD模式时,往往需要选择带有SD卡控制器接口的MCU,或者必须加入额外的SD卡控制单元以支持SD卡的读写。
在SD卡数据读写时间要求不是很严格的情况下,选用SPI模式可以降低硬件成本。
因为在SPI模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多的MCU都集成有现成的SPI 接口电路,采用SPI模式对SD卡进行读写操作可大大简化硬件电路的设计。
SD卡的管脚排列和总线读写方式

SD卡的管脚排列和总线读写方式
SD 卡的引脚定义:
管脚排列和总线读写方式name=image_operate_52221302162801312 real_src=s12.sinaimg/middle/5e374701ga04f0776e47b690
src=s12.sinaimg/middle/5e374701ga04f0776e47b690 title=[转载]SD 卡的管脚排列和总线读写方式/
SD 卡引脚功能详述:
注:S:电源供给I:输入O:采用推拉驱动的输出
PP:采用推拉驱动的输入输出
SD 卡支持两种总线方式:
SD 方式与SPI 方式。
SD 模式是SD 卡标准的读写方式,但是在选用SD 模
式时,往往需要选择带有SD 卡控制器接口的MCU,或者必须加入额外的SD
卡控制单元以支持SD 卡的读写。
然而,很多51 单片机没有集成SD 卡控制器
接口,若选用SD 模式通讯就无形中增加了产品的硬件成本。
在SD 卡数据读
写时间要求不是很严格的情况下,选用SPI 模式可以说是一种最佳的解决方案。
我用软件模拟出SPI 总线时序读写SD 卡。
其中SD 方式采用6 线制,使用CLK、CMD、DAT0~DAT3 进行数据通信。
而SPI 方式采用4 线制,使用CS、CLK、DataIn、DataOut 进行数据通信。
SD 方式时的数据传输速度与SPI 方式要快,采用单片机对SD 卡进行读写时
一般都采用SPI 模式。
采用不同的初始化方式可以使SD 卡工作于SD 方式或
SPI 方式。
这里只对其SPI 方式进行介绍。
SD 卡SPI 模式下与单片机的连接图:。
SD卡读写操作详细说明

SD卡读写操作详细说明51单⽚机实现对SD卡的读写SD卡SPI模式下与单⽚机的连接图:22.23.//获得16位的回应24. Read_Byte_SD(); //read the first byte,ignore it.25.do26. { //读取后8位27. tmp = Read_Byte_SD();28. retry++;29. }30.while((tmp==0xff)&&(retry<100));31.return(tmp);32.}2)初始化SD卡的初始化是⾮常重要的,只有进⾏了正确的初始化,才能进⾏后⾯的各项操作。
在初始化过程中,SPI的时钟不能太快,否则会造初始化失败。
在初始化成功后,应尽量提⾼SPI的速率。
在刚开始要先发送⾄少74个时钟信号,这是必须的。
在很多读者的实验中,很多是因为疏忽了这⼀点,⽽使初始化不成功。
随后就是写⼊两个命令CMD0与CMD1,使SD卡进⼊SPI 模式初始化时序图:初始化例程:1.//--------------------------------------------------------------------------2.初始化SD卡到SPI模式3.//--------------------------------------------------------------------------4.unsigned char SD_Init()5.{6.unsigned char retry,temp;7.unsigned char i;8.unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};9. SD_Port_Init(); //初始化驱动端⼝10.11. Init_Flag=1; //将初始化标志置112.13.for (i=0;i<0x0f;i++)14. {15. Write_Byte_SD(0xff); //发送⾄少74个时钟信号16. }17.18.//向SD卡发送CMD019. retry=0;20.do21. { //为了能够成功写⼊CMD0,在这⾥写200次22. temp=Write_Command_SD(CMD);23. retry++;24.if(retry==200)25. { //超过200次26.return(INIT_CMD0_ERROR);//CMD0 Error!27. }28. }29.while(temp!=1); //回应01h,停⽌写⼊30.31.//发送CMD1到SD卡32. CMD[0] = 0x41; //CMD133. CMD[5] = 0xFF;34. retry=0;35.do36. { //为了能成功写⼊CMD1,写100次37. temp=Write_Command_SD(CMD);38. retry++;39.if(retry==100)40. { //超过100次41.return(INIT_CMD1_ERROR);//CMD1 Error!4.unsigned char Read_CSD_SD(unsigned char *Buffer)5.{6.//读取CSD寄存器的命令7.unsigned char CMD[] = {0x49,0x00,0x00,0x00,0x00,0xFF};8.unsigned char temp;9. temp=SD_Read_Block(CMD,Buffer,16); //read 16 bytes10.return(temp);11.}4)读取SD卡信息综合上⾯对CID与CSD寄存器的读取,可以知道很多关于SD卡的信息,以下程序可以获取这些信息。
SD卡读写操作详细说明

SD卡读写操作详细说明SD卡(Secure Digital Card)是一种常见的存储设备,广泛应用于各种数码设备,如相机、手机、音乐播放器等。
SD卡读写操作是指对SD卡进行数据的读取和写入操作。
本文将详细介绍SD卡的读写操作流程和相关细节。
一、SD卡读写操作的基本原理SD卡采用了Flash存储技术,数据的读写是通过对存储芯片中的电荷进行控制实现的。
每个存储单元可以存储一个位(0或1),多个存储单元可以组成字节、块等不同大小的数据单元。
二、SD卡的初始化在进行SD卡的读写操作之前,首先需要对SD卡进行初始化。
SD卡的初始化包括以下几个步骤:1.插入SD卡:将SD卡插入到SD卡插槽中。
2.电源供给:给SD卡供电,使其可以正常工作。
3.寻卡:通过命令与SD卡进行通信,找到SD卡并识别其属性和参数。
三、SD卡的读操作SD卡的读操作是指从SD卡中读取数据。
SD卡的读操作流程如下:1.发送读命令:通过控制器向SD卡发送读命令,告知SD卡要读取的数据的起始地址和长度。
2.接收应答:SD卡接收到读命令后,会返回一个应答信号,确认是否接收到了读命令。
3.读取数据:当SD卡接收到读命令后,在指定的地址范围内读取数据,并将数据传输给控制器。
4.数据传输:控制器接收到SD卡传输的数据后,将数据转发给主机或其他设备进行处理。
四、SD卡的写操作SD卡的写操作是指向SD卡中写入数据。
SD卡的写操作流程如下:1.发送写命令:通过控制器向SD卡发送写命令,告知SD卡要写入的数据的起始地址和长度。
2.接收应答:SD卡接收到写命令后,会返回一个应答信号,确认是否接收到了写命令。
3.写入数据:当SD卡接收到写命令后,在指定的地址范围内写入数据。
4.数据传输:控制器向SD卡传输要写入的数据,SD卡接收到数据后进行存储。
五、SD卡的块操作SD卡的读写操作是以块为单位进行的,一个块的大小一般为512字节。
SD卡的块操作流程如下:1.发送块命令:通过控制器向SD卡发送块命令,告知SD卡要进行块操作的起始块号和块数。
SD和MMC卡读写说明

目录第1章 SD/MMC卡读写模块 (1)1.1 SD/MMC卡的外部物理接口 (1)1.1.1 SD模式 (2)1.1.2 SPI模式 (3)1.2 访问SD/MMC卡的SPI模式硬件电路设计 (4)1.2.1 SPI总线 (5)1.2.2 卡供电控制 (5)1.2.3 卡检测电路 (5)1.3 SD/MMC卡读写模块的文件结构及整体构架 (5)1.3.1 SD/MMC卡读写模块的文件组成 (5)1.3.2 SD/MMC读写模块整体框架 (6)1.4 SD/MMC卡读写模块的使用说明 (6)1.4.1 SD/MMC卡读写模块的硬件配置 (6)1.4.2 SD/MMC卡读写模块提供的API函数 (9)1.5 SD/MMC卡读写模块的应用示例一 (11)1.5.1 硬件连接与配置 (11)1.5.2 实现方法 (11)1.6 SD/MMC卡读写模块的使用示例二 (18)1.6.1 实现方法 (18)1.6.2 例子建立与运行步骤 (20)1.6.3 参考程序 (24)1.7 SD/MMC软件包应用总结 (27)第1章SD/MMC卡读写模块SD/MMC卡是一种大容量(最大可达4GB)、性价比高、体积小、访问接口简单的存储卡。
SD/MMC卡大量应用于数码相机、MP3机、手机、大容量存储设备,作为这些便携式设备的存储载体,它还具有低功耗、非易失性、保存数据无需消耗能量等特点。
SD卡接口向下兼容MMC(MutliMediaCard多媒体卡)卡,访问SD卡的SPI协议及部分命令也适用于MMC卡。
SD/MMC卡读写模块是ZLG 系列中间件的重要成员之一,又称为ZLG/SD。
该模块是一个用来访问SD/MMC卡的软件读写模块,目前最新版本为2.00,本版本不仅能读写SD卡,还可以读写MMC卡;不仅能在前后台系统(无实时操作系统)中使用,还可以在嵌入式操作系统μC/OS-II中使用。
本文模块只支持SD/MMC卡的SPI模式。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
大家读写SD卡怎么不用SD模式方式读取,是SPI方式读取简单?下面贴一段代码,是在FPGA上程序,只能用SD模式进行读,没有文件系统,没有用AVR硬件实现,电路图:电路说明,SD_DAT3一直给高电平程序:#ifndef __SD_Card_H__#define __SD_Card_H__#define High 1#define Low 0//-------------------------------------------------------------------------// SD Card Set I/O Direction#define SD_CMD_IN DDRX.1 = Low#define SD_CMD_OUT DDRX.1 = High#define SD_DAT_IN DDRX.2 = Low#define SD_DAT_OUT DDRX.2 = High#define SD_CLK_OUT DDRX.3 = High#define SD_DAT3_OUT DDRX.0 = High// SD Card Output High/Low#define SD_CMD_LOW PORTX.1 = Low#define SD_CMD_HIGH PORTX.1 = High#define SD_DAT_LOW PORTX.2 = Low#define SD_DAT_HIGH PORTX.2 = High#define SD_CLK_LOW PORTX.3 = Low#define SD_CLK_HIGH PORTX.3 = High#define SD_DAT3_HIGH PORTX.0 = High// SD Card Input Read#define SD_TEST_CMD PINX.1#define SD_TEST_DAT PINX.2//------------------------------------------------------------------------- #define BYTE unsigned char#define UINT16 unsigned int#define UINT32 unsigned long//------------------------------------------------------------------------- void Ncr(void);void Ncc(void);BYTE response_R(BYTE);BYTE send_cmd(BYTE *);BYTE SD_read_lba(BYTE *,UINT32,UINT32);BYTE SD_card_init(void);//------------------------------------------------------------------------- BYTE read_status;BYTE response_buffer[20];BYTE RCA[2];BYTE cmd_buffer[5];const BYTE cmd0[5] = {0x40,0x00,0x00,0x00,0x00};const BYTE cmd55[5] = {0x77,0x00,0x00,0x00,0x00};const BYTE cmd2[5] = {0x42,0x00,0x00,0x00,0x00};const BYTE cmd3[5] = {0x43,0x00,0x00,0x00,0x00};const BYTE cmd7[5] = {0x47,0x00,0x00,0x00,0x00};const BYTE cmd9[5] = {0x49,0x00,0x00,0x00,0x00};const BYTE cmd16[5] = {0x50,0x00,0x00,0x02,0x00};const BYTE cmd17[5] = {0x51,0x00,0x00,0x00,0x00};const BYTE acmd6[5] = {0x46,0x00,0x00,0x00,0x02};const BYTE acmd41[5] = {0x69,0x0f,0xf0,0x00,0x00};const BYTE acmd51[5] = {0x73,0x00,0x00,0x00,0x00};//------------------------------------------------------------------------- void Ncr(void){SD_CMD_IN;SD_CLK_LOW;SD_CLK_HIGH;SD_CLK_LOW;SD_CLK_HIGH;}//------------------------------------------------------------------------- void Ncc(void){int i;for(i=0;i<8;i++){SD_CLK_LOW;SD_CLK_HIGH;}}//------------------------------------------------------------------------- BYTE SD_card_init(void){BYTE x,y;SD_CMD_OUT;SD_DAT_IN;SD_CLK_HIGH;SD_CMD_HIGH;SD_DAT_LOW;read_status=0;for(x=0;x<40;x++)Ncr();for(x=0;x<5;x++)cmd_buffer[x]=cmd0[x];y = send_cmd(cmd_buffer);do{for(x=0;x<40;x++);Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd55[x];y = send_cmd(cmd_buffer);Ncr();if(response_R(1)>1) //response too long or crc errorreturn 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=acmd41[x];y = send_cmd(cmd_buffer);Ncr();} while(response_R(3)==1);Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd2[x];y = send_cmd(cmd_buffer);Ncr();if(response_R(2)>1)return 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd3[x];y = send_cmd(cmd_buffer);Ncr();if(response_R(6)>1)return 1;RCA[0]=response_buffer[1];RCA[1]=response_buffer[2];Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd9[x];cmd_buffer[1] = RCA[0];cmd_buffer[2] = RCA[1];y = send_cmd(cmd_buffer);Ncr();if(response_R(2)>1)return 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd7[x];cmd_buffer[1] = RCA[0];cmd_buffer[2] = RCA[1];y = send_cmd(cmd_buffer);Ncr();if(response_R(1)>1)return 1;Ncc();for(x=0;x<5;x++)cmd_buffer[x]=cmd16[x];y = send_cmd(cmd_buffer);Ncr();if(response_R(1)>1)return 1;read_status =1; //sd card readyreturn 0;}//------------------------------------------------------------------------- BYTE SD_read_lba(BYTE *buff,UINT32 lba,UINT32 seccnt){BYTE c=0;UINT32 i,j;lba+=101;for(j=0;j<seccnt;j++){{Ncc();cmd_buffer[0] = cmd17[0];cmd_buffer[1] = (lba>>15)&0xff; cmd_buffer[2] = (lba>>7)&0xff; cmd_buffer[3] = (lba<<1)&0xff; cmd_buffer[4] = 0;lba++;send_cmd(cmd_buffer);Ncr();}while(1){SD_CLK_LOW;SD_CLK_HIGH;if(!(SD_TEST_DAT))break;}for(i=0;i<512;i++){BYTE k;for(k=0;k<8;k++){SD_CLK_LOW;SD_CLK_HIGH;c <<= 1;if(SD_TEST_DAT)c |= 0x01;}*buff=c;buff++;}for(i=0; i<16; i++){SD_CLK_LOW;SD_CLK_HIGH;}}read_status = 1; //SD data next inreturn 0;}//------------------------------------------------------------------------- BYTE response_R(BYTE s){BYTE a=0,b=0,c=0,r=0,crc=0;BYTE i,j=6,k;while(1){SD_CLK_LOW;SD_CLK_HIGH;if(!(SD_TEST_CMD))break;if(crc++ >100)return 2;}crc =0;if(s == 2)j = 17;for(k=0; k<j; k++){c = 0;if(k > 0) //for crc culcarb = response_buffer[k-1];for(i=0; i<8; i++){SD_CLK_LOW;if(a > 0)c <<= 1;elsei++;a++;SD_CLK_HIGH;if(SD_TEST_CMD)c |= 0x01;if(k > 0){crc <<= 1;if((crc ^ b) & 0x80)crc ^= 0x09;b <<= 1;crc &= 0x7f;}}if(s==3){if( k==1 &&(!(c&0x80)))r=1;}response_buffer[k] = c;}if(s==1 || s==6){if(c != ((crc<<1)+1))r=2;}return r;}//------------------------------------------------------------------------- BYTE send_cmd(BYTE *in){int i,j;BYTE b,crc=0;SD_CMD_OUT;for(i=0; i < 5; i++){b = in[i];for(j=0; j<8; j++){SD_CLK_LOW;if(b&0x80)SD_CMD_HIGH;elseSD_CMD_LOW;crc <<= 1;SD_CLK_HIGH;if((crc ^ b) & 0x80)crc ^= 0x09;b<<=1;}crc &= 0x7f;}crc =((crc<<1)|0x01);b = crc;for(j=0; j<8; j++){SD_CLK_LOW;if(crc&0x80)SD_CMD_HIGH;elseSD_CMD_LOW;SD_CLK_HIGH;crc<<=1;}return b;}//-------------------------------------------------------------------------#endif这些程序有些我也不明白,贴出来希望大家一起探讨交流,打破网站SD卡用SPI方式读写的垄断局面,哈哈sd模式下应该有4各data吧,怎么你的只用一个?SPI模式是1Bit的SD模式是1Bit或4BitSD卡确实也像USB一样分为全速(FULL-SPEED)卡和低速卡(LOW-SPEED)。