『FPGA通信接口』DDR(4)DDR3内存条SODIMMs读写测试

文章目录
- 前言
- 1.MIG IP核配置
- 2.测试程序
- 3.DDR应用
- 4.传送门
前言
不论是DDR3颗粒还是DDR3内存条,xilinx都是通过MIG IP核实现FPGA与DDR的读写。本文区别于DDR颗粒,记录几个与颗粒配置不同的地方。关于DDR的原理与MIG IP的简介,请查看前面文章,链接在文末。本文提供了配套的工程源码,链接在文末,本文用的内存条为MT16KTF1G64HZ-1G6,FPGA芯片为xc7k325tffg900 -2。请按照顺序循序渐进阅读本系列的文章。
1.MIG IP核配置
- 1.如无特殊说明,配置保持与前述文章MIG IP核配置一致。第五页如图所示配置。其中①指DDR3颗粒的物理时钟,例如一颗16bit位宽的DDR设置为400MHz,则它的传输速度为每一个800MHz(DDR双沿传输的原因)周期传输16bit。这里时钟的范围受到FPGA芯片速度等级和型号的制约,以及与内存条的支持速度也有关。如我用的内存条MT16KTF1G64HZ-1G6,速度范围在1500ps-3000ps之间。②指的是用户时钟,4:1的4指的是①设置的物理时钟。第③部分指的是类型选择,内存条选择SODIMMs。④处是DDR3内存条的型号,如果不在列表需要根据速度参数,位宽大小找一个兼容的型号。⑤处勾选上mask后,如果相应的管脚不连接,会造成DDR3初始化失败。其余配置保持默认即可。

- 2.第六页 此处①代表参考时钟,选择200MHz为固定大小。②处如果是内存条就选择RZQ/4,如果是颗粒就选择RZQ/6。

- 3.DDR3颗粒要勾选DCI Cascade,内存条不用勾选。后面就是选择引脚,其他的都保持默认,即可。

