打印
[牛人杂谈]

SD卡操作

[复制链接]
956|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
SD 卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪**器的新一代**设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。SD 卡由日本松下、东芝及美国 SanDisk公司于 1999 年 8 月共同开发研制。大小犹如一张邮票的 SD **卡,重量只有 2 克,但却拥有高**容量、快速数据传输率、极大的移动灵活性以及很好的安全性。SD 卡 在 24mm×32mm×2.1mm 的 体 积 内 结 合 了 快 闪 记 忆 卡 控 制 器 与 MLC(Multilevel Cell)技术和 Toshiba(东芝)NAND 芯片技术,通过 9 针的接口界面与专门的驱动器相连接,不需要额外的电源来保持其上**的信息。而且它是一体化固体介质,没有任何移动部分,所以不用担心机械运动的损坏。

使用特权

评论回复
沙发
天灵灵地灵灵|  楼主 | 2019-10-21 21:26 | 只看该作者
内部单元
SD 卡上所有单元(如图 28.1.2)由内部时钟发生器提供时钟。接口驱动单元同步外部时钟的 DAT 和 CMD 信号到内部所用时钟。
卡有自己的电源开通检测单元,无需附加的主复位信号来在电源开启后安装卡。它防短路,在带电插入或移出卡时,无需外部编程电压,编程电压在卡内生成。
SD 卡接口控制包括:CMD,CLK,DAT0~DAT3 等引脚,SD 卡支持 SD 模式与 SPI 模式,不同模式下,各引脚不尽相同,如下表。在多张 SD 卡连接的设备中,为了标识单独的 SD 卡,其内部的卡标识寄存器(CID:Card Identification)和相应地址寄存器(RCA:Relative Card Address)预先准备好。 一个附加的寄存器包括不同类型操作参数,这个寄存器叫做 CSD(Card Specific Data),使用 SD 卡线访问存储器还是寄存器的通信由 SD 卡标准定义如下表


使用特权

评论回复
板凳
天灵灵地灵灵|  楼主 | 2019-10-21 21:26 | 只看该作者

使用特权

评论回复
地板
天灵灵地灵灵|  楼主 | 2019-10-21 21:26 | 只看该作者

使用特权

评论回复
5
天灵灵地灵灵|  楼主 | 2019-10-21 21:27 | 只看该作者
SD 卡的指令由 6 个字节组成,字节 1 的最高 2 位固定为 01,低 6 位命令号(比如 CMD16 为 10000 即 16 进制数的 0x10,完整的 CMD16,第一个字节为 01010000,即 0x10+0x40)。
字节 2~5 为命令参数,有些命令没有参数。
字节 6 的高七位为 CRC 值,最低位恒定为 1。
SD 卡的命令总共有 12 类,分为 Class0~Class11,本章,我们仅介绍几个重要的命令。

使用特权

评论回复
6
天灵灵地灵灵|  楼主 | 2019-10-21 21:27 | 只看该作者


上表中,大部分的命令是初始化的时候用到的,表中的 R1、R3、R7 等是 SD 卡的回应,SD 卡和单片机的通信采用发送应答机制。

使用特权

评论回复
7
天灵灵地灵灵|  楼主 | 2019-10-21 21:28 | 只看该作者

使用特权

评论回复
8
天灵灵地灵灵|  楼主 | 2019-10-21 21:28 | 只看该作者
每发送一个命令,SD 卡都会发出一个应答,以告知主机该命令的执行情况,或是主机需要获取的数据。SPI 模式下,SD 卡针对不同的命令,应答可以是 R1~R7,R1 的应答,各位描述如下表所示:

使用特权

