基于FPGA的SD NAND读写测试(图文并茂+源代码+详细注释)

        本实验所使用的源代码已同步至个人主页的资源处,可供读者自行学习......

什么是SD NAND?

1.SD NAND 卡介绍

        SD NAND 卡是一种基于 NAND 闪存技术的存储设备,其外观和接口类似于标准的 SD 卡。它将 NAND 闪存芯片和必要的控制电路集成在一个小型的封装内,以 SD 卡的形式提供数据存储功能。

2.SD NAND 卡与其他SD卡的对比

119c024e608146fcbf06ef8c0297cdb6.png

        与原始的 NAND(闪存)相比,该产品有许多优势,它有具有以下功能

        嵌入式坏块管理功能:这意味着它可以自己检测和标记坏块,在数据存储和读取过程中自动避开这些坏块。例如,当写入数据时,产品会先检查目标块是否为坏块,如果是,就会选择其他正常的块来存储数据,从而提高了数据存储的可靠性和效率。

        更强的嵌入式纠错码(ECC)功能:ECC 是一种用于检测和纠正数据传输或存储过程中错误的技术。在 NAND 闪存中,数据可能会因为各种因素(如电气干扰、闪存单元老化等)而出现错误。原始的 NAND 闪存可能只有基本的 ECC 功能或者需要依赖外部的 ECC 机制。该产品具有更强的嵌入式 ECC 功能,能够更有效地检测和纠正更多的数据错误。例如,它可以纠正多位数据错误,确保从闪存中读取的数据的准确性,降低数据出错导致系统故障或数据丢失的风险。

        即使是异常断电,它仍然能保持你的数据安全。

3.SD NAND卡的物理结构如下:

        SD 卡主要由以下几个部分组成,存储单元作为存储数据的核心部件,通过存储单元接口与卡控制单元实现数据传输。电源检测单元能够确保 SD 卡工作在适宜的电压范围内,一旦出现掉电或上电的情况,它会促使控制单元和存储单元接口进行复位操作。卡及接口控制单元负责掌控 SD 卡的运行状态,其中包含6个寄存器。接口驱动器则对 SD 卡引脚的输入输出进行控制。

c07887a1ca0940328a08c2b8bb1e6a00.png

 4.引脚分配图如下:

a5555337f0d44857b8709bface8d88d8.png

        SD NAND卡的读写控制主要有两种模式: SD模式和SPI模式

        在SD模式下:SD 卡共使用到 SCLK、CMD、SDD[3:0]六根 信号线;SDIO 总线与多张 SD 卡连接时,可以共用 SCLK 时钟信号线,对于 CMD、SDD[3:0]信号线,每张 SD 卡都要独立连接.

        在 SPI 模式下,SD 卡共使用到 CS、SCLK、DI(MISO)、DO(MOSI)四 根信号线;SPI 总线与多张 SD 卡连接时,除 CS 片选信号线不可共用外,其他信号均可共用。

6719b1c3440c4b83b2dc668fe6ca53aa.png

5.SD卡的寄存器

bb2f9534e3bc442ead23fa357109135a.png

                              对于SD卡寄存器的详细介绍,读者可参考以下文章                                     《Part1_Physical_Layer_Simplified_Specification_Ver7.10》  

6.SD NAND卡的读写控制时序

       以下所有内容皆是基于SPI模式下,读者注意区分!

       1.命令与响应时序

        SD NAND卡传输过程中有SCLK和DATA。下图的DATAIN指的是DI,DATAOUT指的是DO。当主机发送指令时,SD NAND卡接收到命令后,产生响应给主机。

e073b7624af34fc9972ea25c11960583.png

        主机发送的命令可以让SD NAND卡中的数据读出,并且通过CRC校验数据的正确性(注意CRC是由SD NAND卡硬件设备生成的),此时只对某一块(block)读数据。

a47ecc477ea04eaea17d21f9ac067f83.png

        主机发送的命令除了可以让数据读出,还可以让数据写入,而且每次的读/写都是按块进行的,即每次读写一般为512 字节。8aef4c34165c4980a7ac1759332e57b6.png

        2.SD NAND卡的读写命令

        发送的命令格式为:48bit,通过CMD命令线发送。

