一、简介
SD卡是一种应用广泛的存储设备,ZYNQ也支持SD卡接口。本文对此接口进行介绍,主要包括SD卡,ZYNQ SD卡接口特性和基于FATFS文件系统的测试用例。
二、SD卡介绍
SD 卡的英文全称是 Secure Digital Card,即安全数字卡(又叫安全数码卡),是在 MMC 卡(Multimedia Card,多媒体卡)的基础上发展而来,是SD协会开发的一种专有的非易失性 存储卡格式,用于便携式设备。由于它体积小、数据传输速度快、可热插拔等优良的特性,被广泛地于便携式装置上使用。我们小时候也把SD卡叫做内存卡,经常会买来装在MP3,MP4和手机上下载电影,音乐之类的。ZYNQ也支持SD卡。
SD卡从尺寸上分成两种,一种是标准SD卡,一种是小尺寸的Micro SD Card也叫TF卡。


SD卡从容量上分为三种:SD 卡、SDHC卡(Secure Digital High Capacity,高容量安全数字卡)和 SDXC 卡(SD eXtended Capacity,容量扩大化的安全存储卡)。

SD卡速度分类比较多。不同的协议有不同的分类,SD2.0使用speedclass分类,SD3.0使用UHS(Ultra High Speed)分类。具体分类如下:

三、ZYNQ SD卡控制器简介
1、概述
ZYNQ的SD/SDIO 外设控制器控制与连接到 PS 的 SDIO 设备和 SD 存储卡之间的通信。它支持各种便携式低功耗的SD和SDIO应用,例如 802.11 设备、GPS、WiMAX、UWB 等。该外设兼容标准 SD Host Controller Specification Version 2.0 Part A2,并支持 SDMA(单次操作 DMA)、ADMA1(4 KB 边界受限 DMA)和 ADMA2(ADMA2 允许在 32 位系统存储器中以任意位置和任意大小传输数据------分散-聚集 DMA)。还支持 SD1、SD4 中最多七个功能,但不支持 SPI 模式。它支持 SD 高速(SDHS)和 SD 高容量(SDHC)卡标准。SD/SDIO 外设通过 AHB 总线与 ARM 处理器通信。SDIO 设备控制器支持内部 FIFO。

2、特点
- 仅支持主机模式
- 100 MHz AHB 主从 CPU 1x 时钟
- 支持 AHB 主设备 DMA 接口
- 支持 AHB 从设备接口
- 支持 SD 规范 2.0 版
- 支持全速和低速
- 支持 1 位和 4 位数据接口
- 低速时钟 1-400 KHz
- 支持高速接口
- 全速时钟 1-50 MHz,最大吞吐量为 25 MB/s
- 支持存储卡、I/O 卡和组合卡
- 支持电源控制模式
- 支持中断
- 1 KB 数据 FIFO 接口
3、SD卡控制器系统视图
SD卡控制器的系统级视图如下。根据此图可知,SDIO接口控制器的中断类型为IRQ中断,中断ID分别是56,79。和系统内核通过AHB总线交互。由系统内核提供时钟和复位是信号。SD卡控制器的IO可以路由到MIO也可以路由到EMIO。

