[X]关闭
2

(非AXI4)S02-CH01_DDR3_READ_WRITE(内存读写测试)

摘要: 1.1 MIG 控制器概述本节介绍 7 系列 FPGA 存储器接口解决方案核心架构,概述了核心模块和接口。7 系列 FPGA 存储器接口解决方案核心如图 1-1-1 所示。1.2 用户 FPGA 逻辑接口图 1-1-1 所示的FPGA用户逻辑代码通过MIG ...

软件版本:VIVADO2017.4

操作系统:WIN10

硬件平台:MK7160FA

1.1 MIG  控制器概述

本节介绍 7 系列 FPGA 存储器接口解决方案核心架构,概述了核心模块和接口。

7 系列 FPGA 存储器接口解决方案核心如图 1-1-1 所示。

1.2  用户 FPGA 逻辑接口

图 1-1-1 所示的FPGA用户逻辑代码通过MIG控制器IP接到了DDR2或者DDR3的物理芯片。

IPCORE 提供一个可以测试的例子,但是这个例子不方便阅读,所以这里笔者写一个更加实用,容易阅读和理解MIG控制器使用的例子。


AXI4 从接口块

AXI4 从站接口将 AXI4 事务映射到 UI,以向内存控制器提供行业标准总线协议接口。AXI4协议访问MIG的方式不本章节讨论范围。


用户界面块和用户界面

UI 块向用户提供 FPGA 逻辑块。它通过呈现平面地址空间和缓冲读写数据来提供对本机接口的简单替代。MIG提供的UI接口大大简化了DDR在FPGA上使用。假如没有MIG控制器想要高效得访问DDR需要自己编写逻辑,这个难度就太大了,一般FPGA工程师就无法玩转DDR了。


内存控制器和本机接口


内存控制器(MC)的前端显示 UI 块的本机接口。本地接口允许用户设计提交存储器读写请求,并提供将数据从用户设计移动到外部存储器件的机制,反之亦然。内存控制器的后端连接到物理接口,

并处理该模块的所有接口要求。内存控制器还提供了重新排序选项,重新排序接收的请求以优化数据吞吐量和延迟。


DDR PHY 的前端接到MIG 控制器,而后端接到具体的DDR芯片。当处理PHY的延迟时需要使用IDELAYCTRL,来控制时序。任何使用任何使用 IDELAYs 的BANK都需 IDELAYCTRL。 IDELAY 与数据组(DQ)相关联。 任何使用这些信号的 BANK/时钟区域都需 IDELAYCTRL.MIG 工具实例化一个IDELAYCTRL,然后使用 IODELAY_GROUP 属性(参见 iodelay_ctrl.v 模块)。基于此属性,Vivado Design Suite 可根据需要在设计中正确复制 IDELAYCTRL IDELAYCTRL 参考频率由 MIG 工具设置为 200 MHz,300MHz 或 400 MHz,具体取决于 FPGA 的存储器接口频率和速度等级。 根据设置的 IODELAY_GROUP 属性,Vivado Design Suite 会复制 IDELAY 块所在区域的 IDELAYCTRL。


当用户自己创建一个多控制器设计时,每个 MIG 输出都具有用原语实例化的组件。这违反了IDELAYCTRLs 的规则和 IODELAY_GRP 属性的使用。IDELAYCTRL 需要只有一个组件的实例化才能正确设置属性,并允许工具根据需要进行复制。


用户接口


UI 如表 1-2-1 所示,并连接到 FPGA 用户设计,以允许访问外部存储设备。表 1-2-1 User Interface

表 1-2-1 继续

注意:

1.该信号仅提供到 memc_ui_top 模块级别。 只有当 ECC 被使能时才应使用该信号。

app_addr [ADDR_WIDTH - 1:0]

此输入表示当前正在提交给用户界面的请求的地址。 UI 聚合外部 SDRAM 的所有地址字段,并向您显示一个平面地址空间。每个地址代表4BYTES 这个读者请注意。


app_cmd[2:0]

此输入指定请求的命令如下表所示

表 1-2-2 Commands for app_cmd[2:0]

app_en

此信号在输入请求中使用,用户必须赋值于 app_addr [],app_cmd [2:0]和 app_hi_pri,然后断言 app_en 将该请求提交给 UI。这将通过断言 app_rdy 启动 UI 确认的握手。


app_hi_pri

