低功耗、低噪声的MAXQ2000微控制器适合于多种应用。MAXQ2000在闪存中存储非易失性数据,并和用户代码空间共享32k字(64kB)的闪存容量。但如果你的应用需要更多的非易失性存储器怎么办呢? 这篇文章说明了如何使用安全数码(SD )存储介质来扩展MAXQ2000的非易失性数据存储器。
对于你的应用设计来说,首要应该考虑电源电压和电流的要求。在典型的MAXQ2000应用中,可采用一个双路线性稳压器,从而在所选的时钟频率下使处理器工作于尽可能低的核心电压(V(DD))下。MAXQ2000的V(DD)电压可低至1.8V。V(DDIO)为MAXQ2000的I/O引脚供电,允许的电压范围最低至V(DD),最高可达3.6V。可接受的外部存储器电流消耗受限于电源的额定电流,对于电池供电设备,则电流消耗受限于电池系统的容量。
其次,在保证能为目标应用提供足够带宽的前提下,应将连接外部存储器的MAXQ2000 I/O数限制到最少。例如,Atmel的AT29LV512闪存芯片与一个主机微控制器连接时,需要15条地址线、8条数据线和3条控制线。由于MAXQ2000没有外部地址/数据总线,在上述例子中,就需要由软件来控制总线事务。对于某些应用来说,这种方法不能很有效地利用MAXQ2000的I/O引脚。
然而,基于SPI 和I²C的外部闪存器件只需要3到4个接口引脚。MAXQ2000具有一个硬件SPI模块,而I²C在MAXQ2000上必须由用户通过软件实现(即"位模拟")。这种集成功能使得SPI接口成为访问外部非易失性存储器的主要途径。
SD存储介质是一种非易失性外部存储器,可满足许多应用的上述要求。SD格式是"多媒体卡" (MMC)格式的继任产品。SD卡存储器一般工作于3.3V电压,具有适度的电流要求。SD卡的容量从几兆字节到最高4GB不等。容量范围如此之宽,可为众多应用提供充足的外部存储空间。
由于SD卡采用专有的共享总线,乍一看,似乎很难与MAXQ2000接口。然而,SD继承了MMC的第二总线格式-SPI。由于MAXQ2000提供SPI硬件支持,连接非常容易。
图1. MAXQ2000与SD存储卡的接口非常简单。
图1的电路图给出了一个典型应用电路。SD卡要求全双工、8位SPI操作。数据从MAXQ2000的MOSI引脚同步输入SD卡的DI引脚,并由SD卡的DO线同步输入MAXQ2000的MISO引脚。数据在CLK信号的上升沿同步输入和输出。在每次数据传输的末尾还必须提供8个额外的时钟,以允许SD完成任何未完结的操作。对应这些额外时钟的输入数据必须全为1。识别阶段的时钟频率必须限定在400kHz以内,但SD卡一经识别后,时钟频率便可提高到25MHz。
MAXQ2000包含一个硬件SPI模块,可以方便地针对SD卡接口进行配置。为了配置时钟极性和数据长度,需将SPICF寄存器置为全零。这种SPI模块配置在时钟的上升沿锁存数据,并将数据长度设置为8位。对于本应用,MAXQ2000的系统时钟频率为16MHz。在这种情况下,需要将SPICK寄存器置为0x28,从而使SPI时钟频率接近380kHz。必须将SPICN寄存器的低2位置位,以使能SPI主机模式。
SD卡的SPI协议与SD总线协议相似。如果一片SD卡没有数据要发送,则将DO引脚保持在全1的空闲状态,因此不是在每个时钟沿都从SD卡的DO引脚接收有效数据。当SD卡有数据要回送给主机时,要在数据之前先发送一些以0为起始位的特定令牌。当这些令牌发送完毕之后,SD卡要发送的所有定长数据立即被发送出去。由于接收器事先已经知道要接收的字节数,因而响应中不包含表征长度的字节。此外,由于在起始令牌和数据都发送完毕后才会进入空闲状态,所以全部数据字节都以不带前缀的原始形式发送。和总线上其它所有通信过程一样,令牌大小也要和SPI传输的8位边界对齐。主机发送给SD卡的指令和数据都遵循类似的格式,以全1指示总线空闲。除了状态令牌以外,所有传输都由附加在数据末尾的循环冗余校验(CRC)码进行保护。系统提供两种CRC算法:CRC-7用于小数据块,CRC-16则用于大数据块。CRC是SD SPI接口的可选部分,但除非应用系统限制它的使用,否则应该使用CRC来确保数据的完整性。
CRC算法通常用于检测由不可靠的通信通道引起的误差。特定CRC类型的选择根据需要保护的数据长度来决定。对于基于SD存储介质的数据,采用CRC-7和CRC-16编码方式。
CRC算法将被保护的数据用选中的除数进行除法运算,产生一个余数。因为该算法中用得的是多项式,所以该除法运算不含进位逻辑。无需考虑进位时,除法运算可通过逻辑XOR操作来实现。所选中的除数通常用CRC的多项式来表示。接着,计算出的余数和数据一起传输,接收器用此余数来检查确认数据在传输过程中是否正常。
对于CRC-7,余数可通过一个7位移位寄存器在软件中计算。计算开始时,将该移位寄存器初始化置为全零。当受保护数据的每一位(MSB在先)被移入移位寄存器的LSB时,移出移位寄存器的MSB,并进行检查。如果移出的位为1,则用CRC-7多项式系数0x09进行异或运算,以此来修正移位寄存器的内容。如果从移位寄存器中移出的位为0,则无需XOR操作。受保护数据的最后一位被移入移位寄存器且完成了条件XOR操作后,必须按此类似方式移入7个或更多0。这一过程称作扩张并完成多项式除法运算。此时,CRC-7值可从移位寄存器直接读出。
图2. 通过移位寄存器架构计算CRC-7。
当接收器收到所有受保护的数据后,接收器可计算基于受保护数据的CRC-7值并将改值与接收到的CRC-7值进行比较。如果这两个值不同,接收器就能判断出受保护数据在传输过程中出现错误。如果这两个值相同,则接收器可完全判定通信通道上的数据是完整的。
CRC-16算法可用同样的方式来构建。在这种情况下,移位寄存器长度为16位而不是7位;多项式系数改为0x1021,且输入数据通过16个0位来扩张。
发送给SD卡的命令采用6字节的格式(图3)。命令的第1个字节可通过将6位命令码与16进制码0x40进行或运算得到。如果命令需要,则在接下来的4个字节中提供一个32位的参数;最后1个字节包含了从第1个字节到第5个字节的CRC-7校验和。表1列出了一些重要的SD命令。
图3. 发送给存储卡的SPI模式SD命令采用6字节格式。
表1. 部分SD存储卡命令
Command | Mnemonic | Argument | Reply | Description |
0 (0x00) | GO_IDLE_STATE | none | R1 | Resets the SD card. |
9 (0x09) | SEND_CSD | none | R1 | Sends card-specific data. |
10 (0x0a) | SEND_CID | none | R1 | Sends card identification. |
17 (0x11) | READ_SINGLE_BLOCK | address | R1 | Reads a block at byte address. |
24 (0x18) | WRITE_BLOCK | address | R1 | Writes a block at byte address. |
55 (0x37) | APP_CMD | none | R1 | Prefix for application command. |
59 (0x3b) | CRC_ON_OFF | Only Bit 0 | R1 | Argument sets CRC on (1) or off (0). |
41 (0x29) | SEND_OP_COND | none | R1 | Starts card initialization. |
刚上电时,SD卡缺省使用专有的SD总线协议。为了将SD卡切换到SPI模式,主机应发出命令0 (GO_IDLE_STATE)。SD卡会检测到SPI模式选择信息,因为卡选择(CS)引脚在该命令和其它所有SPI命令传送过程中都保持为低电平。SD卡以R1响应(图4)作为回应。空闲状态位被置为高电平,表明SD卡已进入空闲状态。为了保持与MMC卡的兼容性,此阶段的SPI时钟频率一定不能超过400kHz。
图4. R1响应指示发出的命令是否成功执行。
SD卡进入SPI模式后,SD规范要求主机在进行其它任何请求之前先发送一条初始化命令。为了能区分MMC卡和SD卡,SD卡采用了一种不同的初始化命令,MMC卡对该命令是不响应的。先向卡发送命令55 (APP_CMD),紧接着再发送应用命令41 (SEND_OP_COND),这样即完成了这个重要的步骤。MMC卡对命令55不做回应,通过这一点可鉴别出MMC卡,并将其视作无效介质而拒绝访问。这个命令序列要一直重复执行,直到来自存储卡的R1响应中所有位均为0 (也就是说,IDLE位变为低)才停止。
清单1. 代码必须用SEND_OP_COND来识别SD和MMC卡。
SD卡包含了一些重要的寄存器,用来提供SD卡的相关信息。最重要的寄存器是存储卡特定数据寄存器(CSD)。对于我们的应用示例而言,我们感兴趣的是存储器的数据块大小和总容量。我们还必须对存储卡标识数据寄存器(CID)加以注意,因为它包含了存储卡的制造商详细信息和序列号。图5显示了CSD寄存器和CID寄存器的配置结构。
图5. CSD寄存器和CID寄存器提供SD卡的相关信息。
要读取存储卡的寄存器或数据块,我们首先必须理解存储卡如何响应我们的请求。在SPI模式下,SD卡以R1应答SEND_CSD (9)、SEND_CID (10)和READ_SINGLE_BLOCK (17)命令。接着则是一个起始令牌,然后是所请求的数据,最后是数据的CRC-16校验和。我们不能想当然地认为数据起始令牌是紧接着R1响应即刻发出的,因为总线在这两个事件之间会进入空闲状态一段时间。图6显示了数据响应的细节。
图6. 从SD卡到主机的数据传输要加入一个起始令牌作为前缀。
使用SEND_CSD和SEND_CID命令可返回寄存器的内容,以便确定SD卡的参数。这些命令分别返回与CSD或CID寄存器容量大小一致的固定数量的字节。SEND命令字节中包含的参数被SD卡忽略。
从SD卡中读取一个数据块是相当简单的。主机发出READ_SINGLE_BLOCK命令,并将起始字节地址作为参数。这个地址必须和介质上一个块的起始位置对齐。然后SD卡会验证这个字节地址,并以一个R1命令作为响应。如果命令中的地址越界,则会在命令响应中指示这种情况。
如果完成了SD介质的读取操作并且没有错误发生,则先发送一个起始数据令牌,接着是固定数量的数据,最后是两个字节的CRC-16校验和。如果SD卡碰到硬件故障或介质读取错误,则不会发送起始数据令牌。而是发送一个错误令牌,数据传输随之中止。
写入一个数据块和读取数据块类似,即主机必须提供一个与SD卡数据块边界对齐的字节地址。写入数据块的大小必须与READ_BL_LEN相同,一般为512字节。通过发出WRITE_BLOCK (24)命令启动写操作过程,SD卡将以R1命令响应格式进行应答。如果命令响应表明写操作可以进行,则主机发送数据起始令牌,接着是固定数量的数据字节,最后以发送数据的CRC-16校验和结束。SD卡返回一个数据响应令牌以指示待写入的数据是否被接受。
如果数据被接受,SD卡会在存储卡忙时始终将DO线保持为低电平。存储卡忙期间,主机不必始终将卡选择线保持为低电平,如果解除CS选择状态,SD卡将释放DO线。当多于一个的设备与SPI总线连接时,上述处理方式非常有用。主机可以一直等待SD卡释放忙指示标志,也可以定期触发片选信号以检查存储卡的工作状态。如果卡仍然处于忙状态,它会将DO线拉低以指示该状态。否则,存储卡会使DO线返回至空闲状态(见图7)。
图7. 从主机到SD卡的数据传输使用一套更为复杂的握手机制。
可利用CRC-7和CRC-16校验来检测主机与SD卡间的通信错误。如果因物理因素而导致错误发生,如在插入、移除时的触点抖动,或是可拆卸介质固有的接触不良状况,错误检测机制可实现坚固的错误恢复功能。我们强烈建议使用校验和机制,这可以通过发出CRC_ON_OFF (59)命令并将参数的最低位置为高来启动该功能。
清单2. 强烈推荐使能CRC校验和。
SD存储卡为嵌入式系统提供了一种紧凑和低功耗的非易失性存储器方案。利用MAXQ2000微控制器提供的硬件SPI模块,能以极少的开销访问SD介质卡。Maxim公司提供的参考软件(可由 china.maximintegrated.com/MAXQ2000_SD 获取)演示了一个最小的实现方案,包括从SD卡读取数据块和向SD卡写入数据块所需的基本操作。
参考文献
更多关于SD存储介质的信息可从 Secure Digital Association 获取。
Further information on the SDmedia format can be obtained from the Secure Digital Association at Secure Digital Association .The SD media breakout board used in this project can be ordered from .