2.测试程序
如果需要修改这段程序,需要注意MIG的接口各信号的位宽应该保持一致,另外程序中设计了两个LED灯,读写测试正确的时候,指示灯led1常亮,反之则闪烁。LED2只是容量,当测试到所设置的容量的时候常量。代码中TEST_LENGTH指示的含义是突发次数,也可以说是容量。每一次突发是512bit数据,使用内存的容量除以512bit,即为最大的突发次数。当然使用的芯片的物理位宽不同,例如只有一片16bit位宽的DDR颗粒,那一次突发的数据为8*16bit=128bit,那最大的突发次数就要用量除以128bit了。
module dimm_top(input sys_clk_p,input sys_clk_n, inout [63:0] ddr3_dq , inout [7:0] ddr3_dqs_n , inout [7:0] ddr3_dqs_p , output [15:0] ddr3_addr , output [2:0] ddr3_ba , output ddr3_ras_n , output ddr3_cas_n , output ddr3_we_n , output ddr3_reset_n , output [1:0] ddr3_ck_p , output [1:0] ddr3_ck_n , output [1:0] ddr3_cke , output [1:0] ddr3_cs_n , output [7:0] ddr3_dm , output [1:0] ddr3_odt , output reg led1, output reg led2 ); wire clk_rst; wire clk_200;reg [29:0] app_addr_begin=0;wire app_en; //写命令使能wire [2:0] app_cmd; //用户读写命令wire app_wdf_wren; //DDR3写使能wire app_wdf_end; //突发写最后一个数标识wire [29:0] app_addr; //用户平面地址wire app_rdy; //设备接收准备就绪 wire app_wdf_rdy; //写响应wire [511:0] app_rd_data; //用户读数据wire app_rd_data_end; //突发读当前时钟最后一个数据wire app_rd_data_valid; //读数据有效wire [511:0] app_wdf_data; //用户写数据wire app_sr_active; //保留wire app_ref_ack; //刷新请求wire app_zq_ack; //ZQ 校准请求wire init_calib_complete; //校准完成信号wire ui_clk ; //用户时钟wire ui_clk_sync_rst; clk_wiz_0 u_clk_wiz_0(.clk_out1(clk_200), .reset(1'b0), .locked(clk_rst), .clk_in1_p(sys_clk_p),.clk_in1_n(sys_clk_n));mig_7series_0 mig_JC (// Memory interface ports.ddr3_addr (ddr3_addr), // output [15:0] .ddr3_ba (ddr3_ba), // output [2:0].ddr3_cas_n (ddr3_cas_n), // output .ddr3_ck_n (ddr3_ck_n), // output [1:0] .ddr3_ck_p (ddr3_ck_p), // output [1:0] .ddr3_cke (ddr3_cke), // output [1:0] .ddr3_ras_n (ddr3_ras_n), // output .ddr3_reset_n (ddr3_reset_n), // output .ddr3_we_n (ddr3_we_n), // output .ddr3_dq (ddr3_dq), // inout [63:0] .ddr3_dqs_n (ddr3_dqs_n), // inout [7:0] .ddr3_dqs_p (ddr3_dqs_p), // inout [7:0] .init_calib_complete (init_calib_complete), // output .ddr3_cs_n (ddr3_cs_n), // output [1:0] .ddr3_dm (ddr3_dm), // output [7:0] .ddr3_odt (ddr3_odt), // output [1:0] // Application interface ports.app_addr (app_addr), // input [29:0] .app_cmd (app_cmd), // input [2:0] .app_en (app_en), // input .app_wdf_data (app_wdf_data), // input [511:0] .app_wdf_end (app_wdf_end), // input .app_wdf_wren (app_wdf_wren), // input .app_rd_data (app_rd_data), // output [511:0] .app_rd_data_end (app_rd_data_end), // output .app_rd_data_valid (app_rd_data_valid), // output .app_rdy (app_rdy), // output .app_wdf_rdy (app_wdf_rdy), // output .app_sr_req (1'b0), // input .app_ref_req (1'b0), // input .app_zq_req (1'b0), // input .app_sr_active (app_sr_active), // output .app_ref_ack (app_ref_ack), // output .app_zq_ack (app_zq_ack), // output .ui_clk (ui_clk), // output用户时钟输出,其实是通过IP配置自己配出来的 .ui_clk_sync_rst (ui_clk_sync_rst), // output .app_wdf_mask (64'b0), // input [63:0] //写数据屏蔽.sys_clk_i (clk_200),//输入IP的时钟// Reference Clock Ports.clk_ref_i (clk_200),//参考时钟 .sys_rst (clk_rst) // input sys_rst);parameter TEST_LENGTH = 27'd134200000; //每一次突发是512bit 8GB可以支持134217728次突发 99.98%// parameter TEST_LENGTH = 32'd60000000;//**************1.先写后读状态机state machineparameter IDLE = 2'd0; parameter WRITE = 2'd1; parameter WAIT = 2'd2; parameter READ = 2'd3; reg [511:0]my_512_data;reg [26:0] wr_addr_cnt;reg [26:0] rd_addr_cnt;reg [1:0] state;always @(posedge ui_clk or negedge rst_n) beginif((~rst_n)||(error_flag)) begin state <= IDLE; my_512_data <= 512'd0; wr_addr_cnt <= 27'd0; rd_addr_cnt <= 27'd0; app_addr_begin<= 30'd0; endelse if(init_calib_complete)begin //MIG IP核初始化完成case(state)IDLE:beginstate <= WRITE;my_512_data <= 512'd0; wr_addr_cnt <= 27'd0; rd_addr_cnt <= 27'd0; app_addr_begin <= 30'd0; endWRITE:beginif((wr_addr_cnt == TEST_LENGTH-1) &&(app_rdy && app_wdf_rdy))state <= WAIT; //写到设定的长度跳到等待状态else if(app_rdy && app_wdf_rdy)begin //写条件满足my_512_data <= my_512_data + 1; //写数据自增wr_addr_cnt <= wr_addr_cnt + 1; //写计数自增app_addr_begin<= app_addr_begin + 8; //DDR3 地址自增end else begin //写条件不满足,保持当前状态my_512_data <= my_512_data; wr_addr_cnt <= wr_addr_cnt;app_addr_begin<= app_addr_begin; endendWAIT:begin state <= READ; //下一个时钟,跳到读状态rd_addr_cnt <= 27'd0; //读地址复位app_addr_begin<= 30'd0; //DDR3读从地址0endREAD:begin //读到设定的地址长度 if((rd_addr_cnt == TEST_LENGTH -1 ) && app_rdy)state <= IDLE; //则跳到空闲状态 else if(app_rdy)begin //若MIG已经准备就绪,则开始读rd_addr_cnt <= rd_addr_cnt + 1'd1; //用户地址每次加一app_addr_begin <= app_addr_begin + 8; //DDR3地址加8end else begin //若MIG没准备好,则保持原rd_addr_cnt <= rd_addr_cnt;app_addr_begin <= app_addr_begin; endenddefault:beginstate <= IDLE;my_512_data <= 512'd0;wr_addr_cnt <= 27'd0;rd_addr_cnt <= 27'd0;app_addr_begin <= 30'd0;endendcaseendend //**************2.根据状态机与MIG指示信号为app信号赋值assign app_en =((state == WRITE && (app_rdy && app_wdf_rdy))||(state == READ && app_rdy)) ? 1'b1:1'b0; assign app_cmd =(state == READ) ? 3'd1 :3'd0; assign app_wdf_wren=(state == WRITE && (app_rdy && app_wdf_rdy)) ? 1'b1:1'b0;assign app_wdf_end =app_wdf_wren; assign app_addr =app_addr_begin;assign app_wdf_data=my_512_data; //*******************3.用户判错逻辑reg [26:0] rd_cnt;wire rst_n; //复位,低有效reg error_flag;parameter L_TIME = 28'd200_000_000;reg [27:0] led_cnt; //led计数wire error; //读写错误标记assign rst_n = ~ui_clk_sync_rst;//&&myrstalways @(posedge ui_clk or negedge rst_n) beginif(~rst_n) rd_cnt <= 0; //若计数到读写长度,且读有效,地址计数器则�?0 else if(app_rd_data_valid&&(rd_cnt == TEST_LENGTH - 1))rd_cnt <= 0; //其他条件只要读有效,每个时钟自增1else if (app_rd_data_valid)rd_cnt <= rd_cnt + 1;end//判断错误,读出数据应为计数递增数据assign error = (app_rd_data_valid && (rd_cnt!=app_rd_data));always @(posedge ui_clk or negedge rst_n) beginif(~rst_n)led2<=0;else if(rd_cnt==32'd134200000-1)led2<=1;end always @(posedge ui_clk or negedge rst_n) beginif(~rst_n) error_flag <= 0;else if(error)error_flag <= 1;end//读写测试正确,指示灯led1常亮,反之则闪烁always @(posedge ui_clk or negedge rst_n) beginif((~rst_n) || (~init_calib_complete )) beginled_cnt <= 28'd0;led1 <= 1'b0;endelse beginif(~error_flag) //常亮代表正常,闪烁代表故障 led1 <= 1'b1; else begin led_cnt <= led_cnt + 28'd1;if(led_cnt == L_TIME - 1'b1) beginled_cnt <= 25'd0;led1 <= ~led1; end endendendendmodule
3.DDR应用
DDR在FPGA系统中的作用主要是作为存储器使用,用于存储数据和程序。DDR存储器通常被用作FPGA系统中的主存储器,用于存储采集数据和中间结果。DDR3作为高速缓存与FPGA相连,在不同领域均发挥着重要作用。在高性能计算领域,DDR用于存储大规模数据集、模型参数、数据计算结果,从而充分发挥FPGA并行计算的能力,完成计算任务;在图像处理领域,用于匹配图像采集接口与传输接口之间的速度,完成图像采集;在通信领域,DDR用于存储大量数据包,实现数据的缓存和处理,提高数据传输速度和处理效率。总之,DDR在不同领域扮演着重要角色。以采集摄像头数据为例,采用乒乓操作的思想是在DDR中开辟两块大小为1帧图像的缓冲区,如果读取速度大于写入速度的时候,需要采用乒乓操作的方式发挥DDR弹性缓冲的作用。往缓冲区写的时候,1号缓冲区写满之后,切换到2号缓冲区写,2号写满之后,在往1号去写,如此往复 。由于读取速度大于写入速度,因此,读一定是在与当前写不同的另一块缓冲区去读,在底层,可能会对同一块缓冲区的数据读取很多次,但是这并不影响人在视觉上对于画面流畅的影响。这就是通过乒乓操作实现了数据缓冲,匹配了读写两端的速度。如下图所示,

