『FPGA通信接口』DDR(3)DDR3颗粒读写测试

在这里插入图片描述

文章目录

  • 前言
  • 1.配套工程简介
  • 2.测试内容与策略
  • 3. 测试程序分析
  • 4.程序结果分析
  • 5.一个IP控制两颗DDR3
  • 6.传送门

前言

以四颗MT41K512M16HA-125AIT颗粒为例,介绍如何在一块新制板卡上做关于DDR3的器件测试。前面两篇介绍了什么是DDR,并介绍了xilinx给出的FPGA与DDR完美结合的方案MIG IP核,请按照顺序阅读DDR相关文章,链接在文末。DDR3颗粒,DDR3内存条,DDR4颗粒,DDR4内存条都可以与FPGA相连,DDR芯片选型以及链接形式选型与系统对于数据带宽的要求,存储容量的要求,对结构的要求息息相关,同时不同形式不同代DDR对FPGA选型提出了要求,本文介绍DDR3颗粒与FPGA相连,实现读写测试

1.配套工程简介

提供了两套DDR3颗粒测试工程,工程文件名是DDR3_2PCS800MHz,DDR3_4PCS400MHz,对应2片DDR的800Mhz读写测试,4片DDR的400Hz读写测试。此外还有DDR4颗粒测试工程和DDR3内存条测试工程。两套DDR3颗粒测试工程主控芯片是xilinx xc7k325tffg900-2,颗粒是MT41K512M16HA-125AIT,vivado版本是2020.2。不同的速度测试实际上只需要修改IP里面的配置即可。2片与4片的区别是,一次DDR引脚时钟,写入DDR的数据量是32bit和64bit的区别;MIG IP是按照8倍突发工作,即一个ui_clk用户时钟,MIG读取8个地址的数据,所以2片与4片会导致MIG IP的数据总线是256bit和512bit的区别。为了读者能够快速应用到自己的场景,提供的工程做了区分。需要说明的是,工程应用在本地需要注意,切换相应的时钟输入,切换DDR的UCF文件,切换指示灯的链接,如果有更多的指示灯,则可以接TEST_LENGTH相关的计数器指示一次测试结束,或者指示MIG IP的初始化结果。如果FPGA的型号不同或者DDR颗粒不同,建议重新创建工程进行测试,并且根据对应芯片重新计算TEST_LENGTH。例程都是按照app接口进行控制,在DDR3_4PCS400MHz中提供了一个block design,可以置顶编译综合布线生成bit后,使用tcl的命令便捷读写指定位置,用在定位某个确定位置的读写,这个block design用的是DDR 的AXI接口。
在这里插入图片描述
需要注意,本例的DDR颗粒不在MIG IP所直接支持的列表中,因为通过查询手册自定义了一个DDR型号,如下图所示。
在这里插入图片描述

2.测试内容与策略

通过写入和读出判断读写过程是否正确;此外,工程实践中会遇到当工作频率高的时候DDR读写不稳定, 因此必要进行速度测试。此外还应进行容量进行测试。一个测试工程,对上述三项全部测试;在MIG的平面地址接口中,按照地址顺序写入确定的已知值,然后在按照相同顺序读出这些已知值做比较,相同则常亮led表示测试通过,否则led闪烁表示测试失败。

3. 测试程序分析

附verilog测试代码,省略了模块例化部分,程序步骤解读如下:
①例化clk ip产生200MMIG参考电压输入
②例化MIG ip通过app接口读写ddr数据
③写两段式状态机,为进行容量测试,写至满容量的90%即可。写完切换至读状态,若读写无误则一直读写。Wr_addr_cnt或者rd_addr_cnt每计数一次,app_addr_begin自增8,这是因为,当工作频率配置为800MHz且用户时钟ui_clk与工作频率的比值配置为4:1时,ui_clk为200MHz。四片DDR3的数据位宽为64bit,由于”“DDR(double data rate)”,所以在每一个800MHz周期应该提供128bit数据,因此每一个200MHz周期应该向MIG提供512bit数据。而在单一内核中,每一个平面地址存储位数为16bit,四片即64bit,那512bit/64bit=8,即一个200MHz周期的512bit数据写入了8个平面地址,因此此处一次突发(即Wr_addr_cnt或者rd_addr_cnt每计数一次),app_addr_begin自增8。
该颗粒平面地址空间有16+10+3=29bit,上一段的描述提到一次突发需要8个地址,那么满容量可以进行多少次突发?即2^29(满地址)/8=67108864,将TEST_LENGTH设置为32’d60000000,即写了60000000/67108864=90%的空间,这样可以满足容量测试的要求。
④结合状态机运行状态和MIG返回的指示信号为app接口信号赋值,此处应结合各信号含义和接口时序核准。
⑤用户判错逻辑,写入和读出的都是从0开始递增的数据,当出错时指示灯闪烁。

