1、存储芯片分类
目前市面上的存储芯片,大致可以将其分为 3 大类:
① EEPROM
EEPROM (Electrically Erasable Programmable read only memory) 是指带电可擦可编程只读存储器,是一种掉电后数据不丢失的存储芯片。EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。
这类产品容量小,读取速度慢,且无法在应用过程中写入数据,十分不便。目前多存在于一些 MCU 内部,如遥控器,电风扇等各类低端、低速消费类产品。相信你读大学如果玩单片机的话,那么应该是不陌生。
② NOR Flash
NOR Flash 由 Intel 在 1988 年发明,是市场上两种主要的非易失闪存技术之一。NOR Flash 技术的出现,彻底改变了原先由 EPROM 和 EEPROM 一统天下的局面。
NOR Flash 可能是目前应用领域最广泛的一种存储芯片了,基本上主流的电子产品里都有使用,比如手机摄像头内部,或者屏幕驱动电路板。主要用来存储代码和一些比较小的数据文件。NOR Flash 架构决定了它的容量不能做大,而且读取速度比较慢。好处在于简单易用,其接口可以实现地址寻址,也就意味着可以做到直接对某个地址直接操作,而不需要建立额外的文件系统。
③ NAND Flash
虽然很多人平常说的 Flash 存储器一半默认其就是 NOR Flash ,但这无疑是不严谨的。FLASH 产品可以分为两个大类:NOR Flash 和 NAND Flash 。
NAND Flash 是市场上两种主要的非易失闪存技术之一,由东芝公司在 1989 年发明。其强调降低每比特的成本,并拥有更高的性能,可以像磁盘一样可以通过接口轻松升级。
NAND Flash 应该是目前最热门的存储芯片了。因为我们生活中经常使用的电子产品都会涉及到它。比如你买手机,肯定会考虑 64GB,还是 256GB?买笔记本是买 256GB,还是 512GB 容量的硬盘呢?(目前电脑大部分采用了基于 NAND Flash 产品的固态硬盘)
2、NOR Flash 与 NAND Flash 的区别
Flash 闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何 Flash 器件的写入操作都只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。NAND 器件执行擦除操作是十分简单的,而 NOR 则要求在进行擦除前先要将目标块内所有的位都写为 0。
执行擦除时块尺寸的不同进一步拉大了 NOR 和 NAND 之间的性能差距,统计表明,对于给定的一套写入操作 (尤其是更新小文件时),更多的擦除操作必须在基于 NOR 的单元中进行。这样,当选择存储解决方案时,用户必须权衡以下因素:
NOR Flash 支持随机访问,所以支持 XIP(execute In Place),NAND Flash 需要按块进行读取,所以不支持 XIP
NAND FLASH 理论读取速度与 NOR Flash 相近,实际情况会根据接口不同有些差异
NOR 与 NAND 写入前都需要先擦除,NOR 在擦除时以 64 ~ 128KB 的块进行,执行一个写入 / 擦除操作的时间约 5s,NAND 在擦除时以 8 ~ 32KB 的块进行,执行一个写入 / 擦除操作的时间约 4ms
NAND 理论最大擦除次数比 NOR 多
NOR 驱动比 NAND 简单,NAND FLASH 需要通过专门的 NFI(NAND FLASH Interface)与 Host 端进行通信,驱动相对复杂
所有 Flash 都会有位反转的问题,NAND 位反转概率要比 NOR 高,NAND Flash 必须要使用 ECC
NAND 的单元尺寸几乎是 NOR 器件的一半,所以 NAND 成本更低
NOR 与 NAND 各有特点,应用场景与应用难度也不同,一般来讲,NOR 适用于小容量、略低速且需要直接对地址块进行操作的应用,而 NADN 则适用于大容量的高速应用。SD NAND 在保留了 NAND 架构优质特性的同时改进了不足之处,内置的控制器能自行管理 NAND Flash,无需在外部处理 ECC 和进行坏块管理,免去了 MTD 层,不需要写繁琐的驱动代码。
3、什么是 SD 卡?
① 概述
SD 卡的英文全称是 Secure Digital Card,即安全数字卡(又叫安全数码卡),是在 MMC 卡(Multimedia Card,多媒体卡)的基础上发展而来,主要增加了两个特色:更高的安全性和更快的读写速度。
② 容量标准和速度等级
若按照容量 对 SD 卡进行等级划分,SD 卡可分为 4 个等级,SD(Secure Digital Card,安全数字卡) 卡、SDHC 卡(Secure Digital High Capacity,高容量安全数字卡)、SDXC 卡( SD eXtended Capacity,容量扩大化的安全数字卡)和 SDUC(Secure Digital Ultra Capacity,超 容量安全数字卡)。现今,市场的主流 SD 产品是 SDHC 和 SDXC 这两种较大容量的存储 卡,SD 卡因容量过小,已逐渐被市场淘汰,SDUC 则是容量太大,预计会出现在未来市 场。SD 卡的四种容量标准,具体见下图:
不同品牌和厂商生产的 SD 卡在对存取速度上的定义标准不同,这会使用户在选择 SD 卡时产生困扰。所以 SD 协会根据视频匀速写入到 SD 卡的最低持续速度来划分不同等级, 每个等级的速率是以每秒传输多少 MB 来衡量的,单位为 MB/S。
SD 协会定义了三种速度等级:速度等级、UHS 速度等级与视频速度等级。三种速度等级的具体传输速度如下图:
4、什么是 SD NAND?
上文中提到的 SD 卡其实更应该叫做 TF 卡,在日常生活中最常见的应用就是数码相机的存储卡。因为它是可拆卸的,所以这类 SD 卡最大的优点就是便携方便,但同时也有容易丢失和接触不良等毛病,所以多用于消费类产品。
在工业级应用中,更多见的是一类贴片式的 SD NAND 产品,俗称贴片式 T 卡或贴片式 SD 卡。虽然 SD NAND 和 TF 卡称呼上有些类似,但是 SD NAND 和 TF 卡有着本质上的区别:
为什么 SD NAND 和 TF 卡 之间有这么大区别呢?因为 SD NAND 是为内置存储而生,是焊接在 PCB 板上的,是针对工业级应用的产品,所以品质稳定、一致性高、使用稳定性高、同时尺寸也小。而 TF 卡主要是针对普通消费者,品质和一致性、使用稳定性等相对要求不高,再加上国内鱼龙混杂的市场环境,导致内置存储用 TF 卡的品质风险高。
NAND Flash 产品的一个特质就是它的品质并不是 0 和 1 这么简单,有些品质隐患是使用一段时间之后才被发现,如果这个产品已经销往海外,处理起来会变得异常麻烦。使用 SD NAND 可以为客户产品带来整体品质的提升,提供确定性,是客户产品良好品牌和口碑的稳定基石。而使用 TF 卡时,产品整机不可控因素会增高,比如常见的卡座老化松动、TF 触点氧化、TF 卡遗失、抗震性能减退等等。综上所述,虽然 SD NAND 与 TF 卡使用的协议相同,但从外观到内在都有区别。正在使用 TF 卡的客户需要提升产品稳定性及耐用性时,SD NAND 是绝佳选择。
尽管 SD NAND 和 TF 卡之间有着这么大的区别,但具体到实际应用,其对外接口和驱动程序都是一样了,这说明可移植性非常好。
① 物理结构
SD NAND 从物理结构看包括 5 个部分,分别为存储单元、存储单元接口、电源检测、卡及接口控制器和对外接口,具体见下图。
存储单元是存储数据部件,存储单元通过存储单元接口与卡控制单元进行数据传输
存储单元接口是接口控制器与存储单元的数据交互通道
电源检测单元保证 SD NAND 工作在合适的电压下,如出现掉电或上电状态时,它会使控制单元和存储单元接口复位
卡及接口控制单元控制 SDNAND 的运行状态,它包括 8 个寄存器
对外接口单元控制 SD NAND 引脚的输入输出,一般包含 SDIO 接口和 SPI 接口
② 对外接口
SD NAND 共有 9 个引脚,其中包括 3 根电源线、1 根时钟线、1 根命令线和 4 根数据线。如下:
CLK:同步时钟线,由主机产生,即由主控制器(FPGA)输出; 使用 SPI 模式 时,该引脚与 SPI 总线的 SCK 时钟信号相连
CMD:命令控制线, SDIO 主机通过该线发送命令控制 SD NAND,如果命令要求 SD NAND 提供应答 (响应), SD NAND 也是通过该线传输应答信息; 使用 SPI 模式时,该引脚与 SPI 总线的 MOSI 信号相连, SPI 主机通过它向 SD NAND 发送命令及数据,但因为 SPI 总线 的 MOSI 仅用于主机向从机输出信号,所以 SD NAND 返回应答信息时不使用该信号线;
DAT0-3:在 SDIO 模式下,它们均为数据线,传输读写数据, SD NAND 可将 D0 拉低表 示忙状态; 在 SPI 模式下, DAT0 与 SPI 总线的 MISO 信号相连, SD NAND 通过该信号线向主机发送数据或响应, DAT3 与总线的 CS 信号相连, SPI 主机通过该信号线选择要通讯的 SD NAND。
VDD、VSS1、VSS2:电源和地信号。
③ 工作模式
SD NAND 有两种工作模式:SDIO 模式与 SPI 模式
在 SDIO 模式下,SD NAND 共使用到 CLK、CMD、DAT[3:0] 6 根信号线;SDIO 总线与多个 SD NAND 连接时,可以共用 CLK 时钟信号线,对于 CMD、DAT[3:0] 信号线,每个 SD NAND 都要独立连接。SDIO 总线与 SD 卡连接方式,具体见下图。此模式使用 IO 引脚多,但传输速度高。
在 SPI 模式下,SD NAND 共使用到 CS(DAT[3])、CLK、MISO(DAT[0])、MOSI(CMD) 4 根信号线;SPI 总线与多个 SD NAND 连接时,除 CS 片选信号线不可共用外,其他信号均可公用。SPI 总线与 SD NAND 连方式,具体见下图。此模式使用 IO 引脚少,但传输速度慢。
④ 内部寄存器
SD NAND 总共有 8 个寄存器,用于设定或表示 SD NAND 信息,寄存器描述具体见下图。 这些寄存器只能通过对应的命令访问,对 SD NAND 的控制操作是通过命令来执行的, SD NAND 定义了 64 个命令(部分命令不支持 SPI 模式) ,每个命令都有特殊意义,可以实现某一特定功能, SD NAND 接收到命令后,根据命令要求对 SD NAND 内部寄存器进行修改,程序控制中只需要发送组合命令就可以实现 SD NAND 的控制以及读写操作。
内部寄存器就不展开讲了,我们用 FPGA 实现读写测试也不需要了解那么多寄存器。
5、SD NAND 的控制时序
① 命令与读写时序
SD NAND 的通信是基于命令和数据传输的。通讯由一个起始位 (“0”) 开始,由一个停止位 (“1”) 终止。SD NAND 通信一般是主机发送一个命令 (Command),从设备在接收到命令后作出响应(Response),如有需要会有数据(Data) 传输参与。SD NAND 的基本交互是命令与响应交互, 见下图:
SD NAND 数据是以块 (Block) 形式传输的,SDHC 规格数据块长度一般为 512 字节,数据可以从主机到芯片,也可以是从芯片到主机。数据块需要 CRC 位来保证数据传输成功,CRC 位由 SD NAND 系统硬件生成。单个数据块的读、写时序分别见下 2 图:
读写操作都是由主机发起的,主机发送不同的命令表示读或写, SD NAND 接收到命令后先针对命令返回响应。在读操作中, SD NAND 返回一个数据块,数据块中包含 CRC 校验码;在写操作中,主机接收到命令响应后需要先发送一个标志(TOKEN)然后紧跟一个要写入的数据块,SD NAND 接收完数据块后会返回一个数据响应及忙碌标志,当 SD NAND 把接收到的数据写入到内部存储单元完成后,会停止发送忙碌标志,主机确认 SD NAND 空闲后,才可以发送下一个命令。
SD NAND 数据传输支持单块和多块读写,它们分别对应不同的操作命令, 结束多块读写时需要使用命令来停止操作。
② 命令格式
SD NAND 命令由主机发出,命令格式固定为 48bit,通过 CMD 信号线连续传输。SD NAND 命令格式,具体见下图:
起始位和终止位:命令的主体包含在起始位与终止位之间,它们都只包含一个数据位,起始位为 0,终止位为 1。
传输标志:用于区分传输方向,该位为 1 时表示命令,方向为主机传输到 SD NAND,该位为 0 时表示响应,方向为 SD NAND 传输到主机。命令主体内容包括命令、地址信息 / 参数和 CRC 校验三个部分。
命令号:它固定占用 6bit,所以总共有 64 个命令,每个命令都有特定的用途,部分命令不适用于 SPI 总线,或不适用于 SD NAND 操作,只是专门用于 MMC 卡或者 SD I/O 卡。
地址 / 参数:每个命令有 32bit 地址信息 / 参数用于命令附加内容,例如,广播命令没有地址信息,这 32bit 用于指定参数,而寻址命令这 32bit 用于指定目标 SD NAND 的地址, 当使用 SDIO 驱动多个 SD NAND 时,通过地址信息区分控制不同的 SD NAND,使用 SPI 总线驱动时,通过片选引脚来选择不同的 SD NAND,所以使用这些命令时地址可填充任意值。
CRC7 校验:长度为 7bit 的校验位用于验证命令传输内容正确性,如果发生外部干扰 导致传输数据个别位状态改变将导致校准失败,也意味着命令传输失败, SD NAND 不执行命令。 使用 SDIO 驱动时,命令中必须包含正确的 CRC7 校验值;而使用 SPI 驱动时,命令中的 CRC7 校验默认是关闭的,即这 CRC7 校验位中可以写入任意值而不影响通讯,仅在发送 CMD0 命令时需要强制带标准的 CRC7 校验。
③ 命令内容
SD NAND 命令可分为标准命令 (如 CMD0) 和特殊应用命令 (如 ACMD41),其中特殊应用命令只有在先写入 CMD55 命令后才能被识别。按照指令类型又可将 SD NAND 命令分为基本命令、数据块写命令、数据块读命令、擦除命令等 12 种 (class0 ~ class11)。
本次实验将会使用 SPI 模式实现 SD NAND 的数据读写操作,所以接下来只列举 SPI 模式下常用的 SD 卡命令,具体见下表:
SPI 模式下,上述各命令中,命令 CMD0 的 CRC7 校验为固定的 1001_010;命令 CMD8 的 CRC7 校验为固定的 1000_011;其他命令的 CRC7 校验在 SPI 模式下无作用,赋值为 1111_111 即可。
④ 响应格式
当 SD NAND 接收到命令时,会向 SD NAND 回传命令响应。SD NAND 有 5 种类型的命令响应:R1、R1b、R2、R3、R7;SDIO NAND 还支持另外两种命令响应:R4、R5。下文只对部分响应做介绍。
R1 响应格式,具体见下图:
in idle state:当该位为 1 时,表示 SD NAND 处于空闲状态
erase reset:因为接收到无需擦除操作的命令,擦除操作被复位
illegal command:接收到一个无效的命令代码
com crc error:接收到的上一个命令的 CRC 校验错误
erase sequence error:擦除命令的控制顺序错误
address error:读写的数据地址不对齐(数据地址需要按块大小对齐)
parameter error:命令的参数错误
R3 响应格式,具体见下图:
R3 响应包括 5 个字节,首先返回的第 1 个字节内容为 R1,剩下的其余字节为 OCR( Operation Conditions Register, 操作条件寄存器)寄存器的内容。
R7 响应格式,具体见下图:
R7 响应包括 5 个字节,首先返回的第 1 个字节内容为 R1,R7 [31:28] 位为命令版本,R7[27:12] 为保留位,R7[11:8] 为反馈的电压范围,最后 1 个字节为检查模式。
6、FPGA 实现 SD NAND 读写
接下来编写 FPGA 的 Verilog 代码实现向 SD NAND 的指定扇区中写入 512 个字节的数据,写完后将数据读出,并通过指示灯的方式验证数据是否被正确读写。需要说明的是,后文的读写操作均采用 SPI 模式。
6.1、设计思路
① 上电时序
SD NAND 同其他的许多芯片一样上电后需要保持一定的时间以便维持电压稳定,这个时间通常是 74 + 个时钟周期,一般实际应用中可设置参数为 74~100。只有经过这个过渡时间后,才可以执行后续的 SD NAND 初始化操作。
② 初始化时序
SD NAND 在正常读写操作之前,必须先对 SD NAND 进行初始化,使其工作在预期的工作模式。初始化流程如下:
1.SD NAND 完成上电后,主机 FPGA 先对从机 SD NAND 发送至少 74 个以上的同步时钟,在上电同步期间,片选 CS 引脚和 MOSI 引脚必须为高电平(MOSI 引脚除发送命令或数据外,其余时刻都为高电平);
- 拉低片选 CS 引脚,发送命令 CMD0(0x40)复位 SD NAND,命令发送完成后等待 SD NAND 返回响应数据;
3.SD NAND 返回响应数据后,先等待 8 个时钟周期再拉高片选 CS 信号,此时判断返回的响应数据。如果返回的数据为复位完成信号 0x01,在接收返回信息期间片选 CS 为低电平, 此时 SD NAND 进入 SPI 模式,并开始进行下一步,如果返回的值为其它值,则重新执行第 2 步;
- 拉低片选 CS 引脚,发送命令 CMD8(0x48)查询 SD NAND 的版本号,只有 SD2.0 版本才支持此命令,命令发送完成后等待 SD NAND 返回响应数据;
5.SD NAND 返回响应数据后,先等待 8 个时钟周期再拉高片选 CS 信号,此时判断返回的响应数据。如果返回的电压范围为 4’b0001 即 2.7V~3.6V,说明 2.0 版本,进行下一步,否则重新执行第 4 步;
- 拉低片选 CS 引脚,发送命令 CMD55(0x77)告诉 SD NAND 下一次发送的命令是应用相关命令,命令发送完成后等待 SD NAND 返回响应数据;
7.SD NAND 返回响应数据后,先等待 8 个时钟周期再拉高片选 CS 信号,此时判断返回的响应数据。如果返回的数据为空闲信号 0x01,开始进行下一步,否则重新执行第 6 步。
- 拉低片选 CS 引脚,发送命令 ACMD41(0x69)查询 SD NAND 是否初始化完成,命令发送完成后等待 SD NAND 返回响应数据;
9.SD NAND 返回响应数据后,先等待 8 个时钟周期再拉高片选 CS 信号,此时判断返回的响应数据。如果返回的数据为 0x00,此时初始化完成,否则重新执行第 6 步。
③ 写操作时序
至此,SD NAND 完成了复位以及初始化操作,进入到 SPI 模式的读写操作。SD NAND 读写一次的数据量必须为 512 字节的整数倍,即对 SD NAND 读写操作的最少数据量为 512 个字节。我们可以通过命令 CMD16 来配置单次读写操作的数据长度,以使每次读写的数据量为 (n*512)个字节(n≥1),本次 SD NAND 的读写操作使用默认配置,即单次读写操作的数据量为 512 个字节。
SD NAND 的写操作时序图如下图所示:
拉低片选信号 CS_N,向 SD NAND 写入命令 CMD24,命令号为 0x58,携带参数为 4 字节的 SD NAND 写扇区地址,CRC 校验字节未使用直接写入 0xFF,命令发送完成后 等待 SD NAND 返回响应数据
若 SD NAND 返回正确响应数据 R1 为 0x00,等待 8 个时钟周期,向 SD NAND 写入令牌 0xFE,紧随其后写入 512 个字节的数据
数据发送完成后,再向 SD NAND 写入 2 个字节的 CRC 校验字节。SPI 模式下不对数据进行 CRC 校验,直接写入两个字节的 0xFF
校验数据发送完成后, SD NAND 会有响应数据返回,随后 SD NAND 将 Miso 信号拉低进入写忙状态
MISO 信号再次拉高后 SD NAND 退出写忙状态,等待 8 个时钟周期后拉高片选信号,SD NAND 数据写操作完成,可以执行其它操作
④ 读操作时序
SD NAND 的读操作时序图如下图所示:
-
拉低片选信号 CS_N, 向 SD NAND 写入命令 CMD17,命令号为 0x51,携带参数为 4 字节的 SD NAND 读扇区地址,CRC 校验字节未使用直接写入 0xFF,命令发送完成后 等待 SD NAND 返回响应数据
-
若 SD NAND 返回正确响应数据 R1 为 0x00,以 SD NAND 返回的数据头 0xFE 为标志,接收自 SD NAND 读出的 512 字节数据和 2 字节的 CRC 校验字节
-
解析到数据头 0xFE 后,接下来接收 SD NAND 返回的 512 个字节的数据
-
数据解析完成后,接下来接收 2 个字节的 CRC 校验值。 由于 SPI 模式下不对数据进行 CRC 校验,可直接忽略这两个字节
5.CRC 校验字节接收完毕,等待 8 个时钟周期,拉高片选信号 CS_N,一次数据读操作完成
⑤ 程序设计
通过前面介绍的 SD NAND 初始化、写操作以及读操作可知,SD NAND 的这 3 个操作是相互独立且不能同时进行的,因此我们可以将 SD NAND 的初始化、写操作以及读操作分别划分为 3 个独立的模块,最后将这三个模块例化在 SD NAND 的控制器模块中,便于在其它工程项目中使用。
下图是系统框图,PLL 时钟模块(PLL)为各个模块提供驱动时钟,SD NAND 测试数据产生模块产生测试数据写入 SD NAND,写完后从 SD NAND 中读出数据,最终读写测试结果由 LED 显示模块通过控制 LED 灯的显示状态来指示。
顶层模块:顶层模块完成了对其它四个模块的例化,SD NAND 测试数据产生模块产生的开始写入信号及数据连接至 SD NAND 控制器模块,数据写完后从 SD NAND 控制器中读出数据, 并验证数据的正确性,将验证的结果连接至 LED 显示模块。
PLL 时钟模块:PLL 时钟模块通过调用锁相环(PLL)IP 核来实现,总共输出 2 个时钟,频率都是 50Mhz,但两个时钟相位相差 180 度。我们知道,SD 卡的 SPI 通信模式为 CPOL=1, CPHA=1;即 SPI_CLK 在空闲时为高电平,数据发送是在时钟的第一个边沿,也就是 SPI_CLK 由高 电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。为了在程序代码中统 一使用上升沿,我们使用两个相位相差 180 度的时钟来对 SD NAND 进行操作。
SD NAND 测试数据产生模块:SD NAND 测试数据产生模块产生的开始写入信号和数据写入 SD NAND 控制器模块中,数据写完后从 SD NAND 控制器中读出数据,并验证数据的正确性,将验证的结果发送给 LED 显示模块。
SD NAND 控制器模块:SD NAND 控制器模块例化了 SD NAND 初始化模块、 SD NAND 写数据模块和 SD NAND 读数据模块。SD NAND 初始化模块完成对 SD NAND 的上电初始化操作;SD NAND 写数据模块完成对 SD NAND 的写操作;SD NAND 读数据模块完成对 SD NAND 的读操作。 由于这三个模块都操作了 SD NAND 的引脚信号,且这三个模块在同一时间内不会同时操作,所以此模块实现了对其它三个模块的例化以及选择 SD NAND 的引脚连接至其中某一个模块。
LED 显示模块:LED 显示模块将 SD NAND 测试数据产生模块输出的验证结果值, 通过控制 LED 灯的显示状态来指示。
SD NAND 控制器部分代码如下:
module sd_ctrl_top(
input clk_ref , // 时钟信号
input clk_ref_180deg, // 时钟信号, 与 clk_ref 相位相差 180 度
input rst_n , // 复位信号, 低电平有效
//SD 卡接口
input sd_miso , //SD 卡 SPI 串行输入数据信号
output sd_clk , //SD 卡 SPI 时钟信号
output reg sd_cs , //SD 卡 SPI 片选信号
output reg sd_mosi , //SD 卡 SPI 串行输出数据信号
// 用户写 SD 卡接口
input wr_start_en , // 开始写 SD 卡数据信号
input [31:0] wr_sec_addr , // 写数据扇区地址
input [15:0] wr_data , // 写数据
output wr_busy , // 写数据忙信号
output wr_req , // 写数据请求信号
// 用户读 SD 卡接口
input rd_start_en , // 开始读 SD 卡数据信号
input [31:0] rd_sec_addr , // 读数据扇区地址
output rd_busy , // 读数据忙信号
output rd_val_en , // 读数据有效信号
output [15:0] rd_val_data , // 读数据
output sd_init_done //SD 卡初始化完成信号
);
//wire define
wire init_sd_clk ; // 初始化 SD 卡时的低速时钟
wire init_sd_cs ; // 初始化模块 SD 片选信号
wire init_sd_mosi ; // 初始化模块 SD 数据输出信号
wire wr_sd_cs ; // 写数据模块 SD 片选信号
wire wr_sd_mosi ; // 写数据模块 SD 数据输出信号
wire rd_sd_cs ; // 读数据模块 SD 片选信号
wire rd_sd_mosi ; // 读数据模块 SD 数据输出信号
//*********************
//** main code
//*********************
//SD 卡的 SPI_CLK
assign sd_clk = (sd_init_done==1’b0) ? init_sd_clk : clk_ref_180deg;
//SD 卡接口信号选择
always @(*) begin
//SD 卡初始化完成之前, 端口信号和初始化模块信号相连
if(sd_init_done == 1’b0) begin
sd_cs = init_sd_cs;
sd_mosi = init_sd_mosi;
end
else if(wr_busy) begin
sd_cs = wr_sd_cs;
sd_mosi = wr_sd_mosi;
end
else if(rd_busy) begin
sd_cs = rd_sd_cs;
sd_mosi = rd_sd_mosi;
end
else begin
sd_cs = 1’b1;
sd_mosi = 1’b1;
end
end
//SD 卡初始化
sd_init u_sd_init(
.clk_ref (clk_ref),
.rst_n (rst_n),
.sd_miso (sd_miso),
.sd_clk (init_sd_clk),
.sd_cs (init_sd_cs),
.sd_mosi (init_sd_mosi),
.sd_init_done (sd_init_done)
);
//SD 卡写数据
sd_write u_sd_write(
.clk_ref (clk_ref),
.clk_ref_180deg (clk_ref_180deg),
.rst_n (rst_n),
.sd_miso (sd_miso),
.sd_cs (wr_sd_cs),
.sd_mosi (wr_sd_mosi),
//SD 卡初始化完成之后响应写操作
.wr_start_en (wr_start_en & sd_init_done),
.wr_sec_addr (wr_sec_addr),
.wr_data (wr_data),
.wr_busy (wr_busy),
.wr_req (wr_req)
);
//SD 卡读数据
sd_read u_sd_read(
.clk_ref (clk_ref),
.clk_ref_180deg (clk_ref_180deg),
.rst_n (rst_n),
.sd_miso (sd_miso),
.sd_cs (rd_sd_cs),
.sd_mosi (rd_sd_mosi),
//SD 卡初始化完成之后响应读操作
.rd_start_en (rd_start_en & sd_init_done),
.rd_sec_addr (rd_sec_addr),
.rd_busy (rd_busy),
.rd_val_en (rd_val_en),
.rd_val_data (rd_val_data)
);
endmodule
SD NAND 控制器模块输出的 sd_init_done(SD NAND 初始化完成信号)连接至 SD NAND 测试数据产生模块,只有在 SD NAND 初始化完成之后(sd_init_done 为高电平),才能对 SD NAND 进行读写测试。SD NAND 控制器模块将 SD NAND 的初始化以及读写操作封装成方便用户调用的接口,SD NAND 测试数据产生模块只需对 SD NAND 控制器模块的用户接口进行操作即可完成对 SD NAND 的读写操作。
6.2、仿真结果
一般的测试中,我们都需要先进行仿真来观察时序等测试行为。此次实验由于找不到好的 SD NAND 的 Verilog 模型,所以仿真测试略。
6.3、实验结果
上文已经说了常用的相机中的 TF 卡与工业级的 SD NAND(贴片式 T 卡)的区别,所以本次实验我选用的是深圳雷龙公司的一款 SD NAND 产品 ----CSNP32GCR01-AOW。
这是一家专业做存储产品的公司,NAND Flash 是其主要产品。 该公司专注 NAND Flash 设计研发 13 年,在这一块可以说是相当专业。如果你对 NAND Flash 仍有疑惑的问题,或者你想在你的设计中使用 NAND Flash 产品,都可以直接联系:深圳市雷龙发展有限公司
实验结果其实没什么好看的,LED 灯常量表明说明从 SD NAND 读出的 512 个字节(256 个 16 位数据) 与写入的数据相同,SD NAND 读写测试程序下载验证成功。
PS:有个小细节可以说下,雷龙公司的 SD NAND 开发板还是蛮用心的,封装都是标准的 Micro SD 的封装,只要你的 FPGA 开发板上有 SD 卡座,就可以直接插上使用了,即插即用十分方便,有心了。
亲爱的卡友们,欢迎光临雷龙官网,如果看完文章之后还是有疑惑或不懂的地方,请联系我们,自己去理解或猜答案是件很累的事,请把最麻烦的事情交给我们来处理,术业有专攻,闻道有先后,深圳市雷龙发展专注存储行业 13 年,专业提供小容量存储解决方案。