天天看點

SD卡底層驅動 SPI模式

SD卡底層驅動 SPI模式(轉載)二 作者 騎蝸牛找浪漫 日期 2011-5-6 11:14:00 硬體平台:stm32

編譯環境:MDK401

驅動方式:SPI總線

SD卡底層驅動 SPI模式

下載下傳 (12.88 KB)

2010-11-8 19:50

編寫的函數如下:

1、 u8 SD_Init()                                                         SD卡初始化(複位和激活)

2、 u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc)      向SD卡發送一個指令

3、 u32 SD_GetCapacity(void)                                     擷取SD卡的容量

4、 u8 SD_GetCID(u8 *cid_data)                                 擷取SD卡的CID資訊,包括制造商資訊

5、 u8 SD_GetCSD(u8 *csd_data)                               擷取SD卡的CSD資訊,包括容量和速度資訊

6、 u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count)   讀SD卡的多個block

7、 u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)       讀SD卡的一個block

8、 u8 SD_ReceiveData(u8 *data, u16 len, u8 release)    從SD卡中讀回指定長度的資料,放置在給定位置

9、 u8 SD_WaitReady(void)                                          等待SD卡Ready

10、 u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count)  寫入SD卡的N個block

11、 u8 SD_WriteSingleBlock(u32 sector, const u8 *data)  寫入SD卡的一個block

SD卡指令   推薦SD卡指令共分為12類,分别為class0到class11,不同的SDd卡,主要根據其功能,支援不同的指令集 如下:

Class0 (卡的識别、初始化等基本指令集)

CMD0:複位SD 卡.

CMD1:讀OCR寄存器.

CMD9:讀CSD寄存器.

CMD10:讀CID寄存器.

CMD12:停止讀多塊時的資料傳輸

CMD13:讀 Card_Status 寄存器

Class2 (讀卡指令集):

CMD16:設定塊的長度

CMD17:讀單塊.

CMD18:讀多塊,直至主機發送CMD12為止 .

Class4(寫卡指令集) :

CMD24:寫單塊.

CMD25:寫多塊.

CMD27:寫CSD寄存器 .

Class5 (擦除卡指令集):

CMD32:設定擦除塊的起始位址.

CMD33:設定擦除塊的終止位址.

CMD38: 擦除所選擇的塊.

Class6(寫保護指令集):

CMD28:設定寫保護塊的位址.

CMD29:擦除寫保護塊的位址.

CMD30: Ask the card for the status of the write protection bits

class7:卡的鎖定,解鎖功能指令集  

class8:申請特定指令集 。

class10 -11 :保留

其中 class1,    class3,class9:SPI模式不支援

SD卡指令格式如下:

SD卡底層驅動 SPI模式

下載下傳 (48.37 KB)

2010-11-8 19:45

解釋:6個位元組,第一個位元組最高兩個BIT為01,2-5BYTE為參數,還有一個位元組的CRC校驗

SD卡SPI模式硬體連接配接:(典型連接配接)

SD卡底層驅動 SPI模式

下載下傳 (30.29 KB)2010-11-8 19:50  

SD卡兩種模式,引角使用情況( 注意:本帖所用SPI模式)

SD卡底層驅動 SPI模式

下載下傳 (78.52 KB)

2010-11-8 19:48

SPI時序如下:

SD卡底層驅動 SPI模式

下載下傳 (57.03 KB)

2010-11-8 19:48    

SD卡底層驅動 SPI模式

下載下傳 (48.2 KB)

2010-11-8 19:48    

SD卡時序如下:

SD卡底層驅動 SPI模式

下載下傳 (76.34 KB)

2010-11-8 19:48

SD卡底層驅動 SPI模式

下載下傳 (72.82 KB)

2010-11-8 19:48

SD卡底層驅動 SPI模式

下載下傳 (19.86 KB)

2010-11-8 19:48

SD卡底層驅動 SPI模式

下載下傳 (108.18 KB)

