0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

关于MIG IP核控制DDR3读写测试案例解析

454398 来源:博客园 作者:没落骑士 2020-10-29 14:44 次阅读

本文设计思想采用明德扬至简设计法。在高速信号处理场合下,很短时间内就要缓存大量的数据,这时片内存储资源已经远远不够了。DDR SDRAM因其极高的性价比几乎是每一款中高档FPGA开发板的首选外部存储芯片。DDR操作时序非常复杂,之所以在FPGA开发中用途如此广泛,都要得意于MIG IP核。网上关于MIG控制DDR的资料很多,因此本文只讲述个人认为较重要的内容。由于MIG IP核用户接口时序较复杂,这里给出扩展接口模块用于进一步简化接口时序。

先来看看MIG IP核的架构:

了解下存储芯片侧重要接口:

ddr_addr DDR3的行列地址

ddr_ba DDR3的bank地址

ddr_cas_n ddr_ras_n ddr_we_n 命令控制

ddr_ck ddr_ck_n 差分时钟

ddr_dm 数据输入屏蔽

ddr_o_dt片上终端使能,用于使能和禁止片内终端电阻

ddr_reset_n DDR3复位

ddr_dqs ddr_dqs_n 数据同步信号

ddr_dq 传输数据

之后我们从IP核配置开始说起。Controller Options这页最为重要,其中包括时钟策略和外部DDR芯片参数配置。首先时钟周期选择为400MHz,此时PHY to Controller Clock Ratio只能是4:1,也就是说MIG用户侧时钟为100MHz。下半部分是选择合适的DDR芯片型号和参数,要再三确认无误。

Memory Options这页输入时钟周期选择为200MHz,根据Controller Options页的选项,该时钟经过PLL分频和倍频后的时钟分别作为用户侧时钟100MHz和DDR接口时钟400MHz。

这里有个参考时钟选项,如果Memory Options页PLL输入时钟频率选为200MHz,此处可以直接选择Use System Clock,从而简化接口。

以上是MIG IP核配置过程中较为重要的部分,实际上上述配置也可通过修改工程代码中参数来重定义。IP核配置完成,打开example design工程顶层文件,我们来重点关注下用户侧接口功能和时序。

这是本人写的注释,更具体清晰的说明还是要查看官方文档UG586.接下来看看写数据和读数据的接口时序图(时钟比例4:1,burst length = 8为例):

指令通道:

写数据:

从时序图可以看出,指令地址和数据使用两套时序,彼此相互独立。为了便于设计,直接将两套时序严格对齐(情况1)也可以正常工作。

读数据:

为什么说“时钟比例4:1,burst length = 8为例”?这一点特别关键。此时用户时钟周期是DDR接口时钟周期的4倍,也就是一个用户时钟信号上升沿对应8个DDR时钟边沿。burst length可以理解为MIG连续操作DDR地址的个数,故在4:1时钟比例下,一个用户时钟周期正好对8个地址进行了读/写操作,256bit数据分8次(32bit)写入DDR中。由此分析,在写数据时让app_wdf_end = app_wdf_wren即可,并且读/写操作时地址递增步长为8.

虽然MIG IP核提供了用户接口,但读写指令通道复用且需要实时关注两个rdy信号造成了时序操作上的不方便。为此我们需要对接口进一步封装,保证写操作时只关注:写使能user_wdata_en 写地址user_waddr 写数据user_wdata和写准备就绪信号user_wdata_rdy,读操作时只关注:读使能user_rdata_en 读地址user_raddr 读数据user_rdata 读数据有效user_rdata_vld和读操作准备就绪user_rdata_rdy。

利用扩展接口模块,将读通道和写通道接口分离,并分别例化一个FIFO缓存地址和数据。当读/写指令同时有效时,通过MIG侧的优先级轮换逻辑轮流读取其中一个FIFO,每次选一个FIFO读取直至FIFO为空再重新选择。其工程结构和核心代码如下:

