1.DDR2
Nexys4 DDR开发板提供的DDR2 SDRAM的大小为128MiB;
2.MIG IP核
DDR2 SDRAM在读、写操作过程中需要进行初始化、刷新、预充电、激活等操作,Xilinx为用户提供了IP核MIG,自动完成DDR2初始化等基本操作,其工作模式为突发传输,突发长度可设置为4或8。
2.1核心架构
信号线可以分成两部分:以app_为前缀的信号信号线与User FPGA Logic进行交互;以ddr_为前缀的信号负责与DDR2 SDRAM进行交互。
比较重要的几个控制信号为app_en,app_addr,app_cmd,app_wdf_data,app_wdf_wren,app_wdf_end,app_rdy,app_wdf_rdy;
这些信号负责控制数据的读写。
读时序
写时序
注意:这里的时钟clk需要使用MIS的输出信号ui_clk,这样才能生成正确的读写时序
2.2 IP核的配置
1)关于IP核的配置,XIlinx提供一个图形化的界面,如下图所示。
2)输入Component Name
3)选择要兼容的设备
4)Clock Period选择Digilent推荐的3077ps,Memory Part选择开发板参考手册中的ddr2芯片型号
5)Input Clock Period选择100MHz,RTT选择50ohms
6)System Clock与Reference Clock选择No Buffer,勾选Internal Vref
7)Internal Termination Impedance选择50 ohms
8)选择Fixed Pin Out
9)Pin Selection中选择Read XDC/UCF,加载从Digilent官网下载的UCF文件来对管脚进行配置
10)接下来一路NEXT
MIG IP核的配置参数是参考下图Digilent推荐的配置参数。
3.DDR2仿真
3.1仿真模型
DDR2在VIVADO上仿真需要去下载相应的仿真模型,以模拟出ddr2的存储环境。
Nexys4 DDR使用的内存芯片为MICRON的MT47H64M16HR-25E,需要去厂商官网下载仿真模型,下载地址为:https://www.micron.com/parts/dram/ddr2-sdram/mt47h64m16hr-25e。需要用到的文件为ddr2_model.v。
3.2仿真例子
4.连续读写测试
过程:先向ddr中连续写入10个数据,然后再依次将数据读出来。
5.参考代码
ddr2写控制
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2018/07/23 20:29:22
// Design Name:
// Module Name: ddr2_write_control
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
// ddr2写入控制
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module ddr2_write_control(
clk_in,
rst_n,
ADDR_I,
DATA_I,
STB_I,
ACK_O,
read_en,
//ddr_ signals
app_en,
app_wdf_wren,
app_wdf_end,
app_cmd,
app_addr,
app_wdf_data,
app_rdy,
app_wdf_rdy
);
parameter DQ_WIDTH = 16;
parameter ECC_TEST = "OFF";
parameter ADDR_WIDTH = 27;
parameter nCK_PER_CLK = 4;
localparam DATA_WIDTH = 16;
localparam PAYLOAD_WIDTH = (ECC_TEST == "OFF") ? DATA_WIDTH : DQ_WIDTH;
localparam APP_DATA_WIDTH = 2 * nCK_PER_CLK * PAYLOAD_WIDTH; //突发长度为8
localparam APP_MASK_WIDTH = APP_DATA_WIDTH / 8;
input clk_in;
input rst_n;
input [26:0] ADDR_I; //读取地址、偏移
input [127:0] DATA_I; //需要写入的数据
input STB_I; //选通信号
output reg ACK_O; //可以接收数据标志位,高有效
output reg read_en;
// Wire declarations
output reg app_en, app_wdf_wren, app_wdf_end;
output reg [2:0] app_cmd;
output reg [ADDR_WIDTH-1:0] app_addr;
output reg [APP_DATA_WIDTH-1:0] app_wdf_data;
input app_rdy, app_wdf_rdy;
//生成写入数据的信号值
//----------FSM--------
reg [2:0] cstate;
parameter IDLE = 3'b001;
parameter WRITE = 3'b010;
reg [3:0] write_count;
always @(posedge clk_in)
begin
if(rst_n) begin
app_cmd <= 3'b1;
app_en <= 1'b0;
app_wdf_data <= 128'h0;
app_addr <= 27'h0;
app_wdf_end <= 1'b0;
app_wdf_wren <= 1'b0;
write_count <= 0;
read_en <= 0;
ACK_O <= 0;
cstate <= IDLE;
end
else if(STB_I) begin
case(cstate)
IDLE:begin
if(app_rdy & app_wdf_rdy) begin
app_wdf_data <= DATA_I;
app_cmd <= 3'b0;
app_addr <= ADDR_I;
app_wdf_wren <= 1'b1;
app_wdf_end <= 1'b1;
app_en <= 1'b1;
ACK_O <= 0; //可以接收数据
write_count <= write_count + 1;
cstate <= WRITE;
end
else cstate <= IDLE;
end
WRITE:begin
app_en <= 1'b0;
app_cmd <= 3'b1;
ACK_O <= 1;
app_wdf_wren <= 1'b0;
app_wdf_end <= 0;
if(write_count == 3)
read_en <= 1;
cstate <= IDLE;
end
default:cstate <= IDLE;
endcase
end
else begin
app_en <= 0;
app_wdf_wren <= 0;
app_wdf_end <= 0;
ACK_O <= 0;
cstate <= IDLE;
end
end
endmodule
ddr2读控制
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2018/07/23 20:32:16
// Design Name:
// Module Name: ddr2_read_control
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module ddr2_read_control(
clk_in,
rst_n,
enable,
//ddr2_signal
app_en,
app_cmd,
app_addr,
app_rd_data,
app_rdy,
app_rd_data_end,
app_rd_data_valid
);
input clk_in;
input rst_n;
input enable;
output reg app_en;
output reg [2:0] app_cmd;
output reg [26:0] app_addr;
input [127:0] app_rd_data;
input app_rdy;
input app_rd_data_end;
input app_rd_data_valid;
reg [26:0] app_addr_tmp;
//读取FSM
reg [4:0] cstate;
localparam IDLE = 5'b0_0001;
localparam READ = 5'b0_0010;
localparam WAIT = 5'b0_0100;
localparam ADDR_ACCUMULATE = 5'b0_1000;
localparam WAIT_FOR_CONFIG = 5'b1_0000;
always @(posedge clk_in)
begin
if(rst_n) begin
app_en <= 0;
app_addr_tmp <= 27'h0;
cstate <= IDLE;
end
else if(enable) begin
case(cstate)
IDLE:begin
app_en <= 1;
app_addr <= app_addr_tmp;
app_cmd <= 3'b001;
cstate <= READ;
end
READ:begin
if(app_rdy) begin
app_en <= 1'b0;
app_addr_tmp <= app_addr_tmp + 27'h8;
cstate <= IDLE;
end
end
default:cstate <= IDLE;
endcase
end
end
endmodule
github代码地址:https://github.com/juxiping/ddr2_write_read