该输入表示当前请求是高优先级,用不到。


app_wdf_data [APP_DATA_WIDTH - 1:0]

该总线提供当前正在写入外部存储器的数据。


app_wdf_end

该输入表示当前周期中 app_wdf_data []总线上的数据是当前请求的数据。


app_wdf_mask [APP_MASK_WIDTH - 1:0]

该总线指示 app_wdf_data [] 的哪些位被写入外部存储器,哪些位保持在当前状态

app_wdf_wren

该输入表示 app_wdf_data []总线上的数据有效。


app_rdy

此输出向用户显示当前正在提交给 UI 的请求是否被接受。如果在 app_en 被断言之后,UI 不会声明此信号,则必须重试当前的请求。如果以下情况,则不会声明 app_rdy 输出:


1)PHY /内存初始化尚未完成


2)所有的BANK机器都被占用(可以看作命令缓冲区已满)


- 请求读取,读取缓冲区已满


- 请求写入,并且没有写缓冲区指针可用


3)正在插入定期读取


app_rd_data [APP_DATA_WIDTH - 1:0]

该输出包含从外部存储器读取的数据。


app_rd_data_end

此输出表示当前周期中 app_rd_data []总线上的数据为当前请求的最后数据。


app_rd_data_valid

该输出表示 app_rd_data []总线上的数据有效。


app_wdf_rdy

该输出表示写入数据 FIFO 准备好接收数据。 接受写入数据当 app_wdf_rdy 和 app_wdf_wren 都被断言时。


app_ref_req

当被置位时,该高电平有效输入请求存储器控制器向 DRAM 发送刷新命令。 必须对单个周期进行脉冲以进行请求,然后至少断言,直到 app_ref_ack 信号被断言以确认请求并指示已经发送请求。


app_ref_ack

当置位时,此高电平有效输入确认刷新请求,并指示命令已从存储控制器发送到 PHY。


app_zq_req

当置位时,该高电平有效输入请求存储器控制器向 DRAM 发送 ZQ 校准命令。 必须对单个周期进行脉冲以进行请求,然后至少断言,直到 app_zq_ack 信号被断言以确认请求并指示已经发送请求。


app_zq_ack

当有效时,此高电平有效输入确认 ZQ 校准请求,并指示命令已从存储控制器发送到 PHY。


ui_clk_sync_rst

这是从与 ui_clk 同步的 UI 重置。


ui_clk

这是 UI 的输出时钟。 它必须是出口到外部 SDRAM 的时钟频率的一半或四分之一,这取决于 GUI 中选择的 2:1 或 4:1 模式。


init_calib_complete

当校准完成时,PHY 会断言 init_calib_complete。 在向内存控制器发送命令之前,应用程序无需等待 init_calib_complete。


AXI4 从接口块


AXI4 从接口模块将 AXI4 事务映射到 UI 界面,为内存控制器提供业界标准的总线协议接口。在通过 MIG 工具提供的设计中,AXI4 从站接口是可选的。两种工具之间的 RTL 是一致的。MIG AXI4 总线接口的方式更多用于 SOC 的开发,本章教程暂时不讲解 AXI4 总线方式,读写 MIG.


1.3  时钟架构(Clocking Architecture)

DDR PHY 设计要求使用 PLL 模块来生成各种时钟,全局和本地时钟网络都用于在整个设计中分配时钟。 PHY 还需要与 PLL 相同的一个 MMCM。该 MMCM 补偿 BUFG 到 PHY 的插入延迟。时钟生成和分配电路和网络驱动 PHY 内的块,大致分为四个单独的一般功能:


•内部(FPGA)逻辑

写入路径(输出)I / O 逻辑


•读路径(输入)和延迟 I / O 逻辑


•IDELAY 参考时钟(小编这里有点不明白的,因为提供给MIG的 ref时钟小编都是给的200M)


对于 DDR3 设计,IDELAY 参考时钟生成需要一个 MMCM。如果设计频率> 667 MHz,则 IDELAY 参考时钟为 300MHz 或 400MHz(取决于 FPGA 速度等级)。MIG 实例化一个 MMCM,用于 300MHz 和 400MHz 时钟生成。


PHY 需要一个 MMCM 和一个 PLL。PLL 用于为大多数内部逻辑,相位器的频率参考时钟以及在多 I/O bank 实现中保持 PHY 控制块保持同步所需的同步脉冲生成时钟。


