How to Use MMC/SDC

How to Use MMC/SDC
数字安全记忆卡(Secure Digital Memory Card)
(以下简称 SDC)实际上是用于移动设
备的标准记忆卡。SDC 向下兼容多媒体卡(Multi Media Card)
(以下简称 MMC)
,因此,
使用 SDC 的设备只需要经很小的改动便可使用 MMC。而今又出现了外形尺寸更小的版本,
例如 RS-MMC,mini SD 以及 Micro SD,功能都是一样的。MMC/SDC 内置微控制器,闪存
控制操作(擦除、读、写以及错误控制)都是在记忆卡内完成的。数据以 512 字节大小的数
据块的形式在存储卡和主控制器之间传输,所以,从上层来看,存储卡可以被看成是一个普
通的硬盘。一般情况下,记忆卡使用的文件系统是带有 FDISK 分区规则的 FAT12/FAT16 文
件系统(FDISK 的解释见附注)
。对于大容量存储卡(≥ 4GB)
,通常使用 FAT32 文件系统。
本文讲述了笔者在嵌入式系统中使用 MMC/SDC 时所用到的基础知识以及各方面的细节
问题。笔者相信,对于那些想要使用 MMC/SDC 的同志们来说,本文必是有用的入门笔记。
(原文件名:MMC 和 SD.jpg)
接口(Contact Interface)
下面的图片说明了 MMC/SDC 的接口。MMC 拥有 7 个触片,SDC 有 9 个触片(比 MMC
多出两个附加的触片)
。这些触片中有三个触片是为了存储卡的供电而设计的,所以,能用
于传递有效信号的触片就剩下 4 个(MMC)或是 6 个(SDC)
。故而,在主机和存储卡之间
的数据传输是通过一个同步串行接口(Synchronous Serial Interface)进行的。
(原文件名:SD 和 MMC 的接口.jpg)
SDC 的工作电压范围可以从其内部的一个特殊寄存器中读出,并以此来确定之。然而,
由于 MMC/SDC 的正常工作电压范围为 2.7V~3.6V,所以,实际供电电压可以定为这个范围
中的任意一个值。因 MMC/SDC 的工作电流可以达到十几毫安,故主机系统必须能提供至
少 100 mA 的电流。
SPI(Serial Peripheral Interface 串行外设接口)模式
SPI 模式是另一种操作模式,是为了能在没有 MMC/SDC 默认主机接口(SDIO 接口)
的情况下使用存储卡而定义的。与 MMC/SDC 的默认接口通信协议相比,SPI 协议要简单得
多。MMC/SDC 可以通过普通 SPI 接口或是 GPIO 口与大部分微控制器相连。因此,对于低
成本的嵌入式应用来说,SPI 模式操作 MMC/SDC 是绝佳选择。而且,价格低廉的微控制器
并没有 MMC/SDC 的默认主机接口(SDIO 接口)
。对于 SDC 来说,“SPI Mode 0”即为其 SPI
模式;而对于 MMC 来说,它使用的不是 SPI 时序,在 SCLK 的上升沿,数据的移出和锁存
操作同时被执行,但在 SPI 模式中的 SPI Mode 0 下,MMC 也能正常工作。因此,对于
MMC/SDC 接口来说,使用 SPI Mode 0(CPHA = 0,CPOL = 0)再合适不过了,但若使用
SPI Mode 3,MMC/SDC 在大部分情况下也能正常工作。
SPI Mode(SPI 模式) Timing Diagram(时序图)
模式 0:上升沿
数据先锁存,后移出
模式 1:上升沿
数据先移出,后锁存
模式 2:下降沿
数据先锁存,后移出
模式 3:下降沿
数据先移出,后锁存
(原文件名:SPI Mode 0.png)
(原文件名:SPI Mode 1.png)
(原文件名:SPI Mode 2.png)
(原文件名:SPI Mode 3.png)
指令和响应
在 SPI 模式下,信号线上的数据传输方向是固定的——面向字节的串行通信传输。从主
机到存储卡的命令帧是一个固定长度的数据包(6 个字节)
,见下图。当存储卡接受到命令
帧时,对于命令帧的响应(R1,R2,R3)便可从存储卡中读出。数据的传输是由主机产生
的串行时钟驱动的,主机必须不间断地读取字节——发送一个 0xFF,然后接收响应数据,
直到收到存储卡的有效响应。对于 SDC 来说,命令响应时间(Ncr)是 0-8 个时钟个数(单
位为 8 个时钟周期)
,对于 MMC 来说,则是 1-8 个时钟个数。片选信号(CS)在对存储卡
的一个执行过程(命令,响应以及可能存在的数据传输)中必须保持为低电平。在 SPI 模式
中,CRC(循环冗余校验)是可选的,但是仍然需要一个位域以组成完整的命令帧。在读操
作进行过程中,DI 信号必须保持为高电平。
(原文件名:命令响应时序.png)
SPI 指令集
每条指令都以简略形式表达,例如 GO_IDLE_STATE 或者 CMDD<n>,<n>是指令索引
号,可以是 0~63 中的任意值。下面的表格仅给出了通常的读/写操作以及存储卡初始化时所
使用的指令。对于所有指令的详细阐述,请参考 MMCA 和 SDCA 的规格说明书。
(原文件名:SPI 指令集.jpg)
*1:ACMD<n> 表示 CMD55-CMD<n>中的一个指令队列;
*2: Rsv(0)[31], HCS[30], Rsv(0)[29:0]
*3: Rsv(0)[31:12], Supply Voltage(1)[11:8], Check Pattern(0xAA)[7:0]
SPI 响应
对于不同的指令索引,一共有三种响应格式:R1,R2 和 R3,对于大多数指令来说,存
储卡经常返回一个字节长度的 R1 响应,下图给出了 R1 响应中的位定义,值 0x00 表示命令
执行成功,如果出现错误,R1 响应中对应的状态位将会被置位。只有执行 CMD58 时,才
会有 R3 响应(由 R1 及后面的 32 位的 OCR 组成)
。
有一些指令的执行时间比指令反应时间还要长,这些指令返回响应 R1b。响应 R1b 是由
R1 响应和“忙标志”组成的(在内部进程执行过程中,引脚 DO 的电平必须始终保持为低电
平)
。主机需要等待这个过程结束——直到收到 0xFF。
(原文件名:R1 和 R3 响应.png)
SPI 模式下的初始化过程
在上电复位后,MMC/SDC 进入其默认操作模式。要进入 SPI 模式,必须执行以下步骤。
上电(存储卡插入)
当供电电压达到 2.2V 时,至少需要等待 1 毫秒。保持引脚 DI 和 CS 为高电平至少 74
个时钟周期(这里的时钟是 SCLK)
,然后存储卡才可以接收默认指令。
软件复位
设置 SPI 时钟速率在 100KHz~400KHz 之间,然后发送 CMD0 指令,同时拉低片选(CS)
引脚以复位存储卡。当存储卡接收到 CMD0 命令时,存储卡会自行检测引脚 CS 的电平,若
CS 电平为低,则卡片进入 SPI 模式。由于 CMD0 指令必须作为默认指令发出,所以指令中
的 CRC 域必须填充一个有效值。一旦存储卡进入 SPI 模式,CRC 校验功能被禁止,此后在
指令执行时,存储卡不会检查 CRC。
so that command transmission routine can be written with the hardcorded CRC value that vali
d for only CMD0 and CMD8
所以,把硬件记录的 CRC 值用于填充 CMD 命令中的 CRC 域,这样的“例行”命令只对
CMD0 和 CMD8 有效(这句翻译有问题,原文没太理解,不知是不是这个意思)
。一旦 CMD0
命令被成功执行,存储卡会进入空闲状态,并向主机回复带有空闲状态标志的 R1 响应
(0x01)。CRC 校验功能也可以被命令 CMD59 打开。
初始化
在空闲状态中,存储卡只接受命令 CMD0(软件复位)
、CMD1(初始化进程)
、ACMD41
(仅针对 SDC 的初始化)和 CMD58(读取 OCR 寄存器)
,除了这些命令之外的其他命令无
效。在空闲状态中,使用命令 CMD58 读取 OCR 寄存器中的内容,检查 OCR 寄存器指示的
工作电压范围,万一实际供电电压超出了工作电压范围,存储卡必须被“弹出”,值得注意的
是,所有存储卡的工作电压范围为 2.7V~3.6V。当存储卡收到命令 CMD1 时,便开始执行初
始化过程。主机在发送 CMD1 命令后必须不断检查卡片的响应以判断卡片的初始化是否已
经完成。当卡片成功初始化时,空闲状态下 R1 响应中的空闲状态位被清零(R1 响应由 0x01
变成 0x00)
。卡片的初始化过程可能需要几百个毫秒(卡的容量越大,初始化需要的时间也
越长)
,所以我们需要考虑超时的问题。在空闲状态位被清零后,就可以执行普通的 读/写 命
令了。
因为对于 SDC 来说,建议采用 ACMD41 而不是 CMD1 作为卡片的初始化命令,所以我
们可以先尝试 ACMD41 命令,若无效则再尝试 CMD1 命令,这样就可以完美支持这两种存
储卡(MMC/SDC)
。
为了优化读/写卡片的性能,SPI 总线的时钟速率应该尽可能的快,CSD 寄存器中
的 TRAN_SPEED 域表明了卡片可以接受的最快时钟速率。对于 MMC 来说,最快时钟速率
为 20MHz,对于 SDC 来说,大多数情况下,最快时钟速率则为 25MHz。
Note that the clock rate will able to be fixed to 20/25MHz in SPI mode because there is no ope
n-drain condition that restricts the clock rate.
注意,在 SPI 模式中,时钟速率可以被固定在 20/25MHz,这是因为没有开漏条件可以
限制时钟速率。
(此话有点不理解,不知这样翻译是否恰当)
对于 2GB 或更大容量的存储卡来说,初始的块长度可能会超过 512,所以,如果需要,
可以通过 CMD16 命令来改变 读/写 的块长度。
如何支持第二版本的 SDC 和高容量的存储卡
在使用 CMD0 命令使卡片进入空闲状态后,发送命令 CMD8
(参数设置为 0x000001AA)
,
在初始化过程之前改变 CRC。如果 CMD8 命令被拒——不合法的命令错误(0x05)
,那么存
储卡为第一代的 SDC 或是 MMCC。但若 CMD8 命令被接受,卡片会返回 R7 响应(由 R1
响应<0x01>和 32 位的数据位组成)
。返回值 0x1AA 的低 12 位表明该卡为第二代存储卡,
并能工作在 2.7V~3.6V 的电压范围之中,反之,卡片必须被“弹出”。CMD8 命令成功执行后,
则使用命令 ACMD41(参数为第 30 位的 HCS)执行初始化进程。在初始化进程结束后,主
机需要读取 OCR 寄存器中的第 30 位(CCS)
,若该位被置位,则下面要阐述的数据读/写操
作命令需要的参数是块的地址而非字节地址,一般情况下,块的大小为 512 字节。
数据传输
数据包和数据响应
在数据传输处理中,在响应了主机的读写命令后,存储卡便会开始发送或接收一个或多
个数据块。数据块是以数据包形式传输的,而数据包则由数据标志、数据块和 CRC 校验域
组成。数据包的格式如下图所示,可以看到,数据标志有三种,其中,“停止传输数据标志”
意味着多块读写操作结束,这个标志是作为字节单独使用的——不包含数据块以及 CRC。
(原文件名:数据传输和响应.png)
读单个块
(原文件名:读单个块.png)
读命令 CMD17 中的参数指定了读取字节或块的起始地址。
The sector address specified by upper layer must be scaled properly.
上层(软件)必须合理指定扇区地址(这句话是否该这样理解)?
若 CMD17 命令成功执行,存储卡将会执行读操作,将读到的数据块发送给主机。在检测到
有效数据标志后,主机会接收到数据域和两个字节的 CRC 校验域。
The CRC bytes must be flushed even if it is not needed.
尽管不需要,还是必须得刷新 CRC 域(flush 到底该如何理解)
。
如果在读操作中出现错误,存储卡将会返回错误标志而不是数据包。
读多个块
(原文件名:多块读.jpg)
多块读的指令可以从指定地址中连续读取多个块。如果在多块读指令之前没有指定需要
读取的块的数量,读进程将会以“开始—结束”的多块读形式执行,读操作将会持续到存储卡
收到 CMD12 命令为止。在收到命令 CMD12 之后的字节是废弃字节,主机必须在收到命令
CMD12 的回应之前把该废弃字节丢弃掉。
写单个块
(原文件名:写单个块.jpg)
当存储卡接收到写命令时,主机在收到命令响应后的 1 个时钟单元(1 个单元为八个
SCLK 时钟周期)后向存储卡发送一个数据包。数据包格式和读数据命令中的数据包格式是
一样的。除非 CRC 功能被开启,否则数据包中的 CRC 域可以被任何值填充。当数据包发出
以后,存储卡会在收到数据包后立即反馈一个数据响应给主机。数据响应后紧跟着一个忙碌
标志以执行写操作。大部分卡片无法修改写数据的块的大小,通常情况下写数据的块的大小
为 512。
在 SPI 模式中,原则上,在一个操作过程中,片选信号(CS)必须始终保持为低电平,
然而,这个规则还是有个例外的。当存储卡处于忙碌状态时,主机可以解除片选信号以释放
SPI 总线,从而去处理其他 SPI 设备。如果在存储卡处理内部进程时,片选信号再次有效,
存储卡会将引脚 DO 的电平拉低。
Therefore a preceding busy check (wait ready immediataly before command and data packet) inste
ad of post wait can eliminate waste wait time.
因此,提前检查卡片忙碌状态(在发送命令和数据包之前就开始)而不是轮询等待,可
以利用浪费的等待时间(这个话有点模棱两可)
。
此外,数据响应发出 1 个时钟单元后,卡片开始执行内部操作。换而言之,存储卡需要
8 个时钟周期以执行内部写操作。在此期间,不需要考虑片选信号的状态,从而可以释放
SPI 总线去执行其他工作。
The state of CS signal during the eight clocks is negligible so that it can done by bus release proce
ss described below.——这句话的后半句怎么理解呢?
写多个块
(原文件名:多块写.jpg)
多块写命令从指定地址开始连续写多个块,若在多块写命令之前没有制定传输数据块的
数量,默认将以“开始—停止”的方式执行该操作,即只有当数据包中的数据标志为停止传输
数据标志时,写多个块的操作才会停止。此时,在停止传输数据标志后,引脚 DO 上会出现
忙碌标志。对于 SDC,
the multiple block write transaction must be terminated with a Stop Tran token independent of the
transfer type, pre-defined or open-ended.
多块写操作需要“停止传输标志”来终止,该标志与数据传输类型无关,可以预先定义或采用
“开始—停止”方式。
(这句话该如何理解?)
读寄存器 CSD 和 CID
这些操作和读单个块的操作是类似的,只是不再需要定义数据块的长度了。CSD 和 CID
寄存器中的内容以 16 字节数据块的形式发送给主机。对于该 CMD 命令的细节,寄存器 CID
和 OCR 的相关知识,请参加 MMC/SDC 的说明书。
总线浮动和热插入的考虑
所有可能浮动的信号必须通过电阻拉成高电平抑或是低电平,对于 MOS 器件来说,这
是一个很普通的设计规则。由于引脚 DI 和引脚 DO 一般情况下是高电平,需要拉高。
SDC/MMC 的规格书建议采用 50KΩ~100KΩ 的上拉电阻。然而,在 SDC/MMC 的规格书中
并未设计到时钟信号的处理,这是因为时钟信号是由主机产生的,若时钟信号产生浮动,应
该将之拉低。
(这是为什么?)
MMC/SDC 支持热插拔,但需要注意主机电路的一些设计细节,以避免误操作。例如,
如果系统供电直接和卡座的电源相连,那么在存储卡被插入卡座时,存储卡的内置电容(与
电源引脚相连的电容)会被充电,从而产生充电电流,该电流会导致 Vcc 电压下滑。下图
中,图 A 表示了在存储卡插入时,
Vcc 电压会下滑约 600mV——这可能会出发单片机的 BOD
(Brown Out Dectect——欠压<低电压>检测)功能。图 B 表示了在电路中加入电感以阻止
电流突变时,Vcc 电压会下滑约 200mV。需要使用低 ESR(Equivalent Series Resistance——
等效串联电阻)的电容,如 OS-CON(固态有机半导体电容器——铝电解电容器)
,能够消
除 Vcc 电压下滑,如图 C 所示。然而,低 ESR 的电容器也会导致 LDO
(Low Dropout Regulator——低压差线性稳压器)的不稳定。
(可以采用开关电源稳压器)
(原文件名:总线浮动和热插入.png)
多从机配置的考虑
在 SPI 总线中,每个从机都被独立的片选信号(CS)选中,因而,SPI 总线可以连接多
个从机设备。普通 SPI 从机通过片选信号驱动或释放其 DO 信号来共享 SPI 总线。
However MMC/SDC drives/releases DO signal in synchronising to the SCLK.
然而,MMC/SDC 驱动或者释放 DO 信号是与 SCLK 同步的。
这意味着 MMC/SDC 和其他连接到 SPI 总线的从机有可能产生总线上的冲突,下图表明
了 MMC/SDC 驱动或释放的时序(引脚 DO 被拉到 Vcc/2 以看出总线状态)
。因此,为了让
MMC/SDC 释放 DO 引脚信号,主机设备必须在释放 CS 信号后向从机发送一个字节。
In the SPI bus, each slave device is selected with separated CS signals, and plural devices can be a
ttached to an SPI bus. Generic SPI slave device drives/releases its DO signal by CS signal asynchr
onously to share an SPI bus. However MMC/SDC drives/releases DO signal in synchronising to t
he SCLK. This means there is a posibility of bus conflict with MMC/SDC and any other SPI slave
s that attached to an SPI bus. Right image shows the drive/release timing of the MMC/SDC (the D
O signal is pulled to 1/2 vcc to see the bus state). Therefore to make MMC/SDC release DO signal
, the master device must send a byte after CS signal is deasserted.
这段话的理解有困难,翻译不太准确。
(原文件名:多从机设计.png)
优化写操作性能
大部分 MMC/SDC 采用 NAND 闪存作为存储阵列。NAND 闪存性价比较高且能够快速
读/写大量数据。但是,其缺点是在重写某个区域的数据时效率很低。一般来说,闪存需要
在写新数据之前擦除已有的数据,而且擦除操作的最小单位(称为擦除块)比写操作的数据
块要大。典型的 NAND 闪存对于写/擦除操作的块大小为 512Bytes/16KBytes。而且,当前的
高速卡采用了“大容量块操作”芯片(2KB/128KB)
。
This means that rewriting entire data in the erase block is done in the card even if write only a
sector (512 bytes).
这表明,在 NAND 介质存储卡中,即使只写一个扇区的数据(512Bytes)也需要在擦除
的块内重写整个数据。
(这句话究竟想要表达什么)
标准
现在假设某个嵌入式系统的存储空间是有限的,那么读写 SDC/MMC 的性能到底如何
呢 ? 笔 者 使 用 便 宜 的 Atmega64 ( 9.2MHz ) 进 行 了 测 试 。 考 虑 到 存 储 空 间 有 限 ,
write( ) 和 read( ) 函数一次仅读取 2048 字节。测试结果是,在容量为 128MB 的 SDC 上,写
速度为 77KB/sec,读速度为 328KB/sec。
对于 512MB 的 SDC,写速度低得可怜——只有 128MB SDC 写速度的 1/3。一般来说,
大容量存储设备的读/写速度与其面记录密度成正比。然而,对于存储卡来说,这个规则有
时是相反的。对于 MMC 来说,看上去其读写速度好像是 SDC 的几倍,性能并不坏。笔者
测试了不同厂家生产的 SDC,发现 PQI(劲永)厂家的 SDC 性能优于 Hitach(日立)的
MMC,而松下和东芝的存储卡产品性能较差。
擦除块的大小
为了分析写操作的细节,
busy time (number of polling cycles) after sent a write data is typed out to console in the low level
disk write function.
在发送一个写数据包后的忙碌时间(轮训时间)——这句话到底应该怎么理解。
Multiple numbers on a line indicates data blocks and a Stop Tran token that issued by a multiple bl
ock write transaction.
——这句话完全不理解。
分析结果表明,对于 128MB 的 SDC 和 512MB 的 SDC,其内部进程是有区别的。128MB
的 SDC 是在多块写操作完成后重写整个擦除块。而 512MB 的 SDC 似乎内置了 4KB 的数据
缓存,所以 512MB 的 SDC 以 4KB 为界重写擦除块,因此两者不能直接作比较。但重写擦
除块的时间可以检测出,对于 128MB 的 SDC,这个时间为 3800(单位是什么)
,而 512MB
的 SDC,这个时间则是 30000——几乎是 128MB SDC 的 8 倍。从分析结果判断,似乎 128MB
的 SDC 采用了小容量块的主控芯片,而 512MB 的 SDC 则采用了大容量块或是 MLC
(Multi=Level Cell—多层单元)主控芯片。当然,块尺寸越大,重写小部分块的性能越低。
对于 512MB 的 SDC,只有存储介质顶端的 512KB 的空间重写速度较快。这段时间可以通
过函数 close( )中的写时间读出。可能该空间是为了快速 FAT 访问而进行了特别处理。
提升写速度
为了避免上述提及的瓶颈,提高 SDC/MMC 的写速度,一次尽可能写入足够多的块(能
与擦除块对齐是最好的)能提升写数据的性能。换而言之,就是分配一个大的数据缓冲区并
将之传递给函数 fwrite( ) 。对于低级存储卡的写功能,必须预先告诉存储卡要写的扇区数以
提高写处理的效率。这被称为“预定义多块写”。然而,这里的预定义指令与 MMC(CMD23)
及 SDC(ACMD23)是不同的。
当然,对于只有几 KB RAM 的廉价 MCU 来说,这些提升 SDC 写速度的方法可能是徒
劳的。与 SDC 相比,CF(CompactFlash)卡的性能是其十倍。若你需要较高的写速度,CF
或 MMC 比 SDC 更合适。
存储卡出厂时被预先分区、格式化,以使分配单元与擦除块对齐。若不小心使用某个设
备将 MMC/SDC 重新格式化或分区时造成与 MMC/SDC 的不兼容。这种优化会被破坏,写
速度可能会降低。笔者曾经尝试过使用 PC 的 FAT32 重新格式化 512MB 的 SDC,在文件复
制时的传输速度下降了不少。因此,重新格式化存储卡需要使用与 MMC/SDC 兼容的设备
而不是 PC。