50f534dba9b24d4b969f23132428c4e9.png

        每一个命令都有一个起始位("0")和停止位("1")

        传输标志:用于区分传输方向,主机传输到 SD 卡时为1;SD 卡传输到主机时为0;

        命令号:它固定占用 6bit,总共有2^6=64条命令

        地址/参数:这 32bit 用于指定目标 SD 卡的地址

        CRC7 校验:长度为 7bit 的校验位用于验证命令传输内容正确性

        3.SPI模式下常用的命令信息

4504752eb3bb493a9ee3d3256a1e20c0.png

d401f3b142dd41c2b0394164c232f4e7.png

        4.响应命令类型

        可参阅《Part1_Physical_Layer_Simplified_Specification_Ver6.00》一文。

实验目标

       PC 机使用串口助手通过串口 RS232 协议向 SD  NAND卡(基于SPI模式)指定扇区写入 512 字节数据,随后读出写入数据回传到 PC 机,验证数据正确性。 

硬件资源 

        SD NAND卡的型号为深圳市雷龙发展有限公司的CSNP64GCR01-BOW,容量为64Gb

87c4ffd9c23442eca417cd79d584ba23.png

将SD NAND 芯片焊接至测试板,测试板可直接 插入TF卡座或读卡器进行测试及调试,预留 的第二组焊盘可用于飞线。

76b71ad8ae34480ca2307f9d1a4b351d.png

        读写测试时直接将芯片焊接到测试板后,将测试板插到TF卡座部分,即可读写测试。

e92e242b55074600a0beadae97856450.png

952f8eac6e4045c4bb1bd21260e444dd.jpeg

模块设计

        这里主要介绍一下SD NAND卡的读写控制模块:

        首先上电后,需要对SD NAND 卡进行初始化,初始化模块输出一个初始化完成信号,用于指示SD NAND卡的读和写模块的进行。

856611843fca4a998b9c9c194cfc8576.png

代码实现