说明:1.每一个bank存储一帧图像数据,bank中每一行为图像的一行数据(即每一次读写的突发长度是一行像素数据,这个突发长度可以自己定义,并不必须要是一行数据),读和写彼此独立进行;2.bank之间的切换由状态机实现,由于读速度大于写速度,则每写完一个bank切换另一个bank去写;每读完一个bank,判断当前写bank,选择不同于写bank的bank进行读。3.由于读速度大于写速度,因此永远不会发生冲突,只是可能某一帧会被重复播放,但在视频应用中,这对用户的视觉不产生任何影响。同理,如果是读的速度小于写的速度,那让写操作刷新缓冲区即选择与读相排斥的缓冲区写,让读操作按照顺序读即可。 上面描述的只是一种乒乓缓冲的思想,实际操作中,可以通过设置三缓存,四缓存的方式让图像更为平滑。另外可以考虑基于这种思想为DDR写一个消息队列,让DDR仲裁控制器的通用性和适配性更强。
4.传送门
- 我的主页
- FPGA通信接口专栏汇总导航
- DDR测试工程源码
- 上一篇:DDR(3)DDR3颗粒读写测试
| END |
🔈文章原创,首发于CSDN论坛。
🔈欢迎点赞❤❤收藏⭐⭐打赏💴💴!
🔈欢迎评论区或私信指出错误❌,提出宝贵意见或疑问❓。
相关文章:
『FPGA通信接口』DDR(4)DDR3内存条SODIMMs读写测试
文章目录 前言1.MIG IP核配置2.测试程序3.DDR应用4.传送门 前言 不论是DDR3颗粒还是DDR3内存条,xilinx都是通过MIG IP核实现FPGA与DDR的读写。本文区别于DDR颗粒,记录几个与颗粒配置不同的地方。关于DDR的原理与MIG IP的简介,请查看前面文章&…...
Element UI 快速入门指南
Element UI 快速入门指南 Element UI 是一个基于 Vue.js 的组件库,提供了丰富的 UI 组件和工具,可以帮助开发人员快速构建现代化的 Web 应用程序。本文将介绍如何快速入门使用 Element UI,并展示一些常用的组件和功能。 安装 Element UI 使…...
CentOS常用命令有哪些?
目录 一、CentOS常用命令有哪些? 二、不熟悉命令怎么办? 场景一:如果是文件操作,可以使用FileZilla工具来完成 场景二:安装CentOS桌面 一、CentOS常用命令有哪些? CentOS 系统中有许多常用命令及其用法…...
cmd查看局域网内所有设备ip
说明:最近碰到一个新问题,就是有一个安卓设备,安装了一个app导致死机了,app设置了开机重启,所以,无论重启还是关机,都是进来就白屏, 这可把人愁坏了,直接死循环了 无论…...
5.3作业
这个声明定义了一个名为 s 的数组,数组包含 10 个元素,每个元素都是一个函数指针。(1)C (2)D (3)C (4)DE (5)C8 11 14(1)int IsFull(sequeue *seqn) { return ((seqn->frnt ((seqn->rear 1) % N)) ? 1 : 0); } (2)int IsEmpty(sequ…...
java-Spring-mvc-(请求和响应)
目录 📌HTTP协议 超文本传输协议 请求 Request 响应 Response 🎨请求方法 GET请求 POST请求 📌HTTP协议 超文本传输协议 HTTP协议是浏览器与服务器通讯的应用层协议,规定了浏览器与服务器之间的交互规则以及交互数据的格式…...
亚马逊测评工作室如何轻松实现高收益,跨境电商揭秘汇率差赚钱术
随着跨境电商在国内市场的持续繁荣,众多电商卖家纷纷将目光投向了这一充满活力的领域。面对国内市场的激烈竞争,许多卖家选择向外拓展,寻求更广阔的发展空间。其中,亚马逊成为了众多卖家的不二选择,毕竟老外的市场还是…...
unity中 UnityWebRequest.Post和 UnityWebRequest uwr = new UnityWebRequest两种方法有什么区别
在Unity中,UnityWebRequest.Post 和 UnityWebRequest uwr new UnityWebRequest(...) 是两种不同的方式来创建和发送HTTP POST请求,但它们之间有一些关键的区别和用法上的差异。 1. UnityWebRequest.Post (静态方法) UnityWebRequest.Post 是一个静态方…...
Java学习-练习试用Java实现求素数
以下是使用Java语言试着编写的求1-100内的素数的程序: public class PrimeNumbers {public static void main(String[] args) {System.out.println("Prime numbers between 1 and 100 are:");for (int i 2; i < 100; i) {if (isPrime(i)) {System.ou…...
最近学习发现一个background-blend-mode,这是CSS的一个新成员吧!这里分享记录一下
介绍 background-blend-mode CSS 属性定义该元素的背景图片,以及背景色如何混合。 混合模式应该按background-image CSS 属性同样的顺序定义。如果混合模式数量与背景图像的数量不相等,它会被截取至相等的数量。在所有的元素中。在SVG,它适…...
虚幻引擎5 Gameplay框架(二)
Gameplay重要类及重要功能使用方法(一) 配置LOG类及PlayerController的网络机制 探索验证GamePlay重要函数、类的执行顺序与含义 我们定义自己的日志,专门建立一个存放自己日志的类,这个类继承自BlueprintFunctionLibrary 然后…...
云原生Kubernetes: K8S 1.29版本 部署Sonarqube
一、实验 1.环境 (1)主机 表1 主机 主机架构版本IP备注masterK8S master节点1.29.0192.168.204.8 node1K8S node节点1.29.0192.168.204.9node2K8S node节点1.29.0192.168.204.10已部署Kuboard (2)master节点查看集群 1&…...
读天才与算法:人脑与AI的数学思维笔记19_深度数学
1. 深度数学 1.1. 组合与选择,是发明新事物的两个不可或缺的条件 1.1.1. 保尔瓦雷里(Paul Valry) 1.2. 利用以往的数学定理证明过程训练算法,以发现新的定理 1.3. 谷歌设在伦敦的总部整体有一种现代牛津大学的感觉,…...
Springboot+Vue项目-基于Java+MySQL的旅游网站系统(附源码+演示视频+LW)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…...
Element UI 简介
Element UI是一个基于Vue.js的组件库,提供了一套丰富的可复用的组件,包括按钮、表单、弹框、表格、菜单等等。它的设计风格简洁大方,易于使用,能够帮助开发者快速构建现代化的Web应用。 在Element UI中,有许多常用的组…...
mysql 删除重复的数据保留id最大的一条
在 MySQL 中,可以使用以下查询删除重复数据,只保留 ID 最大的那条记录: SQL DELETE t FROM table_name t LEFT JOIN ( SELECT column_name, MAX(id) AS max_id FROM table_name GROUP BY column_name ) t2 ON t.column_name t2…...
UE4 Widget制作搜索框
效果: 一、控件层级结构 1.父控件层级结构 2.子控件层级结构 二、蓝图 1.先清除掉创建子项(注意:这里使用的是reverse循环!) 2.判断是否含有关键字,创建子控件...
JavaScript js写九九乘法表(两种方法)
方法一: 观察规律: 第一个数每行都是自增1。 我们发下第二个数都是从1开始,依次递增1,永远不大于前面的数。 前面数字每自增一次,后面数字自增一轮。 我们可以用双重for循环,外层初始值设为i࿰…...
算法--贪心算法
贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。贪心算法在有最优子结构的问题中尤其有效,这意味着局部最优解能决定全局最优解。简单来说,贪心…...
Redis基本數據結構 ― String
Redis基本數據結構 ― String 介紹常用命令範例1. 為字串鍵設值/取得字串鍵的值2. 查看字串鍵的過期時間3. 如何為key設置時間?4. 如何刪除指定key?5. 如何增加value的值?6. 獲取value值的長度 介紹 字串鍵是Redis中最基本的鍵值對類型,這種類型的鍵值對會在數據…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