评论回复
9
天灵灵地灵灵|  楼主 | 2019-10-21 21:28 | 只看该作者
R2~R7 的响应,我们就不介绍了,大家可以参考 SD 卡 2.0 的协议,接下来,我们看看 SD 卡初始化过程。因为我们使用的是 SPI 模式,所以先得让 SD 卡进入 SPI 模式。方法如下:在 SD 卡收到复位命令(CMD0)时,CS 为有效电平(低电平)则 SPI 模式被启用。不过在发送 CMD0 之前,要发送至少 74 个时钟信号,这是因为 SD 卡内部有个供电电压上升时间,大概为 64 个时钟,剩下的10 个时钟用于 SD 卡同步,之后才能开始 CMD0 的操作,在卡初始化的时候,CLK 时钟最大不能超过 400Khz!
接着我们看看 SD 卡的初始化,SD 卡的典型初始化过程如下:
1、初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置,IO 口配置);
2、上电延时(>74 个时钟);
3、复位卡(CMD0),进入 IDLE 状态,设置为 SPI 模式,无须 CRC 校验;
4、发送 CMD8,检查是否支持 2.0 协议;
5、根据不同协议检查 SD 卡(命令包括:CMD55、CMD41、CMD58 和 CMD1 等);
6、取消片选,发 8 个时钟,结束初始化
这样我们就完成了对 SD 卡的初始化,注意末尾发送的 8 个时钟是提供 SD 卡额外的时钟,完成某些操作。通过 SD 卡初始化,我们可以知道 SD 卡的类型(V1、V2、V2HC 或者 MMC),在完成了初始化之后,就可以开始读写数据了。

使用特权

评论回复
10
天灵灵地灵灵|  楼主 | 2019-10-21 21:29 | 只看该作者
SD 卡读取数据,通过 CMD17 来实现,具体过程如下:
1、发送 CMD17;
2、接收卡响应 R1;
3、接收数据起始令牌 0XFE;
4、接收数据;
5、接收 2 个字节的 CRC,如果不使用 CRC,这两个字节在读取后可以丢掉。
6、禁止片选之后,额外发 8 个时钟;

使用特权

评论回复
11
天灵灵地灵灵|  楼主 | 2019-10-21 21:29 | 只看该作者
SD 卡写入数据,通过 CMD24 来实现,具体过程如下:
1、发送 CMD24;
2、接收卡响应 R1;
3、发送写数据起始令牌 0XFE;
4、发送数据;
5、发送 2 字节的伪 CRC;
6、禁止片选之后,发多 8 个 CLK;

使用特权

评论回复
12
天灵灵地灵灵|  楼主 | 2019-10-21 21:29 | 只看该作者

使用特权

评论回复
13
天灵灵地灵灵|  楼主 | 2019-10-21 21:30 | 只看该作者
[1]SD 卡既支持 SDIO 接口,也支持 SPI 接口,M451 只支持 SPI 接口,因此,实验当中只能采用 SPI 接口,SPI 通信我们用回之前学习到的 SPI 接口就可以了。
[2]获取 CID(卡标识别寄存器)时,需要发送指令 10,那么发送命令必需遵循 SD 卡命令传输机制,且每次发送的是 48 位命令,数据格式如下:

使用特权

评论回复
14
天灵灵地灵灵|  楼主 | 2019-10-21 21:31 | 只看该作者
向 SD 卡发送命令时,起始位必须为’0’,第二位为’1’,紧接着就是命令的内容,最后发送的一个字节由 7 位的 CRC 和结束位’1’ 组成。有一点要注意的是,SD 上电后默认为 SD 模式,必须要使用带 CRC 校验的命令,CMD0 让其进入 SPI 模式,进入 SPI 模式之后就无需再用任何带 CRC 校验的命令了,好的,那么现在我们编写简单的发送 SD 卡命令函数,代码如下:
UINT8 SD_SendCmd(UINT8 cmd, UINT32 arg, UINT8 crc)
{
UINT8 r1;
UINT8 Retry=0;
/* 取消上次片选 */
SD_DisSelect();
if(SD_Select())
{
/* 片选失效 */
return 0XFF;
}
/* 分别写入命令 */
SD_SPI_ReadWriteByte(cmd | 0x40); //发送命令,位或 0x40 表示起始位为 0,紧接着发送 1
SD_SPI_ReadWriteByte(arg >> 24); //发送命令内容
SD_SPI_ReadWriteByte(arg >> 16);
SD_SPI_ReadWriteByte(arg >> 8);
SD_SPI_ReadWriteByte(arg);
SD_SPI_ReadWriteByte(crc); //发送 7 位 crc,结束位为 1
/* 等待响应,或超时退出 */
Retry=0X1F;
do
{
r1=SD_SPI_ReadWriteByte(0xFF);
}while((r1&0X80) && Retry--);
/* 返回状态值 */
return r1;
}