对于 400MHz 和 933MHz 之间的 DDR3 SDRAM 时钟频率,两个相位器频率参考时钟的频率都与存储器时钟频率相同。对于低于 400MHz 的 DDR2 或 DDR3 SDRAM 时钟频率,其中一个移相器频率参考时钟以与存储器时钟相同的频率运行,而第二个频率参考时钟必须是存储器时钟频率的 2x 或 4x,使其满足范围要求 400 MHz 至 933 MHz。两个相位器频率参考时钟必须由相同的 PLL 产生,因此它们彼此同相。时钟架构的框图如图 1-3-1 所示。freq_refclk 的相位根据操作频率和为存储器接口引脚选择的 bank 而有所不同。


•在 GUI 中为存储器接口引脚选择 HP 存储区并且存储频率≥400MHz 时,相位为 337.5°。


•在 GUI 中为存储器接口引脚选择 HP 存储区时,存储器频率在 200-400 MHz(不包括 400MHz)之间,相位为 315°。


•对于低电压设备,当选择 HP 存储区用于 GUI 中的存储器接口引脚并且存储器频率≥400MHz 时,相位为 337.5°。


•对于在 GUI 中为存储器接口引脚选择 HP 存储区并且存储器频率在 200-400 MHz(不包括 400MHz)之间的低压设备时,相位为 0°。


•当在 GUI 中为存储器接口引脚选择 HR 库并且存储器频率≥400MHz 时,相位为 337.5°。


•当在 GUI 中为存储器接口引脚选择 HR 库时,存储器频率在 200-400MHz(不包括 400MHz)之间,相位为 0°。


PLL 乘法(M)和除(D)值的默认设置是系统时钟输入频率等于存储器时钟频率。 不需要 1:


的比例。 只要符合 PLLE2 操作条件,并遵守列出的其他约束,PLL 输入分频器(D)可以是“7 系列 FPGA 时钟资源用户指南”(UG472)[参考文献 10]中列出的任何值。 PLL 乘法(M)值必须在 1 和 16 之间,包括 1 和 16。用于存储器时钟的 PLL 输出分频器(O)对于 800Mb/s 及以上必须为 2,对于 400 至 800Mb/s,必须为 2。PLL VCO 频率范围必须保持在硅数据表中指定的范围内。sync_pulse


必须是 mem_refclk 频率的 1/16,必须具有 1/16 或 6.25%的占空比。有关 PLL 和系统时钟 CCIO 输入的物理放置的信息,请参阅设计指南,第 192 页(MIG手册,不是本教程哦)。

ISERDES/OSERDES 连接的详细信息如图 1-3-2 和图 1-3-3。

图1-3-2 Address/Command Path Block Diagram

内部(FPGA)逻辑时钟(Internal (FPGA) Logic Clock)(读者这里注意了,决定了uclk的时钟的哦)

内部 FPGA 逻辑由 DDR2 或 DDR3 SDRAM 时钟频率的一半或四分之一频率的全局时钟资源提供时钟,这取决于 MIG 工具中选择的 4:1 或 2:1 模式。 该 PLL 还输出高速 DDR2 或 DDR3 内存时钟。


写路径(输出)I / O逻辑时钟(Write Path (Output) I/O Logic Clock)

包含数据和控制的输出路径由 PHASER_OUT 计时。PHASER_OUT 为 OUT_FIFO 和 OSERDES / ODDR 的每个字节组提供同步时钟。HASER_OUT 为其相关联的字节组生成字节时钟(OCLK),分频字节时钟(OCLKDIV)和延迟字节时钟(OCLK_DELAYED)。这些时钟直接从频率参考时钟生成,并且彼此同相。字节时钟频率与频率参考时钟频率相同,分频字节时钟是频率参考时钟频率的一半。 OCLK_DELAYED 用于对 DQS ODDR 进行时钟以实现写 DQS 与其相关 DQ 位之间所需的 90°相位偏移。 PHASER_OUT 还驱动在写入期间产生 DQS 所需的信号,与数据字节组相关联的 DQS 和 DQ 3 状态以及字节组的 OUT_FIFO 的读取使能。使用 PHASER_OUT 的地址/控制和写入路径的时钟细节如图 1-3-2 和图 1-3-3 所示。


读路径(输入)I / O 逻辑时钟(Read Path (Input) I/O Logic Clock)