4、SD卡控制器功能描述
4.1 概述
当使用程序控制 I/O(programmed I/O)方式时,数据事务通过 AHB 接口执行。处理器随后使用缓冲数据端口(Buffer Data Port)寄存器进行数据传输。当这些事务在 DMA 控制下执行时,AHB 接口会发起与存储器之间的读事务或写事务。如果中断状态寄存器中有任何中断位被置位,控制器就会向处理器生成中断。
SD/SDIO主机控制器包括:
• 主机-AHB 控制器
• 所有控制寄存器
• 总线监视器
• 时钟生成器
• CRC 生成器和校验器(CRC7 和 CRC16)
主机-AHB 控制器充当 AHB 总线与主机控制器之间的桥接。SD/SDIO 控制器寄存器由处理器通过 AHB 接口进行编程。中断根据中断状态寄存器和中断使能寄存器中设置的值生成。总线监视器检查 SD 总线上发生的违规和超时情况。时钟生成模块根据时钟控制寄存器中编程的值生成 SD 时钟。CRC7 和 CRC16 生成器计算与 SD/SDIO 卡之间命令和数据传输的 CRC。CRC7 和 CRC16 校验器检查从 SD/SDIO 卡接收的响应和数据中是否存在任何 CRC 错误。为了检测卡上的数据缺陷,主机可以在有效载荷数据中包含纠错码。ECC 码用于将数据存储在卡上。应用程序使用该 ECC 码来解码用户数据。
控制器使用两个512字节的双端口FIFO来执行写事务和读事务。在写事务期间(数据从处理器传输到所连接的卡),处理器交替地将数据写入第一个和第二个 FIFO。当数据被传输到所连接的卡时,交替使用第二个和第一个 FIFO,从而实现最大数据吞吐量。在读事务期间(数据从所连接的卡传输到处理器),来自卡的数据交替写入这两个 FIFO。当其中一个 FIFO 中的数据被传输到处理器时,第二个 FIFO 则被来自卡的数据填充,反之亦然,从而优化数据吞吐量。如果控制器无法接收来自所连接卡的任何数据,它会发出"读等待"(read wait),通过停止时钟来停止来自卡的数据传输。
WRITE_DAT_UNTIL_STOP(CMD20) 从主机写入数据流,从给定地址开始,直到随后出现 STOP_TRANSMISSION。READ_DAT_UNTIL_STOP(CMD11)从卡读取数据流,从给定地址开始,直到随后出现 STOP_TRANSMISSION。主机控制器在向第一个 FIFO 写入一块数据或从第一个 FIFO 读取一块数据后,切换到第二个 FIFO,但流事务的块大小并不是由驱动程序编程设置的。因此,对于流写和流读事务,建议主机驱动程序将最大 FIFO 大小值写入块大小寄存器。由于 SDIO FIFO 切片设置为 512 字节,主机驱动程序必须将 512 字节写入块大小寄存器。因此,FIFO 切换在写入/读取 512 字节数据之后发生。
SDIO 时钟由 SDIO 参考时钟根据驱动程序编程的时钟控制寄存器值派生而来,并且仅当驱动程序设置了 SD 时钟使能时才可用。对于 SD,最大频率为 50 MHz。主机控制器同时支持全速卡和高速卡。对于高速卡,主机控制器应在 SDIO 时钟的上升沿输出数据。对于全速卡,主机控制器应在 SDIO 时钟的下降沿输出数据。
SD/SDIO 控制器支持在多种配置下运行:
• 安全数字(SD)存储器
• 安全数字输入/输出(SDIO)
一些 SD 卡槽提供两个额外引脚:卡检测(CD),用于指示卡的插入或存在;写保护(WP),用于报告存储卡上写保护开关的位置。当检测到卡或卡处于写保护状态时,这些引脚通常被拉至 GND。它们需要通过一个 50 KΩ 电阻上拉至 MIO I/O 电压。如下图所示

SDIO 接口可通过 MIO 以及 EMIO 接口使能。它们是互斥的,因为一旦将接口路由通过 MIO,它就不再能通过 EMIO 使用。而且通过 EMIO 的 SDIO 最大工作频率是受限的。EMIO 连接应将 PS SDIO EMIO 接口直接连接到 PL PAD。此外,可能有必要限制 SDIO 仅以全速或低速模式运行。
SD 传输根据块数的指定方式,基本上分为以下三种类型:
- 单块传输:在传输之前,向主机控制器指定块数。所指定的块数始终为一。
- 多块传输:在传输之前,向主机控制器指定块数。所指定的块数为一个或多个。
- 无限块传输:在传输之前,不向主机控制器指定块数。此传输持续进行,直到执行中止事务。对于 SD 存储卡,该中止事务由 CMD12 执行;对于 SDIO 卡,该中止事务由 CMD52 执行。
4.2 SD卡数据传输过程
4.2.1 不使用 DMA 进行数据传输的序列