parameter  TEST_LENGTH = 32'd60000000;
//***********1.先写后读状态机state machine
parameter  IDLE  = 2'd0;           
parameter  WRITE = 2'd1;          
parameter  WAIT  = 2'd2;           
parameter  READ  = 2'd3;   
reg [511:0]my_512_data;
reg [25:0] wr_addr_cnt;
reg [25: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  <= 26'd0;      rd_addr_cnt  <= 26'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  <= 26'd0;     rd_addr_cnt  <= 26'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 <= 26'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  <= 26'd0;rd_addr_cnt  <= 26'd0;app_addr_begin <= 30'd0;endendcaseend
end   
//********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     [25: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;//&&myrst
always @(posedge ui_clk or negedge rst_n) beginif(~rst_n) rd_cnt  <= 0;              //若计数到读写长度,且读有效,地址计数器则�?0else 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) begin
if(~rst_n)led2<=0;
else if(rd_cnt==32'd50000000)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 beginled_cnt <= led_cnt + 28'd1;if(led_cnt == L_TIME - 1'b1) beginled_cnt <= 25'd0;led1 <= ~led1;endend
end
end

4.程序结果分析

正常结果可以看到与上一节MIG IP给出的时序是一致的。
●写开始时序:
写开始时序
●写结束时序:
写结束时序
●读开始时序:
读开始时序
●读结束时序:
读结束时序
测试的结果最好通过读写一定量并且读写指示灯亮确认。当测试异常时,应按照DDR是否初始化成功、MIG app接口时序是否正确、MIG ip配置是否正确、状态机运行状态是否异常方面入手分析。DDR初始化不成功init_calib_complete为0可能的原因是,时钟输入与MIG IP配置不一致,MIG端口没有正确连接,DDR的UCF约束有问题。

5.一个IP控制两颗DDR3

如下原理图,可以清楚的看到,两颗DDR3的相同的控制线连在了一个控制器的相同引脚,而数据线是各自连的。在PCB布线的时候通常用fly_by的方式连接DDR3。对于FPGA而言,把外部的位宽为16bit的两颗DDR当成了一个位宽为32bit的DDR3来控制。这种往往是为了扩大容量;或者为了匹配rank位宽;或者为了提升带宽,将两片或者四片甚至更多片DDR3放在一起。对于这种场景,只需将上一篇IP配置第5步中的data width设置为实际芯片加起来的位宽即可。如两片16bit位宽颗粒相连,则设置位宽为32bit即可。其余的用户逻辑且把他当作一片位宽为32bit的DDR3即可。实际上,用户存入的32bit数据在实际存放时,高位16bit和低位16bit的数据被放到不同的两片DDR3中,唯一的关联就是,这两个位置的物理值是相等的而已。
在这里插入图片描述

6.传送门

  • 我的主页
  • FPGA通信接口专栏汇总导航
  • 上一篇:MIG IP核的使用
  • DDR3测试工程
END

🔈文章原创,首发于CSDN论坛。
🔈欢迎点赞❤❤收藏⭐⭐打赏💴💴!
🔈欢迎评论区或私信指出错误❌,提出宝贵意见或疑问❓。

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

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

相关文章

神经网络反向传播算法

今天我们来看一下神经网络中的反向传播算法&#xff0c;之前介绍了梯度下降与正向传播~ 神经网络的反向传播 专栏&#xff1a;&#x1f48e;实战PyTorch&#x1f48e; 反向传播算法&#xff08;Back Propagation&#xff0c;简称BP&#xff09;是一种用于训练神经网络的算…

品牌百度百科词条需要什么资料?

品牌百度百科词条是一个品牌的数字化名片&#xff0c;更是品牌历史、文化、实力的全面展现。 作为一个相当拿得出手的镀金名片&#xff0c;品牌百度百科词条创建需要什么资料&#xff0c;今天伯乐网络传媒就来给大家讲解一下。 一、品牌基本信息&#xff1a;品牌身份的明确 品…

【漏洞复现】科达 MTS转码服务器 任意文件读取漏洞

0x01 产品简介 科达 MTS转码服务器是一款专业的视频转码设备&#xff0c;采用了高性能的硬件配置和先进的转码技术&#xff0c;能够实现高效、高质量的视频转码。 0x02 漏洞概述 科达 MTS转码服务器存在任意文件读取漏洞&#xff0c;攻击可以通过该漏洞读取服务器任意敏感信…

FSD自动驾驶泛谈

特斯拉的FSD&#xff08;Full-Self Driving&#xff0c;全自动驾驶&#xff09;系统是特斯拉公司研发的一套完全自动驾驶系统。旨在最终实现车辆在多种驾驶环境下无需人类干预的自动驾驶能力。以下是对FSD系统的详细探讨&#xff1a; 系统概述 FSD是特斯拉的自动驾驶技术&…

宠物领养|基于SprinBoot+vue的宠物领养管理系统(源码+数据库+文档)

宠物领养目录 基于Spring Boot的宠物领养系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1前台 1.1 宠物领养 1.2 宠物认领 1.3 教学视频 2后台 2.1宠物领养管理 2.2 宠物领养审核管理 2.3 宠物认领管理 2.4 宠物认领审核管理 2.5 教学视频管理 四、…

零基础自学前端到达到什么水平才能找工作?

零基础自学前端到达到什么水平才能找工作&#xff1f; 零基础自学前端到达到什么水平才能找工作&#xff1f;从这个字眼的表面上来回答这个问题&#xff0c;但是是前端水平越高越好咯。前端技术人才只有不断通过学习、项目的事件来不断充实提高自己的技术&#xff0c;随之而来&…

【Jenkins】持续集成与交付 (四):修改Jenkins插件下载地址、汉化

🟣【Jenkins】持续集成与交付 (四):修改Jenkins插件下载地址、汉化 一、修改Jenkins插件下载地址二、汉化Jenkins三、关于Jenkins💖The Begin💖点点关注,收藏不迷路💖 一、修改Jenkins插件下载地址 由于Jenkins官方插件地址下载速度较慢,我们可以通过修改下载地址…

vue2迁移到vue3,v-model的调整

项目从vue2迁移到vue3&#xff0c;v-model不能再使用了&#xff0c;需要如何调整&#xff1f; 下面只提示变化最小的迁移&#xff0c;不赘述vue2和vue3中的常规写法。 vue2迁移到vue3&#xff0c;往往不想去调整之前的代码&#xff0c;以下就使用改动较小的方案进行调整。 I…

CVPR 小样本土地覆盖制图 张洪艳教授团队获挑战赛冠军

提出了一个广义的基于少镜头分割的框架&#xff0c;以更新高分辨率土地覆盖制图中的新类&#xff0c;分为三个部分:(a)数据预处理:对基础训练集和新类的少镜头支持集进行分析和扩充;(b)混合分割结构:将多基学习器和改进的投影到正交原型(POP)网络相结合&#xff0c;增强基类识别…

CSS中文本样式(详解网页文本样式)

目录 一、Text介绍 1.概念 2.特点 3.用法 4.应用 二、Text语法 1.文本格式 2.文本颜色 3.文本的对齐方式 4.文本修饰 5.文本转换 6.文本缩进 7.color&#xff1a;设置文本颜色。 8.font-family&#xff1a;设置字体系列。 9.font-size&#xff1a;设置字体大小。…

Laravel5.4 反序列化

文章目录 0x01 环境搭建0x02 POP 链0x03 exp0x04 总结 前言&#xff1a;CC 链复现的头晕&#xff0c;还是从简单的 Laravel 开始吧。 laravel 版本&#xff1a;5.4 0x01 环境搭建 laravel安装包下载地址 安装后配置验证页面。在 /routes/web.php 文件中添加一条路由&#xf…

数据库基础--MySQL简介以及基础MySQL操作

数据库概述 数据库&#xff08;DATABASE&#xff0c;简称DB&#xff09; 定义:是按照数据结构来组织、存储和管理数据的仓库.保存有组织的数据的容器(通常是一个文件或一组文件) 数据库管理系统(Database Management System,简称DBMS) 专门用于管理数据库的计算机系统软件;…

iBarcoder for Mac:一站式条形码生成软件

在数字化时代&#xff0c;条形码的应用越来越广泛。iBarcoder for Mac作为一款专业的条形码生成软件&#xff0c;为用户提供了一站式的解决方案。无论是零售、出版还是物流等行业&#xff0c;iBarcoder都能轻松应对&#xff0c;助力用户实现高效管理。 iBarcoder for Mac v3.14…

[软件工具]批量根据文件名查找PDF文件复制到指定的地方,如何批量查找文件复制,多个文件一起查找复制

多个文件目录下有多个PDF, 如何根据文件名一个清单&#xff0c;一次性查找多个PDF复制保存 如图所示下面有7个文件夹&#xff0c;每个文件夹里面有几百上千PDF文件 如何从上千个PDF文件中一次性快速找到我们要的文件呢 &#xff1f; 我们需要找到文件名是这样的PDF&#xff0…

vue3 jspdf,element table 导出excel、pdf,横板竖版分页

多个表格需要&#xff0c;pdf需要的格式与原本展示的表格样式不同 1.创建一个新的表格&#xff0c;设置pdf需要的样式&#xff0c;用vue的h函数放入dom中 2.excel用xlxs插件直接传入新建el-table的dom,直接导出 3.pdf导出类似excel黑色边框白底黑字的文件&#xff0c;把el-t…

低代码工业组态数字孪生平台

2024 两会热词「新质生产力」凭借其主要特征——高科技、高效能及高质量&#xff0c;引发各界关注。在探索构建新质生产力的重要议题中&#xff0c;数据要素被视为土地、劳动力、资本和技术之后的第五大生产要素。数据要素赋能新质生产力发展主要体现为&#xff1a;生产力由生产…

【linuxC语言】fcntl和ioctl函数

文章目录 前言一、功能介绍二、具体使用2.1 fcntl函数2.2 ioctl函数 三、拓展&#xff1a;填写arg总结 前言 在Linux系统编程中&#xff0c;经常会涉及到对文件描述符、套接字以及设备的控制操作。fcntl和ioctl函数就是用来进行这些控制操作的两个重要的系统调用。它们提供了对…

Visual Studio中怎样更改Nuget程序包源

场景 Visual Studio 2019 在使用NuGet添加依赖包时&#xff0c;在预览中搜索不到程序包。 排查下NuGet的程序包源为本地。 将程序包源修改下。 实现 在解决方案上右击选择管理解决方案中的NuGet程序包(在 Visual Studio 中打开“工具”>“选项”>“NuGet 包管理器”…

请求路径引发的http308错误

记录一个请求路径输错引发的问题。 正确路径&#xff1a; /user/bind-email 请求路径我们如果输错故意多打一个s /user/bind-emails 正常预检请求会报错404未找到&#xff0c;我们下意识的就去排查路径是不是写错了 但是如果多打一个/ /user//bind-email 此时预检请求会报308永…

Java中优雅实现泛型类型的强制转换

在Java中经常遇到将对象强制转换成泛型类的情况&#xff1a; Map<String, Object> data Map.of("name", "XiaoMing","age", 17,"scores", List.of(80, 90, 70) );List<Integer> scores (List<Integer>) data.get…