输入读取数据路径由 PHASER_IN 块计时。 PHASER_IN 块为 IN_FIFO 和 IDDR / ISERDES 的每个字节组提供同步时钟。 PHASER_IN 块接收相关字节组的 DQS 信号,并为 DDR2 或 DDR3 SDRAM 数据捕获产生两个延迟时钟:读字节时钟(ICLK)和读分频字节时钟(ICLKDIV)。 ICLK 是与相关 DQS 相对齐的频率参考时钟的延迟版本。ICLKDIV 用于将数据捕获到 ISERDES 中的第一级触发器中。ICLKDIV与 ICLK 对齐,是 ISERDES 中触发器最后一级的并行传输时钟。ICLKDIV 也用作与字节组相关联的 IN_FIFO 的写时钟。 PHASER_IN 块还驱动字节组的 IN_FIFO 的写使能(WrEnable)。使用 PHASER_IN 的读取路径的时钟细节如图 1-3-3 所示。


IDELAY参考时钟(IDELAY Reference Clock)

用户必须提供 200 MHz ref_clk,然后 MIG 会使用附加的 MMCM 创建相应的 IDELAYCTRL 频率。 IDELAYCTRL 模块会持续校准 I/O 区域中的 IDELAY 元件,以解决不同的环境条件。 IP 内核假定外部时钟信号正在驱动 IDELAYCTRL 模块。如果 PLL 时钟驱动 IDELAYCTRL 输入时钟,PLL 锁定信号需要并入 IODELAY_CTRL.v 模块中的 rst_tmp_idelay 信号中。这样可以确保时钟在使用前是稳定的。


1.4 MIG内存控制器用户逻辑时序

本小节讲解控制命令、读命令、写命令极其时序。

1.4.1  命令路径(Command Path)

当用户逻辑 app_en 信号被断言并且 app_rdy 信号从 UI 被断言时,命令被 UI 接受并写入 FIFO。当 app_rdy 被取消置位时,UI 会忽略该命令。用户逻辑需要将 app_en 保持为高电平以及有效的命令和地址值,直到 app_rdy 被断言,如图所示。


如图1-4-1-2所示。此图描述了 app_wdf_data ,app_wdf_wren 和 app_wdf_end 信号的三种场景,如下所示:

1.写入数据以及相应的写入命令(BL8 的下半部分)。

2.写入数据在相应的写入命令之前。

3.写入数据在相应的写命令之后,不应超过两个时钟周期的限制。


对于在写入命令后输出的写入数据,如注 3 所示,最大延迟为两个时钟周期。


1.4.2 写路径

当 app_wdf_wren 被断言并且 app_wdf_rdy 为高时,写数据被写入写入 FIFO(图 1-4-2-1)。如果 app_wdf_rdy 被取消置位,则用户逻辑需要保留 app_wdf_wren 和 app_wdf_end 以及有效的 app_wdf_data 值,直到 app_wdf_rdy 被断言。app_wdf_mask 信号可用于屏蔽写入外部存储器的字节。

如图 1-4-2-2 所示,写入数据和相关联的写入命令之间的单次写入的最大延迟是两个时钟周期。当发出背靠背写入命令时,写入数据和相关的背靠背写命令之间没有最大延迟,如图 1-4-2-2 所示。

必须使用 app_wdf_end 信号来指示存储器写入突发的结束。对于 8 位的内存突发类型,应该在第二个写入数据字上断言 app_wdf_end 信号。应用程序接口数据到 DRAM 输出数据的映射可以是以一个例子解释。


1.4.3 读路径

读取的数据由 UI 以请求的顺序返回,并且在 app_rd_data_valid 被断言时有效(图1-4-3-1 和图1-4-3-2)。app_rd_data_end 信号表示每个读命令脉冲串的结束,在用户逻辑中不需要。

返回的读取数据总是与地址/控制总线上的请求顺序相同。

1.4.4 用户刷新

对于用户控制的刷新,应通过将 USER_REFRESH 参数设置为“ON”来禁用内存控制器管理的维护。要请求 REF 命令,app_ref_req 会选通一个周期。当存储器控制器将命令发送到 PHY 时,它会将 app_ref_ack 选通一个周期,之后可以发送另一个请求。界面如图 1-4-4-1 所示。