module  data_rw_ctrl
(input   wire            sys_clk     ,   //输入工作时钟,频率50MHzinput   wire            sys_rst_n   ,   //输入复位信号,低电平有效input   wire            init_end    ,   //SD卡初始化完成信号input   wire            rx_flag     ,   //写fifo写入数据标志信号input   wire    [7:0]   rx_data     ,   //写fifo写入数据input   wire            wr_req      ,   //sd卡数据写请求input   wire            wr_busy     ,   //sd卡写数据忙信号output  wire            wr_en       ,   //sd卡数据写使能信号output  wire    [31:0]  wr_addr     ,   //sd卡写数据扇区地址output  wire    [15:0]  wr_data     ,   //sd卡写数据input   wire            rd_data_en  ,   //sd卡读出数据标志信号input   wire    [15:0]  rd_data     ,   //sd卡读出数据input   wire            rd_busy     ,   //sd卡读数据忙信号output  reg             rd_en       ,   //sd卡数据读使能信号output  wire    [31:0]  rd_addr     ,   //sd卡读数据扇区地址output  reg             tx_flag     ,   //读fifo读出数据标志信号output  wire    [7:0]   tx_data         //读fifo读出数据
);//parameter define
parameter   DATA_NUM    =   12'd256     ;   //读写数据个数
parameter   SECTOR_ADDR =   32'd1000    ;   //读写数据扇区地址
parameter   CNT_WAIT_MAX=   16'd60000   ;   //读fifo输出数据时间间隔计数最大值//wire  define
wire    [11:0]  wr_fifo_data_num    ;   //写fifo内数据个数
wire            wr_busy_fall        ;   //sd卡写数据忙信号下降沿
wire            rd_busy_fall        ;   //sd卡读数据忙信号下降沿
//wire            rd_fifo_rd_en       ;   //读fifo读使能信号//reg   define
reg             wr_busy_dly         ;   //sd卡写数据忙信号打一拍
reg             rd_busy_dly         ;   //sd卡读数据忙信号打一拍
reg             send_data_en        ;   //串口发送数据使能信号
reg     [15:0]  cnt_wait            ;   //读fifo输出数据时间间隔计数
reg     [11:0]  send_data_num       ;   //串口发送数据字节数计数
reg             rd_fifo_rd_en       ;//wr_en:sd卡数据写使能信号
assign  wr_en = ((wr_fifo_data_num == (DATA_NUM)) && (init_end == 1'b1))? 1'b1 : 1'b0;//wr_addr:sd卡写数据扇区地址
assign  wr_addr = SECTOR_ADDR;//wr_busy_dly:sd卡写数据忙信号打一拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_busy_dly <=  1'b0;elsewr_busy_dly <=  wr_busy;//wr_busy_fall:sd卡写数据忙信号下降沿
assign  wr_busy_fall = ((wr_busy == 1'b0) && (wr_busy_dly == 1'b1))? 1'b1 : 1'b0;//rd_en:sd卡数据读使能信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_en   <=  1'b0;else    if(wr_busy_fall == 1'b1)rd_en   <=  1'b1;elserd_en   <=  1'b0;//rd_addr:sd卡读数据扇区地址
assign  rd_addr = SECTOR_ADDR;//rd_busy_dly:sd卡读数据忙信号打一拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_busy_dly <=  1'b0;elserd_busy_dly <=  rd_busy;//rd_busy_fall:sd卡读数据忙信号下降沿
assign  rd_busy_fall = ((rd_busy == 1'b0) && (rd_busy_dly == 1'b1))? 1'b1 : 1'b0;//send_data_en:串口发送数据使能信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)send_data_en    <=  1'b0;else    if((send_data_num == (DATA_NUM * 2) - 1'b1)&& (cnt_wait == CNT_WAIT_MAX - 1'b1))send_data_en    <=  1'b0;else    if(rd_busy_fall == 1'b1)send_data_en    <=  1'b1;elsesend_data_en    <=  send_data_en;//cnt_wait:读fifo输出数据时间间隔计数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_wait    <=  16'd0;else    if(send_data_en == 1'b1)if(cnt_wait == CNT_WAIT_MAX)cnt_wait    <=  16'd0;elsecnt_wait    <=  cnt_wait + 1'b1;elsecnt_wait    <=  16'd0;//send_data_num:串口发送数据字节数计数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)send_data_num   <=  12'd0;else    if(send_data_en == 1'b1)if(cnt_wait == CNT_WAIT_MAX)send_data_num   <=  send_data_num + 1'b1;elsesend_data_num   <=  send_data_num;elsesend_data_num   <=  12'd0;//rd_fifo_rd_en:读fifo读使能信号
//assign  rd_fifo_rd_en = (cnt_wait == CNT_WAIT_MAX) ? 1'b1 : 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_fifo_rd_en   <=  1'b0;else    if(cnt_wait == (CNT_WAIT_MAX - 1'b1))rd_fifo_rd_en   <=  1'b1;elserd_fifo_rd_en   <=  1'b0;//tx_flag:读fifo读出数据标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)tx_flag <=  1'b0;elsetx_flag <=  rd_fifo_rd_en;fifo_wr_data   fifo_wr_data_inst
(.wrclk      (sys_clk            ),  //数据写时钟.wrreq      (rx_flag            ),  //数据写使能.data       (rx_data            ),  //写入数据.rdclk      (sys_clk            ),  //数据读时钟.rdreq      (wr_req             ),  //数据读使能.q          (wr_data            ),  //读出数据.rdusedw    (wr_fifo_data_num   )   //fifo内剩余数据个数
);fifo_rd_data    fifo_rd_data_inst
(.wrclk      (sys_clk        ),  //数据写时钟.wrreq      (rd_data_en     ),  //数据写使能.data       (rd_data        ),  //写入数据.rdclk      (sys_clk        ),  //数据读时钟.rdreq      (rd_fifo_rd_en  ),  //数据读使能.q          (tx_data        )   //读出数据
);endmodule

        代码部分篇幅过长,详细源代码可参考本人主页资源部分自行学习

实验结果

        PC机通过串口调试助手往SD NAND卡写入数据后,FPGA再将SD NAND卡中的数据读出通过UART发送模块发送给PC机后,可以发现写入和读出的数据位数都是512byte,而且输入数据和读出数据完全正确。

8e692de7e4c0486e8a53665fa6fd4800.png

小结

        这里感谢深圳市雷龙发展有限公司对本实验的支持。该公司专注于NAND Flash设计研发13年。创始人均为步步高/华为技术背景出身。是一家存储元器件代理分销商。 主营:CS创世 SD NAND(又叫贴片式 TF卡/贴片式SD卡)读写速度可达24/13 MB/S,韩国ATO Solution(SLC NAND、SPI NAND、MCP)eMMC、小容量TF卡存储芯片。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习6-梯度下降法

梯度下降法 目的 梯度下降法(Gradient Descent)是一个算法&#xff0c;但不是像多元线性回归那样是一个具体做回归任务的算法&#xff0c;而是一个非常通用的优化算法来帮助一些机器学习算法求解出最优解的&#xff0c;所谓的通用就是很多机器学习算法都是用它&#xff0c;甚…

(0基础保姆教程)-JavaEE开课啦!--11课程(初识Spring MVC + Vue2.0 + Mybatis)-实验9

一、什么是Spring MVC&#xff1f; Spring MVC 是一个基于 Java 的 Web 框架&#xff0c;遵循 MVC 设计模式&#xff0c;用于构建企业级应用程序。它通过控制器(Controller)处理用户请求&#xff0c;模型(Model)处理业务逻辑&#xff0c;视图(View)展示数据&#xff0c;实现了请…

微前端-MicroApp

微前端即是由一个主应用来集成多个微应用&#xff08;可以不区分技术栈进行集成&#xff09; 下面是使用微前端框架之一 MicroApp 对 react微应用 的详细流程 第一步 创建主应用my-mj-app 利用脚手架 npx create-react-app my-mj-app 快速创建 安装 npm install --save rea…

知识库助手的构建之路:ChatGLM3-6B和LangChain的深度应用

ChatGLM3-6B和LangChain构建知识库助手 安装依赖库 使用pip命令安装以下库&#xff1a; pip install modelscope langchain0.1.7 chromadb0.5.0 sentence-transformers2.7.0 unstructured0.13.7 markdown3.0.0 docx2txt0.8 pypdf4.2.0依赖库简介&#xff1a; ModelScope&a…

shell(2)永久环境变量和字符串显位

shell&#xff08;2&#xff09;永久环境变量和字符串显位 声明&#xff01; 学习视频来自B站up主 ​泷羽sec​​ 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习…

Java实现IP代理池

文章目录 Java实现IP代理池一、引言二、构建IP代理池1、代理IP的获取2、代理IP的验证1. 导入必要的库2. 设置代理IP和端口3. 发起HTTP请求4. 检查请求结果5. 完整的验证方法 注意事项 三、使用IP代理池四、总结 Java实现IP代理池 一、引言 在网络爬虫或者需要频繁请求网络资源…

微服务保护和分布式事务

文章目录 一、微服务保护1.1 微服务保护方案&#xff1a;1.1.1 请求限流&#xff1a;1.1.2 线程隔离&#xff1a;1.1.3 服务熔断&#xff1a; 1.2 Sentinel&#xff1a;1.2.1 介绍和安装&#xff1a;1.2.2 微服务整合&#xff1a; 1.3 请求限流&#xff1a;1.4 线程隔离&#x…

后端 Java发送邮件 JavaMail 模版 20241128测试可用

配置授权码 依赖 <dependency><groupId>javax.mail</groupId><artifactId>javax.mail-api</artifactId><version>1.5.5</version> </dependency> <dependency><groupId>com.sun.mail</groupId><artifa…

MySQL安装与卸载(linux)

MySQL安装与卸载 MySQL8.0.26-安装1. 准备一台Linux服务器2. 下载Linux版MySQL安装包3. 上传MySQL安装包4. 创建目录,并解压5. 安装mysql的安装包6. 启动MySQL服务7. 查询自动生成的root用户密码8. 修改root用户密码9. 创建用户10. 并给root用户分配权限11. 重新连接MySQL MySQ…

设置ip和代理DNS的WindowsBat脚本怎么写?

今天分享一个我们在工作时&#xff0c;常见的在Windows中通过批处理脚本&#xff08;.bat 文件&#xff09;来设置IP地址、代理以及DNS 相关配置的示例&#xff0c;大家可以根据实际需求进行修改调整。 一、设置静态IP地址脚本示例 以下脚本用于设置本地连接&#xff08;你可…

施工车辆,工程车类型识别,可识别装载机,搅拌车,挖掘机,拉土车等,支持YOLO,COCO,VOC三种格式带标记

1338总图像数 数据集分割 训练组 87&#xff05; 1170图片 有效集 8% 112图片 测试集 4% 56图片 预处理 自动定向&#xff1a; 已应用 调整大小&#xff1a; 拉伸至 640x640 增强 每个训练示例的输出&#xff1a; 3 旋转&#xff1a; -15 至 15 之间 …

新版布谷直播软件源码开发搭建功能更新明细

即将步入2025年也就是山东布谷科技专注直播系统开发,直播软件源码出售开发搭建等业务第9年,山东布谷科技不断更新直播软件功能&#xff0c;以适应当前新市场环境下的新要求。山东布谷科技始终秉承初心&#xff0c;做一款符合广大客户需求的直播系统软件。支持广大客户提交更多个…

科技赋能:企业如何通过新技术提升竞争力的策略与实践

引言 在当今瞬息万变的商业环境中&#xff0c;科技的迅猛发展正在重新定义行业的游戏规则。无论是小型企业还是跨国巨头&#xff0c;都感受到数字化转型的迫切需求。过去&#xff0c;企业竞争力更多依赖于成本控制、资源调配或市场覆盖&#xff0c;而如今&#xff0c;新技术的引…

项目自动化部署,持续集成/持续交付(CI/CD)工具有那些?他们的优劣势分别是什么?共计15个工具进行对比分析。

项目自动化部署&#xff0c;持续集成/持续交付&#xff08;CI/CD&#xff09;工具有那些&#xff1f;他们的优劣势分别是什么&#xff1f; 主要对比的工具有&#xff1a;Jenkins 、阿里云云效、华为云DevCloud、腾讯云CODING、百度智能云DevOps、 GitLab CI/CD、CircleCI、Trav…

Web登录页面设计

记录第一个前端界面&#xff0c;暑假期间写的&#xff0c;用了Lottie动画和canvas标签做动画&#xff0c;登录和注册也连接了数据库。 图片是从网上找的&#xff0c;如有侵权私信我删除&#xff0c;谢谢啦~

洛谷 P2385 [USACO07FEB] Bronze Lilypad Pond B C语言 bfs

题目&#xff1a; https://www.luogu.com.cn/problem/P2385 题目看仔细&#xff0c;是M行N列.八个方向数组依靠M1,M2&#xff0c;所以初始化方向数组要在主函数里面&#xff0c;传入bfs函数里。 #include <iostream> #include<algorithm> #include<queue>…

告别照相馆!使用AI证件照工具HivisionIDPhotos打造在线证件照制作软件

文章目录 前言1. 安装Docker2. 本地部署HivisionIDPhotos3. 简单使用介绍4. 公网远程访问制作照片4.1 内网穿透工具安装4.2 创建远程连接公网地址 5. 配置固定公网地址 前言 本文主要介绍如何在Linux系统使用Docker快速部署一个AI证件照工具HivisionIDPhotos&#xff0c;并结合…

C语言实例_14之求俩数的最大公约数和最小公倍数

1.最大公约数和最小公倍数概述 最大公约数&#xff08;Greatest Common Divisor&#xff0c;简称GCD&#xff09;&#xff1a; 也称为最大公因数&#xff0c;是指两个或多个整数共有约数中最大的一个。例如&#xff0c;对于整数12和18&#xff0c;它们的约数分别为&#xff1…

Mybatis:Mybatis快速入门

Mybatis的官方文档是真的非常好&#xff01;非常好&#xff01; 点一下我呗&#xff1a;Mybatis官方文档 MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可…

JAVA:Spring Boot 3 实现 Gzip 压缩优化的技术指南

1、简述 随着 Web 应用的用户量和数据量增加&#xff0c;网络带宽和页面加载速度逐渐成为瓶颈。为了减少数据传输量&#xff0c;提高用户体验&#xff0c;我们可以使用 Gzip 压缩 HTTP 响应。本文将介绍如何在 Spring Boot 3 中实现 Gzip 压缩优化。 2、配置 Spring Boot 3 对…