2010-11-8 19:48

SD卡底層驅動 SPI模式

下載下傳 (104.43 KB)

2010-11-8 19:48

時序分析(這裡我舉一個例子)

SD卡讀扇區時序

1、拉低CS,選中SD卡

2、發送指令17(從本帖的上面查)

3、指令發送完畢後不斷的讀取輸出線,讀到0xFE,表示指令成功

4、準備接收資料,0xFE是資料的開始,此後就可以接收512個位元組了   (當然在初始化的時候有用指令16設定塊的大小為512)

5、資料接收完畢,拉高CS線

6、 最後等8個時鐘,你可以随便發一個BYTE就可以了(嚴格按照時序,大家别偷懶哦)

SD卡讀扇區時序

  1. u8 SD_ReceiveData(u8 *data, u16 len, u8 release)
  2. {
  3. u16 retry;
  4. u8 r1;
  5. SD_CS_Reset();  // 啟動一次傳輸
  6. //等待SD卡發回資料起始令牌0xFE
  7. retry = 0;
  8. do
  9. {
  10. r1 = SPI_ReadWriteByte(0xFF);
  11. retry++;
  12. if(retry>200) //200次等待後沒有應答,退出報錯
  13. {
  14. SD_CS_Set();
  15. return 1;
  16. }
  17. }while(r1 != 0xFE);
  18. //開始接收資料
  19. while(len--)
  20. {
  21. *data = SPI_ReadWriteByte(0xFF);
  22. data++;
  23. }
  24. //下面是2個僞CRC(dummy CRC)
  25. SPI_ReadWriteByte(0xFF);
  26. SPI_ReadWriteByte(0xFF);
  27. //按需釋放總線,将CS置高
  28. if(release == RELEASE)
  29. {
  30. //傳輸結束
  31. SD_CS_Set();
  32. SPI_ReadWriteByte(0xFF);
  33. }
  34. return 0;
  35. }

複制代碼

SD_SendCommand

  1. u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc)
  2. {
  3. unsigned char r1;
  4. unsigned char Retry = 0;
  5. // SPI_ReadWriteByte(0xff);
  6. //片選端置低,選中SD卡
  7. SD_CS_Reset();
  8. //發送
  9. SPI_ReadWriteByte(cmd | 0x40); //分别寫入指令
  10. SPI_ReadWriteByte(arg >> 24);
  11. SPI_ReadWriteByte(arg >> 16);
  12. SPI_ReadWriteByte(arg >> 8);
  13. SPI_ReadWriteByte(arg);
  14. SPI_ReadWriteByte(crc);
  15. //等待響應,或逾時退出
  16. while((r1 = SPI_ReadWriteByte(0xFF))==0xFF)
  17. {
  18. Retry++;
  19. if(Retry > 200)
  20. {
  21. break;
  22. }
  23. }
  24. //關閉片選
  25. //在總線上額外增加8個時鐘,讓SD卡完成剩下的工作
  26. SPI_ReadWriteByte(0xFF);
  27. SD_CS_Set();
  28. //傳回狀态值
  29. return r1;
  30. }

複制代碼

SD卡初始化代碼:

這裡我不敢保證大家的卡都能初始化成功,我自己的是可以,我發送CMD0和CMD1就可以初始化啦

網上有更相容的初始化代碼,大家可以看看哦!