使用特权

评论回复
15
天灵灵地灵灵|  楼主 | 2019-10-21 21:42 | 只看该作者
[3]然后接着如何初始化 SD 卡,流程如下:
 初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置,IO 口配置);
 上电延时(>74 个 CLK);
 复位卡(CMD0),进入 IDLE 状态,设置为 SPI 模式,无须 CRC 校验;
 发送 CMD8,检查是否支持 2.0 协议;
 根据不同协议检查 SD 卡(命令包括:CMD55、CMD41、CMD58 和 CMD1 等);
 取消片选,额外发送 8 个 CLK,结束初始化
详细流程图如下:

使用特权

评论回复
16
天灵灵地灵灵|  楼主 | 2019-10-21 21:42 | 只看该作者

使用特权

评论回复
17
天灵灵地灵灵|  楼主 | 2019-10-21 21:43 | 只看该作者
/****************************************
*函数名称:SD_Initialize
*输 入:无
*输 出:0 -成功
其他 -失败
*功 能:SD 卡初始化
******************************************/
UINT8 SD_Initialize(VOID)
{
UINT8 r1; // 存放 SD 卡的返回值
UINT16 retry; // 用来进行超时计数
UINT8 buf[4];
UINT32 i;
/* 初始化 IO */
SD_SPI_Init();
/* 设置到低速模式 */
SD_SPI_SpeedLow();
for(i=0;i<10;i++)
{
/* 发送最少 74 个时钟 */
SD_SPI_ReadWriteByte(0XFF);
}
retry=20;
do
{
/* 进入 IDLE 状态 */
r1=SD_SendCmd(CMD0,0,0x95);
}while((r1!=0X01) && retry--);
/* 默认无卡 */
SD_Type=0;
if(r1==0X01)
{
if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
{
for(i=0;i<4;i++)
{
/* 等待应答 */
buf[i]=SD_SPI_ReadWriteByte(0XFF);
}
/* 卡是否支持 2.7~3.6V */
if(buf[2]==0X01&&buf[3]==0XAA)
{
retry=0XFFFE;
do
{
/* 发送 CMD55 */
SD_SendCmd(CMD55,0,0X01);
/* 发送 CMD41 */
r1=SD_SendCmd(CMD41,0x40000000,0X01);
}while(r1&&retry--);
/* 鉴别 SD2.0 卡版本开始 */
if(retry&&SD_SendCmd(CMD58,0,0X01)==0)
{
for(i=0;i<4;i++)
{
/* 得到 OCR 值 */
buf[i]=SD_SPI_ReadWriteByte(0XFF);
}
/* 检查 CCS */
if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;
else SD_Type=SD_TYPE_V2;
}
}
}
else//SD V1.x/ MMC V3
{
/* 发送 CMD55 */
SD_SendCmd(CMD55,0,0X01);
/* 发送 CMD41 */
r1=SD_SendCmd(CMD41,0,0X01);
if(r1<=1)
{
SD_Type=SD_TYPE_V1;
retry=0XFFFE;
do //等待退出 IDLE 模式
{
/* 发送 CMD55 */
SD_SendCmd(CMD55,0,0X01);
/* 发送 CMD41 */
r1=SD_SendCmd(CMD41,0,0X01);
}while(r1&&retry--);
}
else//MMC 卡不支持 CMD55+CMD41 识别
{
/* MMC V3 */
SD_Type=SD_TYPE_MMC;
retry=0XFFFE;
/* 等待退出 IDLE 模式 */
do
{
/* 发送 CMD1 */
r1=SD_SendCmd(CMD1,0,0X01);
}while(r1&&retry--);
}
if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)
{
/* 错误的卡 */
SD_Type=SD_TYPE_ERR;
}
}
}
/* 取消片选 */
SD_DisSelect();
/* 高速 */
SD_SPI_SpeedHigh();
if(SD_Type)return 0;
if(r1) return r1;
/* 其他错误 */
return 0xAA;
}