只要遵循上述定义的握手,可以随时执行用户刷新操作。对于其他命令,没有额外的接口要求。但是,待处理的请求会影响操作何时出现。内存控制器在发出刷新命令之前完成所有挂起的数据请求。在确定何时选择 app_ref_req 以避免 tREFI 违规时,必须考虑每个待处理请求的时序参数。为了解决最坏的情况,减去每个BANK机器的 tRCD,CL,数据传输时间 tRP,以确保在 tREFI 到期之前所有事务都可以完成。 (tREFI – (tRCD + ((CL + 4) × tCK) + tRP) × nBANK_MACHS)公式 1-1 显示了 REF 请求间隔的最大值。公式 1-1 在校准后应立即发出用户 REF,以建立确定何时发送后续请求的时间基准。

1.5 Setp By Step搭建FPGA工程

Step1:任单击 IP Catalog,选取 Memory Interface Generator(MIG 7 series)IP 添加到 Block design。双击 MIG 7 SERIES ,对这个 IP 进行配置。


双击生成的IP核

选择Create Design 单击NEXT

选择DDR3 单击NEXT

设置MIG 内核时钟频率、内存型号、内存的数据位宽


设置MIG AXI4 最大支持的位宽


设置输入频率



系统和参考时钟时钟选择no buffer,MIG低电平复位


Step9:终端阻抗选择40hms,设置dci


选择Fixed Pin Out


根据原理图手动填写PIN 脚定义,或者选择Read XDC/UCF直接读入pin脚定义,本课程下提供了DDR 配置文件,直接读入既可。


填写完成后,先单击Validate再单击NEXT


继续单击NEXT


继续单击NEXT


继续单击NEXT


继续单击NEXT


最后单击Generate,至此MIG的配置完成


Step17:右击 Open IP_Example Design...


Step18:设置好 IP 的路径


Step19:创建完成后的代码(mig自带的例子)



1.6 Step By Step修改代码

MIG 控制器官方产生的代码过于复杂,不利于学习,所以笔者将对代码做一些修改,使之适配我们开发板,以及有利于学习和消化。

Step1:修改顶层接口信号,由于开发板的核心板上是 100MHZ 单端时钟,以及复位信号是通过按钮提供,所以修改以下接口,并且增加 clk100m 信号以及 rst_key 信号。


Step2:增加 PLL 时钟管理模块,从 100MHZ 输入,输出 200MHZ 时钟提供给 MIG 系统时钟和系统参考时钟,这个 200MHZ 时钟就是刚才设置的,必须确保一致。


Step3:修补并且增加如下代码

wire sys_rst;

wire locked;

wire clk_ref_i;

wire sys_clk_i;

wire clk_200;

   

assign sys_rst = ~rst_key;//复位信号

assign clk_ref_i = clk_200;//200M的参考时钟

assign sys_clk_i = clk_200;//200M的系统时钟


//时钟管理产生DDR需要的时钟   

clk_wiz_0 CLK_WIZ_DDR( .clk_out1(clk_200),.reset(sys_rst),.locked(locked),.clk_in1(clk100m));

Step4:修改 MIG IP CORE 输入信号如下图红框所示


Step5:添加内存测试的读写逻辑控制代码

// End of User Design top instance

//以下是读写测试       

// End of User Design top instance


parameter    [1:0]IDLE  =2'd0;

parameter    [1:0]WRITE =2'd1;

parameter    [1:0]WAIT  =2'd2;

parameter    [1:0]READ  =2'd3;

parameter    [2:0]CMD_WRITE    =3'd0;

parameter    [2:0]CMD_READ     =3'd1;

parameter    TEST_DATA_RANGE   =24'd1000;//部分测试


(*mark_debug = "true"*) reg   [1 :0]state=0;

reg    [23:0]Count_64=0;// 128M*2*16/256

reg    [ADDR_WIDTH-1:0]app_addr_begin=0;

 (*mark_debug = "true"*) wire    tg_compare_error;


assign    app_wdf_end                     =app_wdf_wren;//两个相等即可

assign    app_en                          =(state==WRITE) ? (app_rdy&&app_wdf_rdy) : ((state==READ)&&app_rdy);

assign    app_wdf_wren                    =(state==WRITE) ? (app_rdy&&app_wdf_rdy) : 1'b0;

assign    app_cmd                         =(state==WRITE) ? CMD_WRITE : CMD_READ;

assign    app_addr                        =app_addr_begin;

