1 SD卡相关规范简介
SD联盟在2000年联合发布了SD卡规范1.O版本,包括3个部分:物理层规范,文件系统规范以及安全规范。SD卡规范V1.0采用FAT的文件系统,因此最大存储容量可以达到2 GB。2006年,SD卡规范V2.0发布。新规范根据容量定义了两种卡,即标准容量SD卡和大容量SD卡。前者和1.O版本保持兼容,后者由于采用了FAT32文件系统,存储容量突破了2 GB的限制。新规范定义的最大容量为32 GB。但是由于成本的原因,标准容量SD卡仍然是市场的主流产品。在以微控制器为核心的嵌入式系统中,主要使用SD卡的SPI。模式进行通信,这使得标准容量的SD卡更为合适。本设计适用于2GB以下任意容量的SD卡。
1.1 概 述
SD存储卡在2.7~3.6 V电压下正常工作,工作频率为0~25MHz。图1是普通SD卡的外形和引脚排列。在SPI模式时,第8和第9脚不使用。表1列出了各引脚在SPI模式时的定义和功能描述。
图中的WP是一个机械滑片,通过滑动到不同的位置来对SD卡进行写保护。
SD卡内部有6个和接口相关的寄存器:OCR、CID、CSD、RCA、DSR和SCR。它们只能通过各自对应的指令来访问。OCR、CID、CSD和SCR携带SD卡的规范信息,RCA和DSR作为配置寄存器装载了SD卡的配置参数。
1.2 SPI协议
系统上电之后,如果主机在将CS线声明为低电平的同时发送复位指令(CMDO),则SPI模式启用。SD卡在SPI模式下按字节进行通信,每一个指令和数据块都由数个字节组成并与CS信号对齐(也就是长度为8个时钟周期的整数倍)。
主机和SD卡之间是通过指令与响应来实现交互的。
图2给出了SPI模式下基本的指令与响应的时序。
图中一个方格代表一个字节,H为逻辑全“1”,L为逻辑全“O”,X代表未知,Z为高阻态。NCS、NEC和NCR都是包含N个8时钟周期,具体N的取值范围在SD卡规范中给出了详细的说明。
SD卡所有的指令,长度都是6字节。表2列出了指令格式。
在有效接收到主机发来的指令之后,SD卡将会把对应的响应数据段放在总线上,主机根据响应的内容判断SD卡的状态。所有的响应都是MSB优先传输。SD卡有4种类型的响应格式,分别为R1、R1b、R2、R3。
除了SEND_STATUS和READ_OCR指令外,其他指令的响应都是格式R1。格式R1的长度为1字节,并且最高位总是0。其余每位均是错误指示,在指令接收过程中发生了什么样的错误,对应的错误位就会是“1”。R1b和R1具有相同的格式,它将伴随一个附加的busy信号。busy信号的长度可以是任意个字节。全零表示卡处在“忙”的状态。格式R2的长度为2字节,它是指令SEND_STATUS的响应。它的高字节和R1相同,低字节同样作为状态指示。当接收到了READ_OCR指令时,SD卡将会产生格式R3的响应,该响应的长度为5字节。最高字节和R1相同,其余的4字节将包含SD卡的OCR寄存器信息。
在SD卡规范中详细描述了每条指令的格式内容及作用,并给出了各条指令所对应的响应。对于每种响应的信息也有详细的说明,具体信息参阅参考文献。
2 SD卡接口电路设计
16位的dsPIC33F系列DSC具有高达40 MIPS的指令周期,继承了Microchip公司之前8位和16位MCU产品的优点,并保持着对以往低成本开发系统的兼容性。dsPIC33FJ64GP706是其中一款64引脚的通用产品,拥有高达64 KB的Flash程序存储器和16 KB的数据存储器。该芯片集成了2个通用SPI接口,本设计使用SPI2模块来建立和SD存储卡的通信。
图3所示为dsPIC33FJ64GP706与SD卡座的接口电路。为了防止在无卡接入或卡驱动器呈高阻态时总线悬空,在每根信号线上要接一个上拉电阻,根据SD卡规范(见参考文献,第6章),电阻的阻值可以取10~90kΩ。卡座的CD引脚是SD卡检测信号引脚,当有卡插入时,该引脚对地短路。WP是写保护信号引脚,在卡插入且没有写保护时,该引脚对地短路;如果SD卡写保护或没有卡插入,该引脚通过上拉电阻接到电源正极。
3 SD卡接口的实现
3.1 选择SD卡的SPI模式并初始化SD卡
在上电之后,主机开始发送时钟信号,此时的时钟频率不能超过400 kHz。主机要连续发送至少74个时钟周期的“1”才能使SD卡准备好通信,然后选择SPI模式。SD卡进入SPI模式之后,就可以接收来自主机的操作指令了。这时候主机发送SEND_OP_COND指令,激活卡的初始化过程。在得到正确的响应之后,主机再发送SEND_CSD指令读取CSD寄存器的内容。正确响应之后,将SPI总线时钟频率提高到10 MHz,初始化过程结束。
3.2 指令和响应交互过程的软件实现
typSD_CMD是自定义的结构类型,包含指令索引、CRC和响应格式。最后一个字节数据用来说明该指令有无后续数据块,例如READ_SINGLE_BLOCK(单数据块读指令),它需要SD卡发送一个数据块的数据,因此其后的数据为“1”。对于指令索引,是把开始位和传输位与6位索引值包含在一起的数据。例如G0_IDLE_STATE的索引值是二进制“000000”,加上开始位“O”和传输位“1”,成为“01000000”,即“Ox40”,READ_SINGLE_BLOCK的索引值是“010001”,加上开始位和传输位,成为“01010001”即"0x51”。
定义发送指令函数为SendSDCmd(),返回值为从总线上读取的响应数据。(具体函数略——编者注)函数的第一个参数是指令列表数组中相应指令元素的序号,函数会根据它的值在指令表中查到对应的信息,第二个参数是指令的附加内容。函数中CMD_PACKET是按指令格式(见表2)定义的联合类型,程序通过查表的方式将指令的内容装载到该类型定义的变量中,并通过函数Write_sd()发送出去。write_sd()的作用是把一个字节的数据放到SPI2模块的burfer里,完成一个字节的发送。函数ReadSd()用来读取SPI2接收的一个字节数据。如果接收的数据是0xff,则不是响应数据;如果接收到的响应不为全零,则说明有错误发生。
以上程序按照图2所示时序执行,来实现一次指令和响应数据的交互。当某条指令有后续数据时,按照规范中的时序发送或者读取数据。
3.3 读写操作的实现
READ_SINGLE_BLOCK是单数据块读指令,在接收到有效的读指令后SD卡将会送出一个响应。紧接着是一个带16位CRC校验后缀的数据块,数据块的长度要在之前由SET_BLOCKEN(CMDl6)指令定义,一般为512字节,正好一个扇区的大小。数据块的开始是1字节的开始令牌,值为“0xFE”,结束是2字节的CRC。该操作的通信过程如图4所示。
WRITE_SINGLE_BLOCK是单数据写操作指令,在接收到主机传来的数据后,SD卡会发送一个值为0x5的数据响应,之后进入busy状态。该操作的通信过程如图5所示。
按照以上通信过程编写程序,单数据块读和写的程序流程如图6所示。
4 结果验证
将容量为1 GB的SD卡插入SD读卡器,再将读卡器插入PC机的USB接口中,此时系统出现“可移动磁盘(H:)”根目录。打开winhex软件,点击“工具”下拉菜单中的“打开磁盘”,选择“物理磁盘”中的“RMl:Ceneric STORAGE DEVICE(O.9G,USB)”,单击“确定”按钮,得到该SD卡第一个物理扇区的数据。该SD卡在偏移量从446开始的16个字节有数据“00 03 3D 00 06 OD ED DB F9 00 00 OO 07 5F 1E 00”,该扇区结束的两个字节为“55AA”,其余部分数据均为“00”。
将SD卡取出,插入本设计电路的SD卡座中,用示波器连接D0、CLK和DI线,接通电源,测量SPI总线上的波形。
本设计利用dsPIC33FJ64GP706的SPI接口实现了对SD存储卡的操作,可以把SD卡和dsPIC33F系列DSC两方面的优点集中到一个嵌入式系统中,有较高的利用价值。