SD卡底层驱动 SPI模式

SD卡底层驱动 SPI模式(转载)二 作者 骑蜗牛找浪漫 日期 2011-5-6 11:14:00
硬件平台:stm32
编译环境:MDK401
驱动方式: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卡命令格式如下:
下载 (48.37 KB)
2010-11-8 19:45

解释:6个字节,第一个字节最高两个BIT为01,2-5BYTE为参数,还有一个字节的CRC校验

SD卡SPI模式硬件连接:(典型连接)
下载 (30.29 KB)2010-11-8 19:50
 

 

 

 


SD卡两种模式,引角使用情况注意:本帖所用SPI模式
下载 (78.52 KB)
2010-11-8 19:48

 
 
 

SPI时序如下:
下载 (57.03 KB)
2010-11-8 19:48
 
 

下载 (48.2 KB)
2010-11-8 19:48
 
 

SD卡时序如下:
下载 (76.34 KB)
2010-11-8 19:48

下载 (72.82 KB)
2010-11-8 19:48

下载 (19.86 KB)
2010-11-8 19:48

下载 (108.18 KB)
2010-11-8 19:48

下载 (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. }
复制代码

你可能感兴趣的:(未分类)