使用特权

评论回复
18
天灵灵地灵灵|  楼主 | 2019-10-21 21:44 | 只看该作者
[4]读取数据
发送命令后向 SD 卡获取数据,SD 卡会自动地向主机端发送令牌 0xFE,当主机验证为 0xFE 过后,同时传入 len 的参数比较固定,例如读取 CSD 寄存器时,len 为 16;若然对某一扇区进行读时,len 为 512,最后发送两个伪 CRC 值表示当前的数据结束,因此函数可以编写如下:
/****************************************
*函数名称:SD_RecvData
*输 入: buf 数据缓存区
len 要读取的数据长度
*输 出: 0 成功;
其他 失败;
*功 能:从 sd 卡读取一个数据包的内容
******************************************/
UINT8 SD_RecvData(UINT8*buf,UINT16 len)
{
/* 等待 SD 卡发回数据起始令牌 0xFE */
if(SD_GetResponse(0xFE))
{
return 1;
}
/* 开始接收数据 */
while(len--)
{
*buf=Spi0WriteRead(0xFF);
buf++;
}
/* 下面是 2 个伪 CRC(dummy CRC)*/
SD_SPI_ReadWriteByte(0xFF);
SD_SPI_ReadWriteByte(0xFF);
/* 读取成功 */
return 0;
}

使用特权

评论回复
19
天灵灵地灵灵|  楼主 | 2019-10-21 21:44 | 只看该作者
[5]当一切准备就绪后,就是研究如何获取 SD 卡的 CID 和 CSD 信息。CID 寄存器存储了 SD 卡的标识码。每一个卡都有唯一的标识码。CID 寄存器长度为 128 位。主要是获得厂商信息、产品版本等,它的寄存器结构如下:

使用特权

评论回复
20
天灵灵地灵灵|  楼主 | 2019-10-21 21:45 | 只看该作者
MID
8bit 的二进制数,表示卡的制造商。MID 号,由 SD-3C、LLC 组织来控制、定义、以及分配给 SD 卡制造商。这个程序是用来保证 CID 寄存器的唯一性。
OID
2 个字符的 ASCII 码,表明卡的 OEM 和/或者卡的内容(当用于分发媒体的时候)。OID 同样是由 SD-3C、LLC 组织来控制、定义和分配的。也是为了保证 CID 的唯一性注:SD-3C、LLC 授权给厂家来生产或者销售 SD 卡,包含但不限于 Flash 存储,ROM,OTP,RAM 和 SDIO 卡。
SD-3C 是由松下电子工业,SanDisk 公司和东芝公司成立的有限责任公司。
PNM
产品名称,5 个字符的 ASCII 码。
PRV
产品版本,由两个十进制数组成,每个数 4 个 bit,“n.m” ,n 表示大版本号,m 表示小版本号。比如,产品版本号是“6.2”,
那么 PRV =“0110 0010b”。
PSN
序列号,32 位二进制数。
MDT
制造日期由两个 16 进制数组成,一个是 8bit 的年(y),一个是 4bit 的月(m)。
m=bit[11:8],1= 1 月。
n=bit[19:12],0=2000
比如 2001 年 4 月,MDT=“0000 0001 0100”
CRC
7 位 CRC 校验码,CID 内容的校验码

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

167

主题

3341

帖子

13

粉丝