調試的時候大家看傳回值就可以了,哪裡沒成功就修改哪裡哦!

  1. u8 SD_Init()
  2. {
  3. unsigned char time,temp,i;
  4. SD_CS_Set(); //關閉片選
  5. for(i=0;i<0x0A;i++) //初始時,首先要發送最少74個時鐘信号,這是必須的!!!
  6. {
  7. SPI_ReadWriteByte(0xff); //120個時鐘
  8. }
  9. SD_CS_Reset(); //打開片選
  10. time=0;
  11. do
  12. {
  13. temp=SD_SendCommand(CMD0, 0 ,0x95);//寫入CMD0  複位SD卡
  14. time++;
  15. if(time==200)
  16. {
  17. SD_CS_Set(); //關閉片選
  18. }
  19. }while(temp!=0x01);
  20. time=0;
  21. do
  22. {
  23. temp=SD_SendCommand(CMD1, 0 , 0xff); //寫入CMD1 激活SD卡
  24. time++;
  25. if(time==200)
  26. {
  27. SD_CS_Set(); //關閉片選
  28. }
  29. }while(temp!=0);
  30. SPI_SetSpeed(1);
  31. temp = SD_SendCommand(CMD59, 0, 0x01);
  32. if(temp != 0x00)
  33. {
  34. return temp; //指令錯誤,傳回r1
  35. }
  36. temp=SD_SendCommand(CMD16,512,0xff);
  37. if(temp!=0x00)
  38. {
  39. return temp ;
  40. //指令錯誤,傳回r1
  41. }
  42. SD_CS_Set(); //關閉片選
  43. SPI_ReadWriteByte(0xff); //按照SD卡的操作時序在這裡補8個時鐘
  44. return 0;
  45. }

複制代碼

寫入SD卡的N個block

  1. u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count)
  2. {
  3. u8 r1;
  4. u16 i;
  5. //設定為高速模式
  6. SPI_SetSpeed(SPI_SPEED_HIGH);
  7. //如果不是SDHC,給定的是sector位址,将其轉換成byte位址
  8. if(SD_Type != SD_TYPE_V2HC)
  9. {
  10. sector = sector<<9;
  11. }
  12. //如果目标卡不是MMC卡,啟用ACMD23指令使能預擦除
  13. if(SD_Type != SD_TYPE_MMC)
  14. {
  15. r1 = SD_SendCommand(ACMD23, count, 0x00);
  16. }
  17. //發多塊寫入指令
  18. r1 = SD_SendCommand(CMD25, sector, 0x00);
  19. if(r1 != 0x00)
  20. {
  21. return r1; //應答不正确,直接傳回
  22. }
  23. //開始準備資料傳輸
  24. SD_CS_Reset();
  25. //先放3個空資料,等待SD卡準備好
  26. SPI_ReadWriteByte(0xff);
  27. SPI_ReadWriteByte(0xff);
  28. //--------下面是N個sector寫入的循環部分
  29. do
  30. {
  31. //放起始令牌0xFC 表明是多塊寫入
  32. SPI_ReadWriteByte(0xFC);
  33. //放一個sector的資料
  34. for(i=0;i<512;i++)
  35. {
  36. SPI_ReadWriteByte(*data++);
  37. }
  38. //發2個Byte的dummy CRC
  39. SPI_ReadWriteByte(0xff);
  40. SPI_ReadWriteByte(0xff);
  41. //等待SD卡應答
  42. r1 = SPI_ReadWriteByte(0xff);
  43. if((r1&0x1F)!=0x05)
  44. {
  45. SD_CS_Set(); //如果應答為報錯,則帶錯誤代碼直接退出
  46. return r1;
  47. }
  48. //等待SD卡寫入完成
  49. if(SD_WaitReady()==1)
  50. {
  51. SD_CS_Set(); //等待SD卡寫入完成逾時,直接退出報錯
  52. return 1;
  53. }
  54. //本sector資料傳輸完成
  55. }while(--count);
  56. //發結束傳輸令牌0xFD
  57. r1 = SPI_ReadWriteByte(0xFD);
  58. if(r1==0x00)
  59. {
  60. count = 0xfe;
  61. }
  62. if(SD_WaitReady())
  63. {
  64. while(1)
  65. {
  66. }
  67. }
  68. //寫入完成,片選置1
  69. SD_CS_Set();
  70. SPI_ReadWriteByte(0xff);
  71. return count; //傳回count值,如果寫完則count=0,否則count=1
  72. }

複制代碼