读侧逻辑核心代码:

 1 //读侧--------------------------------------------------------------
 2 
 3 always @(posedge clk or negedge rst_n )begin 
 4     if(rst_n==0) begin
 5         rd_flag <= (0)  ;
 6     end
 7     else if(rd_flag == 0 && mig_rdy && mig_wdf_rdy && !rdempty1 && (rdempty0 || (!rdempty0 && priority == 0)))begin
 8         rd_flag <= (2'b01)  ;//读取 写指令FIFO
 9     end 
10     else if(rd_flag == 0 && mig_rdy && !rdempty0 && (rdempty1 || (!rdempty1 && priority == 1)))begin
11         rd_flag <= (2'b10)  ;//读取 读指令FIFO
12     end 
13     else if((rd_flag == 2'b01 && rdempty1)||(rd_flag == 2'b10 && rdempty0))
14         rd_flag <= 0;
15 end
16 
17 //同时非空时轮换优先级
18 always @(posedge clk or negedge rst_n )begin 
19     if(rst_n==0) begin
20         priority <= (0)  ;
21     end
22     else if(rd_flag == 0 && !rdempty0 && !rdempty1)begin
23         priority <= (!priority)  ;
24     end 
25 end

为了方便测试,设计样式生成模块与扩展接口模块用户侧连接,不断向一段地址写入固定数据序列并在一段时间后读回。

  1 `timescale 1ns / 1ps
  2 /*
  3 该模块功能:
  4 周期性向一段地址执行读写操作 产生固定样式待写入数据用户测试目的
  5 测试完毕后删除该模块,开发用户接口
  6 
  7 具体为:
  8 1 写从0开始之后的10个用户地址(80个DDR地址):0~9递增序列
  9 2 等待20个时钟周期
 10 3 读取写入的10个用户地址
 11 4 等待20个时钟周期
 12 5 重复上述步骤
 13 
 14 说明:
 15 1 每个步骤之间有一个时钟周期空闲
 16 2 由于burst_len = 8 4:1时钟模式下一个用户时钟周期写入数据对应同样时间内8个DDR时钟边沿写入数据,
 17 因此地址递增步长为8
 18 */
 19 module traffic_gen
 20 #(parameter DATA_WIDTH = 32,
 21             ADDR_WIDTH = 29)
 22 (
 23     input                           clk   ,
 24     input                           rst_n ,
 25 
 26     output reg                      gen_wdata_en ,
 27     output reg [ ADDR_WIDTH-1:0]    gen_waddr    ,
 28     output reg [ DATA_WIDTH-1:0]    gen_wdata ,
 29     input                           gen_wdata_rdy ,//写指令和数据通道准备就绪
 30 
 31     output reg                      gen_rdata_en ,
 32     output reg [ ADDR_WIDTH-1:0]    gen_raddr    ,
 33     input      [ DATA_WIDTH-1:0]    gen_rdata     ,
 34     input                           gen_rdata_vld ,
 35     input                           gen_rdata_rdy //读指令通道准备就绪
 36 );
 37 
 38    
 39 reg [ (8-1):0]  cnt0     ;
 40 wire        add_cnt0 ;
 41 wire        end_cnt0 ;
 42 reg [ (2-1):0]  cnt1     ;
 43 wire        add_cnt1 ;
 44 wire        end_cnt1 ;
 45 
 46 reg [ DATA_WIDTH-1:0]  gen_rdata_r     ;
 47 reg   gen_rdata_vld_r     ;
 48 reg    com_flag     ;
 49 
 50 wire wri_state;
 51 wire rd_state;
 52 wire com_change_t;
 53 
 54 //操作周期计数器,计数值为欲操作用户地址段长度+1(需要一个时钟周期空闲)
 55 always @(posedge clk or negedge rst_n) begin 
 56     if (rst_n==0) begin
 57         cnt0 <= 0; 
 58     end
 59     else if(add_cnt0) begin
 60         if(end_cnt0)
 61             cnt0 <= 0; 
 62         else
 63             cnt0 <= cnt0+1 ;
 64    end
 65 end
 66 assign add_cnt0 = (com_flag == 0 && gen_wdata_rdy) || (com_flag == 1 && gen_rdata_rdy);
 67 assign end_cnt0 = add_cnt0  && cnt0 == (30)-1 ;
 68 
 69 //指令标志位 先是0--写 再是1--读
 70 always @(posedge clk or negedge rst_n )begin 
 71     if(rst_n==0) begin
 72         com_flag <= (0)  ;
 73     end
 74     else if(com_change_t)begin
 75         com_flag <= (!com_flag)  ;
 76     end 
 77 end
 78 
 79 assign com_change_t = add_cnt0 && cnt0 == 10 - 1;
 80 
 81 //写操作---------------------------------------------
 82 always @(posedge clk or negedge rst_n )begin 
 83     if(rst_n==0) begin
 84         gen_wdata_en <= (0)  ;
 85     end
 86     else if(wri_state)begin
 87         gen_wdata_en <= (1'b1)  ;
 88     end 
 89     else begin
 90         gen_wdata_en <= (0)  ;
 91     end 
 92 end
 93 
 94 assign wri_state = add_cnt0 && cnt0 <= 10-1 && com_flag == 0;
 95 assign rd_state  = add_cnt0 && cnt0 <= 10-1 && com_flag == 1;
 96 
 97 always @(posedge clk or negedge rst_n )begin 
 98     if(rst_n==0) begin
 99         gen_wdata <= (0)  ;
100     end
101     else begin
102         gen_wdata <= (cnt0)  ;
103     end 
104 end
105 
106 always@(posedge clk or negedge rst_n)begin
107     if(rst_n == 0)
108         gen_waddr <= 0;
109     else if(wri_state)
110         gen_waddr <= gen_waddr + 29'd8;
111     else 
112         gen_waddr <= 0;
113 end
114 //读操作----------------------------------------------
115 
116 always @(posedge clk or negedge rst_n )begin 
117     if(rst_n==0) begin
118         gen_rdata_en <= (0)  ;
119     end
120     else if(rd_state)begin
121         gen_rdata_en <= (1'b1)  ;
122     end 
123     else begin
124         gen_rdata_en <= (0)  ;
125     end 
126 end
127 
128 always@(posedge clk or negedge rst_n)begin
129     if(rst_n == 0)
130         gen_raddr <= 0;
131     else if(rd_state)
132         gen_raddr <= gen_raddr + 29'd8;
133     else 
134         gen_raddr <= 0;
135 end
136 
137 always @(posedge clk or negedge rst_n )begin 
138     if(rst_n==0) begin
139         gen_rdata_r <= (0)  ;
140     end
141     else begin
142         gen_rdata_r <= (gen_rdata)  ;
143     end 
144 end
145 
146 always @(posedge clk or negedge rst_n )begin 
147     if(rst_n==0) begin
148         gen_rdata_vld_r <= (0)  ;
149     end
150     else if(gen_rdata_vld)begin
151         gen_rdata_vld_r <= (1'b1)  ;
152     end 
153     else begin
154         gen_rdata_vld_r <= (0)  ;
155     end 
156 end
157 
158 endmodule

将traffic_gen和extend_interface模块例化在MIG的example design中,利用ILA抓取MIG IP核用户接口信号。

向地址8~80写入数据0~9,再从此段地址中读回数据,0~9被正确读出,MIG IP核控制DDR3读写测试完毕。
编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1629

    文章

    21735

    浏览量

    603188
  • DDR3
    +关注

    关注

    2

    文章

    276

    浏览量

    42261
  • 信号处理
    +关注

    关注

    48

    文章

    1027

    浏览量

    103273
  • 存储芯片
    +关注

    关注

    11

    文章

    897

    浏览量

    43141
  • MIG
    MIG
    +关注

    关注

    0

    文章

    12

    浏览量

    10979
收藏 人收藏

    评论

    相关推荐

    基于Arty Artix-35T FPGA开发板的DDR3mig介绍

    讲解xilinx FPGA 使用mig IPDDR3读写控制,旨在让大家更快的学习和应用DDR3
    的头像 发表于 01-01 10:09 4224次阅读
    基于Arty Artix-35T FPGA开发板的<b class='flag-5'>DDR3</b>和<b class='flag-5'>mig</b>介绍

    mig生成的DDRIP的问题

    请教各位大神,小弟刚学FPGA,现在在用spartan-3E的板子,想用上面的DDR SDRAM进行简单的读写,用MIG生成DDR
    发表于 06-20 20:43

    cyclone V控制DDR3读写,quartusII配置DDR3 ip后,如何调用实现DDR3读写呢,谢谢

    DDR3IP核配置完毕后,产生了好多文件,请问如何调用这些文件实现DDR3读写呢?看了一些文章,说是要等到local_init_done为高电平后,才能进行
    发表于 01-14 18:15

    MIG IP管脚分配问题

    求助大神!!!FPGA对于DDR3读写,FPGA是virtex6系列配置MIG IP 时,需要管脚分配1.原理图上dm是直接接地,管脚分配
    发表于 03-16 18:45

    基于FPGA的DDR3 SDRAM控制器的设计与优化

    不同使用情形下DDR3的带宽利用率来寻求具有较高效率的读写控制方式。本测试计算带宽效率的方式是,向IP
    发表于 08-02 09:34

    Xilinx:K7 DDR3 IP核配置教程

    ”。13.点击“Generate”生成MIG控制器。四、生成文档点击“Generate”,生成MIG控制器相关的设计文档。以上就是基于Xilinx 的K7
    发表于 12-19 14:36

    完成DDR3校准的MIG IP失败的原因?

    大家好 我的问题是DDR3校准完成失败。调试结果:dbg_wrcal_err = 1,通过波形,我们可以看到写入模式不匹配。 我的问题是MIG IP Core配置中是否有任何参数可以调整它?或者我
    发表于 07-23 10:09

    ddr3读写分离方法有哪些?

    DDR3是目前DDR的主流产品,DDR3读写分离作为DDR最基本也是最常用的部分,本文主要阐述DDR3
    的头像 发表于 11-06 13:44 8858次阅读
    <b class='flag-5'>ddr3</b>的<b class='flag-5'>读写</b>分离方法有哪些?

    DDR3读写状态机进行设计与优化并对DDR3利用率进行了测试与分析

    为解决超高速采集系统中的数据缓存问题,文中基于Xilinx Kintex-7 FPGA MIG_v1.9 IP进行了DDR3 SDRAM控制
    发表于 11-16 14:36 2.3w次阅读
    对<b class='flag-5'>DDR3</b><b class='flag-5'>读写</b>状态机进行设计与优化并对<b class='flag-5'>DDR3</b>利用率进行了<b class='flag-5'>测试</b>与分析

    基于FPGA的DDR3多端口读写存储管理的设计与实现

    为了解决视频图形显示系统中多个端口访问DDR3的数据存储冲突,设计并实现了基于FPGA的DDR3存储管理系统。DDR3存储器控制模块使用MIG
    发表于 11-18 18:51 7136次阅读
    基于FPGA的<b class='flag-5'>DDR3</b>多端口<b class='flag-5'>读写</b>存储管理的设计与实现

    mig接口的读写时序

    对于migDDR3/DDR2 SDRAM的读写时序我们不需要了解太多,交给mig就可以了。
    发表于 03-03 11:11 6265次阅读
    <b class='flag-5'>mig</b>接口的<b class='flag-5'>读写</b>时序

    关于Virtex7上DDR3测试例程详解

    这篇文章我们讲一下Virtex7上DDR3测试例程,Vivado也提供了一个DDR的example,但却是纯Verilog代码,比较复杂,这里我们把DDR3
    的头像 发表于 05-02 09:05 3456次阅读
    <b class='flag-5'>关于</b>Virtex7上<b class='flag-5'>DDR3</b>的<b class='flag-5'>测试</b>例程详解

    Virtex7上DDR3测试例程

      这篇文章我们讲一下Virtex7上DDR3测试例程,Vivado也提供了一个DDR的example,但却是纯Verilog代码,比较复杂,这里我们把DDR3
    的头像 发表于 08-16 10:28 1920次阅读

    基于AXI总线的DDR3读写测试

    本文开源一个FPGA项目:基于AXI总线的DDR3读写。之前的一篇文章介绍了DDR3简单用户接口的读写方式:《DDR3
    的头像 发表于 09-01 16:20 4530次阅读
    基于AXI总线的<b class='flag-5'>DDR3</b><b class='flag-5'>读写</b><b class='flag-5'>测试</b>

    基于FPGA的DDR3读写测试

    本文介绍一个FPGA开源项目:DDR3读写。该工程基于MIG控制IP核对FPGA DDR3实现
    的头像 发表于 09-01 16:23 1659次阅读
    基于FPGA的<b class='flag-5'>DDR3</b><b class='flag-5'>读写</b><b class='flag-5'>测试</b>