SD卡 SD 卡(Seecure Digital Memory Cardl)是一種基于 Flash 的新一代存儲(chǔ)器,具有體積小、容量大、數(shù)據(jù)傳輸快、移動(dòng)靈活、安全性能好等優(yōu)點(diǎn),是許多便攜式電子儀器理想的外部存儲(chǔ)介質(zhì)
圖片1.png (27.73 KB, 下載次數(shù): 71)
下載附件
2020-2-14 14:43 上傳
圖片2.png (77.04 KB, 下載次數(shù): 65)
下載附件
2020-2-14 14:43 上傳
SD 卡支持兩種總線方式:SD 方式與 SPI 方式。其中 SD 方式采用 6 線制,使用 CLK、 CMD、DAT0~DAT3 進(jìn)行數(shù)據(jù)通信。而 SPI 方式采用 4 線制,使用 CS、CLK、DataIn、DataOut 進(jìn)行數(shù)據(jù)通信。SD 方式時(shí)的數(shù)據(jù)傳輸速度與 SPI 方式要快,采用單片機(jī)對(duì) SD 卡進(jìn)行讀寫時(shí)一般都采用 SPI 模式。采用不同的初始化方式可以使 SD 卡工作于 SD 方式或 SPI 方式。
這里只對(duì)其 SPI 方式進(jìn)行介紹。 SPI 方式驅(qū)動(dòng) SD 卡的方法 SD 卡的 SPI 通信接口使其可以通過(guò) SPI 通道進(jìn)行數(shù)據(jù)讀寫。從應(yīng)用的角度來(lái)看,采用 SPI 接口的好處在于,很多單片機(jī)內(nèi)部自帶 SPI 控制器,不光給開發(fā)上帶來(lái)方便,同時(shí)也見降低了開發(fā)成本。然而,它也有不好的地方,如失去了 SD 卡的性能優(yōu)勢(shì),要解決這一問(wèn)題,就要用 SD 方式,因?yàn)樗峁└蟮目偩數(shù)據(jù)帶寬。SPI 接口的選用是在上電初始時(shí)向其寫入第一個(gè)命令時(shí)進(jìn)行的。以下介紹 SD 卡的驅(qū)動(dòng)方法,只實(shí)現(xiàn)簡(jiǎn)單的扇區(qū)讀寫。 為了使SD卡初始化進(jìn)入SPI模式,我們需要使用的命令有3個(gè)CMD0,CMD55,ACMD41(使用ACMD類的指令前應(yīng)先發(fā)CMD55,CMD55起到一個(gè)切換到ACMD類命令的作用)。
為什么在使用CMD0以后不使用CMD1?CMD1是MMC卡使用的指令。我們上電或者發(fā)送CMD0后,應(yīng)該首先發(fā)送CMD55+ACMD41確認(rèn)是否有回應(yīng),如果有回應(yīng)則為SD卡,如果等回應(yīng)超時(shí),則可能是MMC卡,再發(fā)CMD1確認(rèn)。 SD卡調(diào)試步驟: 1. 上電時(shí)要延時(shí)足夠長(zhǎng)的時(shí)間給SD卡一個(gè)準(zhǔn)備的過(guò)程,SD卡初始化第一步發(fā)送CMD命令之前,在片選有效的情況下首先要發(fā)送至少74個(gè)時(shí)鐘,否則可能會(huì)出現(xiàn)SD卡不能初始化的問(wèn)題。那么為什么要74個(gè)CLK呢?因?yàn)樵谏想姵跗,電壓的上升過(guò)程據(jù)SD卡組織的計(jì)算約合64個(gè)CLK周期才能到達(dá)SD卡的正常工作電壓他們管這個(gè)叫做Supply ramp up time,其后的10個(gè)CLK是為了與SD卡同步,之后開始CMD0的操作,嚴(yán)格按照此項(xiàng)操作,一定沒(méi)有問(wèn)題。 2. SD卡發(fā)送CMD0命令,返回狀態(tài)為0x01,則復(fù)位成功。 3. SD卡發(fā)送復(fù)位命令CMD0后,要發(fā)送版本查詢命令CMD8,返回狀態(tài)一般分為兩種,若返回0x01,表示此SD卡接收CMD8,也就是說(shuō)SD卡支持版本2;若返回0x05則表示SD卡支持版本1. 4. 理論上要求發(fā)送CMD58獲得SD卡電壓參數(shù),但實(shí)際上都實(shí)現(xiàn)知道SD卡的工作電壓是3.3v,所以可以省略這一步。 5. 發(fā)送CMD55命令,返回0x01,起到轉(zhuǎn)換的作用。 6. 再發(fā)送ACMD41,等待返回0x00,則表示完成初始化。這里要說(shuō)的是如果最后的回應(yīng)內(nèi)容還是0x01的話,可以循環(huán)發(fā)送CMD55+ACMD41,直到回應(yīng)的內(nèi)容0x00。 SD卡操作命令作步驟: 1.讀步驟: 發(fā)送CMD17(單塊)或CMD18(多塊)讀命令,返回0x00 接收數(shù)據(jù)開始令牌0xfe(或0xfc)+正式數(shù)據(jù)512B+CRC校驗(yàn)2B 2.寫步驟: 發(fā)送CMD24(單塊)或CMD25(多塊)寫命令,返回0x00. 發(fā)送數(shù)據(jù)開始令牌0xfe(或0xfc)+正式數(shù)據(jù)512B+CRC校驗(yàn)2B 3.擦除步驟: 發(fā)送CMD32,跟一個(gè)參數(shù)來(lái)指定首個(gè)要擦除的起始地址 發(fā)送CMD33,指定最后的地址 發(fā)送CMD38,擦除指定區(qū)間的內(nèi)容。
向SD卡寫入一個(gè)CMD或者ACMD指令的過(guò)程是這樣的:
1.首先使CS為低電平,SD卡使能;其次在SD卡的Din寫入指令;寫入指令后還要附加8個(gè)填充時(shí)鐘,是SD卡完成內(nèi)部操作;之后在SD卡的Dout上接受回應(yīng);回應(yīng)接受完畢使CS為低電平,再附加8個(gè)填充時(shí)鐘。
2.在SD卡的Din沒(méi)有數(shù)據(jù)寫入時(shí),應(yīng)使Din保持高電平。 一些常用的指令格式: CMD0:0x40,0x00,0x00,0x00,0x00,0x95 CMD8:0x48,0x00,0x00,0x01,0xaa,0x87 CMD55:0x77,0x00,0x00,0x00,0x00,0xff 0x77=0x40+0x37(55的16進(jìn)制表示) ACMD41:0x69,0x40,0x00,0x00,0x00,0xff CMD58:0x7a,0x00,0x00,0x00,0x00,0xff ACMD41屬于附加命令,發(fā)送起來(lái)要麻煩一些,必須提前通知SD卡下一條要發(fā)送的命令為ACMD,這個(gè)通知就是CMD55,它的4字節(jié)參數(shù)都為0即可 SD卡的命令格式: 每一個(gè)命令的長(zhǎng)度都是固定的6個(gè)字節(jié),前1個(gè)字節(jié)的值=命令號(hào)+0x40;中間4個(gè)字節(jié)為參數(shù),不同的命令參數(shù)格式都不相同,但參數(shù)最多為4個(gè)字節(jié);最后1個(gè)字節(jié)是CRC校驗(yàn)碼和1位固定結(jié)束位‘1’。這里需要說(shuō)明一下0x40的意思,任何命令都有一個(gè)固定的起始格式,即先0后1,這是固定的命令起始標(biāo)志,前兩個(gè)字節(jié)的二進(jìn)制碼就是:01xx xxxx SD 卡所有的命令都是由 48 個(gè)數(shù)據(jù)位組成的,其結(jié)構(gòu)如表 2 所示。
圖片3.png (177.83 KB, 下載次數(shù): 67)
下載附件
2020-2-14 14:43 上傳
圖片4.png (61.32 KB, 下載次數(shù): 63)
下載附件
2020-2-14 14:43 上傳
需要特殊說(shuō)明的是CRC的問(wèn)題,這是一種檢驗(yàn)錯(cuò)誤的方法,具體問(wèn)題度娘說(shuō)的還算明白,在SPI模式中,CRC校驗(yàn)?zāi)J(rèn)是關(guān)閉的,也就是說(shuō)這7位必須要發(fā),但是SD卡會(huì)在讀到CRC以后自動(dòng)忽略它,所以全部發(fā)1就可以。例外的是,CMD0,CMD8這兩個(gè)命令發(fā)送的時(shí)候SD卡還沒(méi)有進(jìn)入SPI模式,也就是說(shuō)CRC校驗(yàn)在這個(gè)時(shí)候還是啟用狀態(tài),因此這兩個(gè)命令的CRC效驗(yàn)碼必須要寫正確,SD卡才會(huì)執(zhí)行命令,否在在返回值R1中就會(huì)有相應(yīng)的錯(cuò)誤標(biāo)志位提示開發(fā)人員CRC校驗(yàn)碼錯(cuò)誤。
圖片5.png (15.45 KB, 下載次數(shù): 57)
下載附件
2020-2-14 14:43 上傳
圖片6.png (32.5 KB, 下載次數(shù): 57)
下載附件
2020-2-14 14:43 上傳
圖片7.png (66.4 KB, 下載次數(shù): 62)
下載附件
2020-2-14 14:43 上傳
圖片8.png (32.58 KB, 下載次數(shù): 62)
下載附件
2020-2-14 14:43 上傳
圖片9.png (9.58 KB, 下載次數(shù): 59)
下載附件
2020-2-14 14:43 上傳
SD卡的命令代碼: (1)復(fù)位
圖片10.png (56.03 KB, 下載次數(shù): 64)
下載附件
2020-2-14 14:43 上傳
單片機(jī)源程序如下:
- /*********************************
- * @函數(shù)名:SD_SPI_Rest
- * @描 述:SD卡復(fù)位
- * @參 數(shù):無(wú)
- * @返回值:成功 0 失敗 0x01
- *********************************/
- uchar SD_SPI_Rest()//SD卡復(fù)位,進(jìn)入SPI模式,使用CMD0(命令0)
- {
- uchar time,temp,i;
- uchar pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; //命令0的字節(jié)序列
- SPI_Speed_Slow=1; //將SPI_Speed_Slow置為1
- SD_CS=1; //關(guān)閉片選
- for(i=0;i<0x0f;i++) //復(fù)位時(shí),首先要發(fā)送最少74個(gè)時(shí)鐘信號(hào),這是必須的!。
- {
- SD_SPI_Write_Byte(0xff); //120個(gè)時(shí)鐘 0x0f=15*8=120個(gè)時(shí)鐘信號(hào)
- }
- SD_CS=0; //打開片選
- time=0;
- do
- {
- temp=SD_SPI_Write_CMD(pcmd);//連續(xù)寫入CMD0
- time++;
- if(time==TRY_TIME)
- {
- SD_CS=1; //關(guān)閉片選
- Send_String("初始化失敗"); //提示初始化失敗
- return(0x01);//CMD0寫入失敗
- }
- }while(temp!=0x01); //返回0x01是復(fù)位成功
- SD_CS=1; //關(guān)閉片選
- SD_SPI_Write_Byte(0xff); //按照SD卡的操作時(shí)序在這里補(bǔ)8個(gè)時(shí)鐘
- return 0;//返回0,說(shuō)明復(fù)位操作成功
- }
復(fù)制代碼(2)查版本號(hào) - /*********************************
- * @函數(shù)名:SD_SPI_Version
- * @描 述:讀SD卡版本號(hào)
- * @參 數(shù):無(wú)
- * @返回值:成功 0 失敗 0x01
- *********************************/
- uchar SD_SPI_Version()
- {
- uchar time,temp;
- uchar pcmd[] = {0x48,0x00,0x00,0x01,0xaa,0x87}; // //CMD8
- SD_CS=0; //打開片選
- time=0;
- do
- temp=SD_SPI_Write_CMD(pcmd);
- time++;
- if(time==TRY_TIME)
- {
- SD_CS=1; //關(guān)閉片選
- Send_String("獲取版本號(hào)失敗");//獲取版本號(hào)失敗
- return(0x01);
- }
- }while(temp!=0x01); //返回0x01是2.0版本
- SD_CS=1; //關(guān)閉片選
- SD_SPI_Write_Byte(0xff); //按照SD卡的操作時(shí)序在這里補(bǔ)8個(gè)時(shí)鐘
- return 0;//返回0,說(shuō)明復(fù)位操作成功
- }
復(fù)制代碼(3)初始化
圖片11.png (61.99 KB, 下載次數(shù): 72)
下載附件
2020-2-14 14:43 上傳
- /*********************************
- * @函數(shù)名:SD_SPI_Init
- * @描 述:SD卡初始化
- * @參 數(shù):無(wú)
- * @返回值:成功 0 失敗 0x01
- *********************************/
- uchar SD_SPI_Init() //初始化,使用ACMD41
- {
- uchar time,temp;
- uchar pcmd[] = {0x69,0x40,0x00,0x00,0x00,0xff}; //ACMD41的字節(jié)序列
- uchar pcmd1[]={0x77,0x00,0x00,0x00,0x00,0xff};//CMD55
- /*調(diào)用這兩個(gè)函數(shù)*/
- SD_SPI_Rest(); //復(fù)位SD卡
- SD_SPI_Version();//版本號(hào)
- SD_CS=0; //打開片選
- time=0;
- do
- {
- SD_SPI_Read_Byte(); //這4個(gè)讀函數(shù),必須有,沒(méi)有將不會(huì)初始化成功
- SD_SPI_Read_Byte();
- SD_SPI_Read_Byte();
- SD_SPI_Read_Byte();
- temp=SD_SPI_Write_CMD(pcmd1); // 發(fā)送CMD55
- if(temp!=0x01)//上一次的返回值,這次沒(méi)有返回值
- {
- Send_String("CMD55錯(cuò)誤");
- return 0xfb;
- }
- temp=SD_SPI_Write_CMD(pcmd);//發(fā)送ACMD41
- time++;
- if(time==TRY_TIME)
- {
- SD_CS=1; //關(guān)閉片選
- Send_String("初始化失敗");
- return(0x01);//ACMD41寫入失敗
- }
- }while(temp!=0x00); //當(dāng)返回?cái)?shù)據(jù)時(shí)0x00的時(shí)候,說(shuō)明初始化成功
- SPI_Speed_Slow=0; //初始化完畢,將SPI_Speed_Slow設(shè)置為0,為了提高以后的數(shù)據(jù)傳輸速度
- SD_CS=1; //關(guān)閉片選
- SD_SPI_Write_Byte(0xff); //按照SD卡的操作時(shí)序在這里補(bǔ)8個(gè)時(shí)鐘
- return(0); //返回0,說(shuō)明初始化操作成功
- }
復(fù)制代碼(4)寫一個(gè)扇區(qū)
圖片12.png (92.98 KB, 下載次數(shù): 74)
下載附件
2020-2-14 14:43 上傳
- /*********************************
- * @函數(shù)名:SD_SPI_Write_Sector
- * @描 述:寫一扇區(qū)的數(shù)據(jù)
- * @參 數(shù):addr:扇區(qū)地址 *buffer:指向數(shù)據(jù)緩沖區(qū)的指針
- * @返回值:成功 0x00 失敗 0x01
- *********************************/
- uchar SD_SPI_Write_Sector(uchar *buffer,ulong addr) //向SD卡中的指定地址的扇區(qū)寫入512個(gè)字節(jié),使用CMD24(命令24)
- {
- uchar temp,time;
- uint i;
- uchar pcmd[] = {0x58,0x00,0x00,0x00,0x00,0xff}; //向SD卡中單個(gè)塊(512字節(jié),一個(gè)扇區(qū))寫入數(shù)據(jù),用CMD24
- addr<<=9; //addr = addr * 512 將塊地址(扇區(qū)地址)轉(zhuǎn)為字節(jié)地址 [這里就限制了SD卡的最大容量為4G]
- pcmd[1]=((addr&0xff000000)>>24); //將字節(jié)地址寫入到CMD24字節(jié)序列中
- pcmd[2]=((addr&0x00ff0000)>>16);
- pcmd[3]=((addr&0x0000ff00)>>8);
- SD_CS=0;//打開SD卡片選
- time=0;
- do
- {
- temp=SD_SPI_Write_CMD(pcmd);//發(fā)送ACMD41
- time++;
- if(time==TRY_TIME)
- {
- SD_CS=1; //關(guān)閉片選
- return temp ; //命令寫入失敗
- }
- }while(temp!=0); //寫入地址,返回值是0x00正確
- for(i=0;i<100;i++) //這里要插入若干時(shí)鐘信號(hào)
- {
- SD_SPI_Write_Byte(0xff);
- }
- SD_SPI_Write_Byte(0xfe);//寫入開始字節(jié) 0xfe,后面就是要寫入的512個(gè)字節(jié)的數(shù)據(jù)
- for(i=0;i<512;i++) //將緩沖區(qū)中要寫入的512個(gè)字節(jié)寫入SD卡
- {
- SD_SPI_Write_Byte(buffer[i]); //寫入512個(gè)字節(jié)的數(shù)據(jù)
- }
- SD_SPI_Write_Byte(0xff);
- SD_SPI_Write_Byte(0xff); //兩個(gè)字節(jié)的CRC校驗(yàn)碼,不用關(guān)心
- temp=SD_SPI_Read_Byte(); //讀取返回值
- if((temp&0x1F)!=0x05) //如果返回值是 XXX00101說(shuō)明數(shù)據(jù)已經(jīng)被SD卡接受了
- {
- SD_CS=1;
- return(0x01); //寫塊數(shù)據(jù)失敗
- }
- while(SD_SPI_Read_Byte()!=0xff);//等到SD卡不忙(數(shù)據(jù)被接受以后,
- // SD卡要將這些數(shù)據(jù)寫入到自身的FLASH中,需要一個(gè)時(shí)間)
- //忙時(shí),讀回來(lái)的值為0x00,不忙時(shí),為0xff
- SD_CS=1; //關(guān)閉片選
- SD_SPI_Write_Byte(0xff);//按照SD卡的操作時(shí)序在這里補(bǔ)8個(gè)時(shí)鐘
- return(0); //返回0,說(shuō)明寫扇區(qū)操作成功
- }
復(fù)制代碼(5)讀一個(gè)扇區(qū)
圖片13.png (92.67 KB, 下載次數(shù): 66)
下載附件
2020-2-14 14:43 上傳
- /*********************************
- * @函數(shù)名:SD_SPI_Read_Sector
- * @描 述:讀一扇區(qū)的數(shù)據(jù)
- * @參 數(shù):addr:扇區(qū)地址 *buffer:指向數(shù)據(jù)緩沖區(qū)的指針
- * @返回值:成功 0x00 失敗 0x01
- *********************************/
- uchar SD_SPI_Read_Sector(uchar *buffer,ulong addr)//從SD卡的指定扇區(qū)中讀出512個(gè)字節(jié),使用CMD17(17號(hào)命令)
- {
- uint j;
- uchar time,temp;
- uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff}; //CMD17的字節(jié)序列
- addr<<=9; //addr=addr*512 將塊地址(扇區(qū)地址)轉(zhuǎn)為字節(jié)地址
- pcmd[1]=((addr&0xff000000)>>24);//將字節(jié)地址寫入到CMD17字節(jié)序列中
- pcmd[2]=((addr&0x00FF0000)>>16);
- pcmd[3]=((addr&0x0000FF00)>>8);
- SD_CS=0;//打開片選
- time=0;
- do
- {
- temp=SD_SPI_Write_CMD(pcmd); //寫入CMD17
- time++;
- if(time==TRY_TIME)
- {
復(fù)制代碼注意: 1.2GB以內(nèi)的SD卡(標(biāo)準(zhǔn)卡)和2GB以上的SD卡(大容量卡在地址訪問(wèn)形式上不一樣。 2.對(duì)某一塊要進(jìn)行寫操作時(shí)最好先執(zhí)行擦除命令,這樣寫入的速度就能大大的提高。 3.對(duì)標(biāo)準(zhǔn)卡進(jìn)行字節(jié)操作時(shí),起始和終止必須在一個(gè)物理扇區(qū)內(nèi)。不管是標(biāo)準(zhǔn)卡還是大容量卡一個(gè)讀寫讀寫命令只能對(duì)一個(gè)快進(jìn)行操作,不允許跨物理層地址操作。
全部資料51hei下載地址:
SD卡.zip
(1.86 MB, 下載次數(shù): 91)
2020-2-14 14:59 上傳
點(diǎn)擊文件名下載附件
SD卡資料和代碼 下載積分: 黑幣 -5
|