SD底层驱动c代码.docx
《SD底层驱动c代码.docx》由会员分享,可在线阅读,更多相关《SD底层驱动c代码.docx(14页珍藏版)》请在冰豆网上搜索。
SD底层驱动c代码
SD卡底层驱动程序,c代码
硬件平台:
stm32
编译环境:
MDK401
驱动方式:
SPI总线
下载(12.88KB)
2010-11-819:
50
编写的函数如下:
1、u8SD_Init() SD卡初始化(复位和激活)
2、u8SD_SendCommand(u8cmd,u32arg,u8crc) 向SD卡发送一个命令
3、u32SD_GetCapacity(void) 获取SD卡的容量
4、u8SD_GetCID(u8*cid_data) 获取SD卡的CID信息,包括制造商信息
5、u8SD_GetCSD(u8*csd_data) 获取SD卡的CSD信息,包括容量和速度信息
6、u8SD_ReadMultiBlock(u32sector,u8*buffer,u8count) 读SD卡的多个block
7、u8SD_ReadSingleBlock(u32sector,u8*buffer) 读SD卡的一个block
8、u8SD_ReceiveData(u8*data,u16len,u8release) 从SD卡中读回指定长度的数据,放置在给定位置
9、u8SD_WaitReady(void) 等待SD卡Ready
10、u8SD_WriteMultiBlock(u32sector,constu8*data,u8count) 写入SD卡的N个block
11、u8SD_WriteSingleBlock(u32sector,constu8*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:
Askthecardforthestatusofthewriteprotectionbits
class7:
卡的锁定,解锁功能命令集
class8:
申请特定命令集。
class10-11:
保留
其中 class1, class3,class9:
SPI模式不支持
SD卡命令格式如下:
下载(48.37KB)
2010-11-819:
45
解释:
6个字节,第一个字节最高两个BIT为01,2-5BYTE为参数,还有一个字节的CRC校验
SD卡SPI模式硬件连接:
(典型连接)
下载(30.29KB)
2010-11-819:
50
SD卡两种模式,引角使用情况(注意:
本帖所用SPI模式)
下载(78.52KB)
2010-11-819:
48
SPI时序如下:
下载(57.03KB)
2010-11-819:
48
下载(48.2KB)
2010-11-819:
48
SD卡时序如下:
下载(76.34KB)
2010-11-819:
48
下载(72.82KB)
2010-11-819:
48
下载(19.86KB)
2010-11-819:
48
下载(108.18KB)
2010-11-819:
48
下载(104.43KB)
2010-11-819:
48
时序分析(这里我举一个例子)
SD卡读扇区时序
1、拉低CS,选中SD卡
2、发送命令17(从本帖的上面查)
3、命令发送完毕后不断的读取输出线,读到0xFE,表示命令成功
4、准备接收数据,0xFE是数据的开始,此后就可以接收512个字节了 (当然在初始化的时候有用命令16设置块的大小为512)
5、数据接收完毕,拉高CS线
6、最后等8个时钟,你可以随便发一个BYTE就可以了(严格按照时序,大家别偷懒哦)
SD卡读扇区时序
1.u8SD_ReceiveData(u8*data,u16len,u8release)
2.{
3.u16retry;
4.u8r1;
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.return1;
16.}
17.}while(r1!
=0xFE);
18.//开始接收数据
19.while(len--)
20.{
21.*data=SPI_ReadWriteByte(0xFF);
22.data++;
23.}
24.//下面是2个伪CRC(dummyCRC)
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.return0;
35.}
复制代码
SD_SendCommand
1.u8SD_SendCommand(u8cmd,u32arg,u8crc)
2.{
3.unsignedcharr1;
4.unsignedcharRetry=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.returnr1;
30.}
复制代码
SD卡初始化代码:
这里我不敢保证大家的卡都能初始化成功,我自己的是可以,我发送CMD0和CMD1就可以初始化啦
网上有更兼容的初始化代码,大家可以看看哦!
调试的时候大家看返回值就可以了,哪里没成功就修改哪里哦!
1.u8SD_Init()
2.{
3.unsignedchartime,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.
21.time=0;
22.do
23.{
24.temp=SD_SendCommand(CMD1,0,0xff);//写入CMD1激活SD卡
25.time++;
26.if(time==200)
27.{
28.SD_CS_Set();//关闭片选
29.}
30.}while(temp!
=0);
31.
32.SPI_SetSpeed
(1);
33.temp=SD_SendCommand(CMD59,0,0x01);
34.if(temp!
=0x00)
35.{
36.returntemp;//命令错误,返回r1
37.}
38.temp=SD_SendCommand(CMD16,512,0xff);
39.if(temp!
=0x00)
40.{
41.returntemp;
42.//命令错误,返回r1
43.}
44.SD_CS_Set();//关闭片选
45.SPI_ReadWriteByte(0xff);//按照SD卡的操作时序在这里补8个时钟
46.return0;
47.}
复制代码
写入SD卡的N个block
1.u8SD_WriteMultiBlock(u32sector,constu8*data,u8count)
2.{
3.u8r1;
4.u16i;
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.returnr1;//应答不正确,直接返回
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的dummyCRC
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.returnr1;
47.}
48.//等待SD卡写入完成
49.if(SD_WaitReady()==1)
50.{
51.SD_CS_Set();//等待SD卡写入完成超时,直接退出报错
52.return1;
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.returncount;//返回count值,如果写完则count=0,否则count=1
72.}
复制代码
后记:
关于SPI读写,我就不发了,大家自己写就是了,当然读扇区,写扇区都是差不多的,只是命令不同,所以我只列举了其中一个,大家把函数都写好。
IO设置好,初始化成功后,就可以读一个扇区了,大家取出来,可以用WINHEX对比一下数据是否一致,一般命令成功后就没有什么大问题的。