不使用 DMA 进行数据传输的序列如下:
1、将对应于一个块所执行数据字节长度的值设置到 Block Size 寄存器。
2、将对应于所执行数据块数量的值设置到 Block Count 寄存器。
3、将对应于所发出命令的值设置到 Argument 寄存器。
4、将值设置到 Multi/Single Block Select和Block Count Enable。将对应于所发出命令的值设置到Data Transfer Direction、Auto CMD12 Enable和DMA Enable。
5、将对应于所发出命令的值设置到 Command 寄存器。
注意:当写入命令寄存器的高字节时,SD 命令被发出。
6、等待命令完成中断。
7、向 Normal Interrupt Status 寄存器中的 Command Complete 位写入 1 以清除该位。
8、读取 Response 寄存器,并根据所发出的命令获取必要信息。
9、如果此序列用于向卡写入,转到步骤 (10-W)。如果是从卡读取,转到步骤 (10-R)。
(10-W)、等待缓冲区写就绪中断。
非 DMA 写传输
在收到缓冲区写就绪中断时,ARM 处理器作为主设备,开始通过 Buffer Data Port 寄存器 (FIFO_1) 传输数据。当 FIFO_1 中一个数据块准备好时,发送器开始向 SD 总线发送数据。在 SD 总线上传输数据的同时,针对第二个数据块的缓冲区写就绪中断被发送给 ARM 处理器。ARM 处理器作为主设备,开始通过缓冲数据端口寄存器将第二个数据块发送到 FIFO_2。仅当某个 FIFO 为空且可接收一个数据块时,缓冲区写就绪中断才被置位。
(11-W)、向 Normal Interrupt Status 寄存器中的 Buffer Write Ready 位写入 1 以清除该位。(12-W)、向 Buffer Data Port 寄存器写入一个数据块(根据步骤 (1) 中指定的字节数)。
(13-W)、重复直到所有块都发送完毕,然后转到步骤 (14)。
非 DMA 读传输
每当某个 FIFO 中一个数据块准备好时,缓冲区读就绪中断被置位。在收到缓冲区读就绪中断时,ARM 处理器作为主设备,开始通过 Buffer Data Port 寄存器 (FIFO_1) 读取数据。仅当某个 FIFO 为空且可接收一个数据块时,接收器才开始从 SD 总线读取数据。当两个 FIFO 都满时,主机控制器通过读等待机制(如果卡支持读等待)或通过停止时钟来停止来自卡的数据。
(10-R)、等待缓冲区读就绪中断。
(11-R)、向 Normal Interrupt Status 寄存器中的 Buffer Read Ready 位写入 1 以清除该位。
(12-R)、从 Buffer Data Port 寄存器读取一个数据块(根据步骤 (1) 中指定的字节数)。
(13-R)、重复直到所有块都接收完毕,然后转到步骤 (14)。
14、如果此序列用于单块或多块传输,转到步骤 (15)。如果是无限块传输,转到步骤 (17)。
15、等待传输完成中断。
16、向 Normal Interrupt Status 寄存器中的 Transfer Complete 位写入 1 以清除该位。
17、执行中止事务的序列。
18、注意:步骤 (1) 和步骤 (2) 可以同时执行。步骤 (4) 和步骤 (5) 可以同时执行。
4.2.2使用DMA传输的序列

突发类型,例如 8 拍递增突发、4 拍递增突发或单次传输,用于从系统存储器传输或接收数据,主要是为了避免主设备长时间占用 AHB 总线。
使用 DMA 的序列如下:
1、将 DMA 的系统地址设置到 System Address 寄存器。
2、将对应于一个块所执行数据字节长度的值设置到 Block Size 寄存器。
3、将对应于所执行数据块数量的值设置到 Block Count 寄存器。
4、将对应于所发出命令的值设置到 Argument 寄存器。
5、设置 Multi/Single Block Select 和 Block Count Enable 的值。将对应于所发出命令的值设置到 Data Transfer Direction、Auto CMD12 Enable 和 DMA Enable。
6、将对应于所发出命令的值设置到 Command 寄存器。
注意:当写入 Command 寄存器的高字节时,SD 命令被发出。
7、等待命令完成中断。
8、向 Normal Interrupt Status 寄存器中的 Command Complete 位写入 1 以清除该位。
9、读取 Response 寄存器,并根据所发出的命令获取必要信息。
- DMA 读传输
在收到卡针对写命令返回的 Response End Bit 时(数据正从主机流向卡),SD 主机控制器作为主设备并请求 AHB 总线。收到授权后,主机控制器开始从系统存储器读取一个数据块,并填充 FIFO 的前半部分。每当一个数据块准备好时,发送器就开始在 SD 总线上发送数据。
在 SD 总线上传输数据的同时,主机控制器请求总线,以将第二个数据块填充到 FIFO 的后半部分。使用"乒乓"FIFO 来提高吞吐量。类似地,每当一个 FIFO 为空时,主机控制器就从系统存储器读取一个数据块。此过程持续进行,直到从系统存储器读取完所有数据块。只有在将所有数据块传输到卡之后,才置位传输完成中断。
- DMA 写传输
从卡接收到的数据块(数据正从卡流向主机)被存储到 FIFO 的前半部分。每当一个数据块准备好时,SD 主机控制器就作为主设备并请求 AHB 总线。收到授权后,主机控制器开始将来自 FIFO 前半部分的一个数据块写入系统存储器。
在将数据传送到系统存储器的同时,主机控制器接收第二个数据块,并将其存储到 FIFO 的后半部分。类似地,每当数据准备好时,主机控制器就将一个数据块写入系统存储器。此过程持续进行,直到所有数据块都被传输到系统存储器。只有在将所有数据块传输到系统存储器之后,才置位传输完成中断。
注意:仅当 FIFO 中有空间存储一个数据块时,主机控制器才从卡接收一个数据块。当两个 FIFO 都满时,主机控制器通过"读等待"机制(如果卡支持读等待)或通过停止时钟来停止来自卡的数据。
10、等待传输完成中断和 DMA 中断。
11、如果 Transfer Complete 被置为 1,转到步骤 (14)。如果 DMA Interrupt 被置为 1,转到步骤 (12)。Transfer Complete 的优先级高于 DMA Interrupt。
12、向 Normal Interrupt Status 寄存器中的 DMA Interrupt 位写入 1 以清除该位。
13、将下一数据位置的下一系统地址设置到 System Address 寄存器,并转到步骤 (10)。
14、向 Normal Interrupt Status 寄存器中的 Transfer Complete 和 DMA Interrupt 写入 1 以清除该位。
注意:步骤 (2) 和步骤 (3) 可以同时执行。步骤 (5) 和步骤 (6) 也可以同时执行。
例如,如果主机要向卡传输 4 KB 数据,并假设最大块大小为 256 字节,则主机驱动程序将 Block Size 寄存器编程为 256,并将 Block Count 寄存器编程为值 16。位于 SD2.0/SDIO2.0 主机控制器内部的 AHB 主设备和发送器从这些寄存器获取信息(要传输多少数据)。使用上述信息,AHB 主设备作为主设备,发起一次数据读事务(从系统存储器读取一个数据块------256 字节)。
以下类型的突发主要用于避免主设备长时间占用 AHB 总线。
-
单次传输
-
4 拍递增突发
-
8 拍递增突发
第一个数据块被接收到 FIFO 的前半部分,第二个数据块被接收到 FIFO 的后半部分。类似地,其余数据块交替接收到不同的 FIFO 中。每当 FIFO 中有一个数据块准备好时,发送器就开始将该数据块(256 字节)发送到 SD 总线上。在将整个数据块传输到卡之后,发送器等待来自卡的状态响应。只有当发送器收到卡对前一数据块的良好状态响应时,才发送下一个数据块;否则,该事务被中止,主机重新开始一个新的事务。
4.2.3、使用ADMA传输的序列