assign    app_wdf_data                    ={

                         Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],

                       Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],

                       Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],

                      Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],

                      Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],

                      Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],

                  Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],

                    Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0]

                                             };//写入的数据是计数器


always@(posedge clk)

   if(rst&!init_calib_complete)//

       begin

       state                           <=IDLE;

       app_addr_begin                  <=29'd0;

       Count_64                        <=24'd0;

       end

else case(state)

    IDLE:    begin

       state                            <=WRITE;

       if(app_addr_begin > 100000)

         app_addr_begin                 <=29'd0;

       Count_64                         <=24'd0;

       end

    WRITE:    begin//写整片的DDR3

       state                            <=(Count_64==TEST_DATA_RANGE)&&app_rdy&&app_wdf_rdy ? WAIT:state;//最后一个地址写完之后跳出状态

       Count_64                         <=app_rdy&&app_wdf_rdy?(Count_64+24'd1):Count_64;    

       app_addr_begin                   <=app_rdy&&app_wdf_rdy?(app_addr_begin+29'd16):app_addr_begin;//跳到下一个(8*32=256)bit数据地址

       end

    WAIT:    begin

       state                            <=READ;

       Count_64                         <=24'd0;    

       app_addr_begin                   <=29'd0;    

       end

    READ:    begin//读整片的DDR3

       state                            <=(Count_64==TEST_DATA_RANGE)&&app_rdy? IDLE:state;

       Count_64                         <=app_rdy?(Count_64+24'd1):Count_64;    

       app_addr_begin                   <=app_rdy?(app_addr_begin+29'd16):app_addr_begin;

       end

default:begin

       state                            <=IDLE;

       app_addr_begin                   <=29'd0;

       Count_64                         <=24'd0;

       end        

   endcase


 (*mark_debug = "true"*) (* KEEP = "TRUE" *) reg [63:0]app_rd_data_r;

 (*mark_debug = "true"*) (* KEEP = "TRUE" *) reg app_rd_data_valid_r;

   

always @(posedge clk) begin

  app_rd_data_r <=  app_rd_data[63:0];

  app_rd_data_valid_r <= app_rd_data_valid;

end

       

//16bit count used for comparation

reg [7:0] count_temp;

always @(posedge clk) begin

  if(app_rd_data_valid_r)

     count_temp<= count_temp + 1'b1;

  else if(state==WAIT)count_temp <= 8'd0;

 end


//compare  data read from mig

 (*mark_debug = "true"*) wire [63:0]cm_data;

assign cm_data = {count_temp,count_temp,count_temp,count_temp,count_temp,count_temp,count_temp,count_temp};

assign tg_compare_error=(app_rd_data_valid_r&&(cm_data!=app_rd_data_r));

以上代码实现了往DDR里面写入数据,然后读出比较。以此来检测DDR工作是否正常。

Step6:增加增加debug信号

(*mark_debug = "true"*) (* KEEP = "TRUE" *) reg [63:0]app_rd_data_r;

(*mark_debug = "true"*) (* KEEP = "TRUE" *) reg app_rd_data_valid_r;

(* KEEP = "TRUE" *)确保需要观察的信号不会被优化,(*mark_debug = "true"*)使被定义的型号可以支持在线逻辑分析仪查看。

为了添加调试信号,需要先综合,综合完成后,展开SYNTHESIS 单击Set Up Debug



设置好debug 信号后再进行编译,最后下载到FPGA。

1.7 硬件测试结果



1.8 sim仿真工具进行软件仿真

Step1:修改仿真代码


大约110us左右用户代码开始写数据到DDR。


放大写入的数据为计数值


大约在122us开始从DDR读数据

1

路过

雷人

握手

鲜花

鸡蛋

刚表态过的朋友 (1 人)

发表评论

最新评论

引用 GrandGiant. 2021-1-22 11:19
请问相关的资料在哪里下载呀?
引用 zhang 2019-11-20 15:40
请问顶层文件中的 output init_calib_complete 信号的作用是什么(不是mig)?根据约束文件对应原理图,在核心板原理图中该信号引脚为什么对应的是FLASH IO1?

查看全部评论(2)

本文作者
2019-10-16 09:59
  • 1
    粉丝
  • 6574
    阅读
  • 2
    回复

米联客UIsrc

独家课程 硬核科技

销售电话:18921033576
EMAIL:tjy@uisrc.com
地址:常州溧阳市天目云谷3号楼北楼
热门评论
排行榜