在系统存储器中为 ADMA 创建一个描述符表。
1、将 ADMA 的描述符地址设置到 ADMA System Address 寄存器。
2、将对应于一个块所执行数据字节长度的值设置到 Block Size 寄存器。
3、根据 SDIO 寄存器映射,将对应于所执行数据块数量的值设置到 Block Count 寄存器。
4、如果 Transfer Mode 寄存器中的 Block Count Enable 位被设置为 1,则总数据长度可以由 Block Count 寄存器和描述符表指定。这两个参数应指示相同的数据长度。但是,传输长度受 16 位 Block Count 寄存器的限制。
如果 Transfer Mode 寄存器中的 Block Count Enable 位被设置为 0,则总数据长度不是由 Block Count 寄存器指定,而是由描述符表指定。在这种情况下,如果 ADMA 从 SD 卡读取的数据多于描述符中编程的长度,则该操作被异步中止,并且在 ADMA 完成时丢弃多余的读取数据。
5、将参数值设置到 Argument 寄存器。
6、将值设置到 Transfer Mode 寄存器。主机驱动程序确定 Multi/Single Block Select、Block Count Enable、Data Transfer Direction、Auto CMD12 Enable 和 DMA Enable。Multi/Single Block Select 和 Block Count Enable 根据 SDIO 寄存器映射确定。
7、将值设置到 Command 寄存器。
注意:当写入 Command 寄存器的高字节 3 时,SD 命令被发出并且 DMA 启动。
8、等待命令完成中断。
9、向 Normal Interrupt Status 寄存器中的 Command Complete 位写入 1 以清除该位。
10、读取 Response 寄存器,并从所发出的命令中获取必要信息。
11、等待传输完成中断和 ADMA 错误中断。
12、如果 Transfer Complete 被置为 1,转到步骤 (13)。如果 ADMA Error Interrupt 被置为 1,转到步骤 (14)。
13、向 Normal Interrupt Status 寄存器中的 Transfer Complete Status 位写入 1 以清除该位。
14、向 Error Interrupt Status 寄存器中的 ADMA Error Interrupt Status 位写入 1 以清除该位。
15、中止 ADMA 操作。应通过发出中止命令来停止 SD 卡操作。如有必要,主机驱动程序检查 ADMA Error Status 寄存器,以检测为什么产生 ADMA 错误。
注意:步骤 (3) 和步骤 (4) 可以同时执行。步骤 (6) 和步骤 (7) 也可以同时执行。
注意:在 ADMA2 操作期间,如果 INT 属性与 NOP、RSVD 或 LINK 属性一起设置,控制器将不会生成 DMA 中断。