赞
踩
Dq(数据总线)与Dqs(时钟信号)构成随路时钟。
在Dqs上升或下降沿翻转Dq数据总线信号。
注意:dq与dqs为双线信号。两个信号都由发送方发送。dqs为数据同步信号。
ODT引脚:片上终端电阻,数据线接上拉电阻。
DDR外部IO时钟频率与内部存储时钟频率一致。
DDR2外部IO时钟是内部存储时钟频率的两倍。
DDR2在初始化过程中配置模式寄存器前添加新EMRS选项:可选OCD功能。
目的是让DQS与DQ数据信号之间的偏差降低到最小。
DDR2:ODT功能让信号被电路的终端吸收,不会在电路上形成反射对后面信号造成影响。ODT将终结电阻移植到芯片内部。
DDR2中读写指令可以紧随行激活发送,但读写操作没有提前,为了避免造成命令冲突,引入附加潜伏期。
RL(读潜伏期)= AL(附加潜伏期)+CL(列选通潜伏期)
从写入命令发出到第一个数据输入潜伏期 WL(写入潜伏期)=RL-1=AL+CL-1;
SDRAM无AL。
tDQSS:发出写指令到写数据之间的时间。
DDR3可以根据温度变化的自刷新频率。
CL(寻址时序):DDR2 CL:2~5 AL(附加延迟):0 ~4
DDR3 CL:5~11 AL(附加延迟): 0、CL-1、CL-2 CWD(写入延迟):由具体的工作频率而定
DDR3新增重置(Reset)功能: 初始化、重新配置模式寄存器。
ZQ: 该引脚通过命令集指令用相应的时钟周期对导通电阻和ODT电阻进行重新校准。
DDR3中,使用两个参考电压。VREFCA(命令与地址信号)、VREFDQ(数据总线)。
bit (位)
突发长度
DDR_SDRAM(2bit预读): 2 4 8 内部结构导致,从内部总线32位中一次读出至少2个16位数据
DDR2_SDRAM(4bit预读) 4 8 一次至少读出4个16位,2个完整的时钟周期读出
DDR3_SDRAM(8bit预读) 8
使用突发长度时读写只能顺序地址;不使用读写长度时,读写地址可随机但是要连续写指令。
CK,CK_n: 差分信号时钟。 CKE: 高电平使能操作指令,低电平进入休眠自刷新状态。 CS_n: 片选使能信号。高电平使能芯片。 RAS_n\CAS_n\WE_n: 指令输入。 DM(8位)/DMU,DML(16位): 遮掩输入数据使能信号。 BA0-BA2: bank地址。 A10/AP: 使能在读写操作后自动预充电,高电平使能。 A0-A14(8位宽)/A0-A13(16位宽): 地址总线。 A21/BC_n: 默认高电平8bit突发长度,低电平使用突发突变模式(4bit读,4bit写)。 ODT: 高/低电平使能校准功能。由芯片手册决定。 RESET_n: 初始化或稳定工作中复位使能,重新配置模式寄存器。 DQ: 输入输出引脚,数据总线。 DQS,DQS_n(8位宽)/DQSL,DQSL_n,DQSU,DQSU_n(16位宽): 输入输出引脚,数据同步信号。 TDQS,TDQS_n(8位宽): DRAMs输出引脚。数据遮掩信号,与DQS/DQS_n信号相同,在A11引脚控制下DM/TDQS_n可以使用数据遮掩,此时TDQS_n无效。 Vdd.Vddq: 电压引脚。 Vssq,Vss: 接地。 Vrefca: CA参考电压。 Vrefdq: DQ参考电压。 ZQ: 该引脚通过命令集指令用相应的时钟周期对导通电阻和ODT电阻进行重新校准。
PHY to Controller Clock Ratio:
`timescale 1ns / 1ps module ddr_top( input sys_clk, //系统时钟 // DDR3 inout [7:0] ddr3_dq , //DDR3 数据 inout [0:0] ddr3_dqs_n , //DDR3 dqs负 inout [0:0] ddr3_dqs_p , //DDR3 dqs正 output [14:0] ddr3_addr , //DDR3 地址 output [2:0] ddr3_ba , //DDR3 banck 选 output ddr3_ras_n , //DDR3 行选择 output ddr3_cas_n , //DDR3 列选择 output ddr3_we_n , //DDR3 读写选择 output ddr3_reset_n , //DDR3 复位 output [0:0] ddr3_ck_p , //DDR3 时钟正 output [0:0] ddr3_ck_n , //DDR3 时钟负 output [0:0] ddr3_cke , //DDR3 时钟使能 output [0:0] ddr3_cs_n , //DDR3 片选 output [0:0] ddr3_dm , //DDR3_dm output [0:0] ddr3_odt //DDR3_odt ); wire ui_clk ; wire clk_200 ; wire ui_clk_sync_rst ; wire init_done ; wire [28:0] app_addr ; wire [2:0] app_cmd ; wire app_en ; wire [63:0] app_wdf_data ; wire app_wdf_end ; wire app_wdf_wren ; wire [63:0] app_rd_data ; wire app_rd_data_end ; wire app_rd_data_valid ; wire app_rdy ; wire app_wdf_rdy ; wire [31:0] rd_addr_cnt ; wire [31:0] wr_addr_cnt ; wire error_flog ; wire pll_locked ; wire data_state ; reg sys_rst ; reg [31:0] time_cnt ; wire wr_en ; wire rd_en ; wire rst_en ; always @(posedge clk_200) if(!pll_locked) time_cnt <= 32'b0; else if(time_cnt == 32'd600_0) time_cnt <= time_cnt ; else time_cnt <= time_cnt + 1'b1; always @(posedge clk_200) if(!pll_locked) sys_rst <= 1'b1; else if(time_cnt == 32'd600_0) sys_rst <= 1'b0; else sys_rst <= sys_rst; clk_wiz_0 PLL ( .clk_out1(clk_200), // output clk_out1 .locked(pll_locked), // output locked .clk_in1(sys_clk) ); // input clk_in1 vio_0 vio_0_inst ( .clk(ui_clk), // input wire clk .probe_in0(), // input wire [0 : 0] probe_in0 .probe_out0(wr_en), // output wire [0 : 0] probe_out0 .probe_out1(rd_en), // output wire [0 : 0] probe_out1 .probe_out2(rst_en) // output wire [0 : 0] probe_out2 ); ddr3_rw ddr3_rw_inst( .ui_clk (ui_clk) , //用户时钟 参考时钟 IP设置Clock Period 800M, 4:1比例ui_clk=200M (FPGA与DDR3传输数据时钟200M) .sys_rst (ui_clk_sync_rst) , .rst_en (rst_en), .init_done (init_done) , //DDR3初始化完成 .app_rdy (app_rdy) , //IP核命令接收准备完成信号 .app_wr_data_rdy (app_wdf_rdy) , //IP核数据接受准备完成信号 .app_rd_data_valid (app_rd_data_valid) , //IP读数据有效 .app_rd_data (app_rd_data) , //mig读出的数据 [63:0] .wr_en (wr_en) , //写使能 .rd_en (rd_en) , //读使能 .app_addr (app_addr) , //地址 [28:0] .app_en (app_en) , //IP发送命令信号使能 .app_wd_wren (app_wdf_wren) , //写数据使能 .app_wd_end (app_wdf_end) , //写突发当前时钟最后一个数据 .app_cmd (app_cmd) , //读写命令 .app_data_wr (app_wdf_data) , //写数据 [63:0] .rd_addr_cnt (rd_addr_cnt) , //用户读地址计数 [31:0] .wr_addr_cnt (wr_addr_cnt) , //用户写地址计数 [31:0] .error_flog (error_flog) , //读写错误标志 .data_state (data_state) ); mig_7series_0 mig_7series_0_inst ( .ddr3_addr (ddr3_addr), // output [14:0] .ddr3_ba (ddr3_ba), // output [2:0] .ddr3_cas_n (ddr3_cas_n), // output .ddr3_ck_n (ddr3_ck_n), // output [0:0] .ddr3_ck_p (ddr3_ck_p), // output [0:0] .ddr3_cke (ddr3_cke), // output [0: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 [7:0] .ddr3_dqs_n (ddr3_dqs_n), // inout [0:0] .ddr3_dqs_p (ddr3_dqs_p), // inout [0:0] .init_calib_complete (init_done), // output .ddr3_cs_n (ddr3_cs_n), // output [0:0] .ddr3_dm (ddr3_dm), // output [0:0] .ddr3_odt (ddr3_odt), // output [0:0] // Application interface ports .app_addr (app_addr), // input [28:0] .app_cmd (app_cmd), // input [2:0] .app_en (app_en), // input .app_wdf_data (app_wdf_data), // input [63:0] .app_wdf_end (app_wdf_end), // input .app_wdf_wren (app_wdf_wren), // input .app_rd_data (app_rd_data), // output [63: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 该输入被保留并且应该被绑定到0。 .app_ref_req (1'b0), // input 该高电平有效输入请求向DRAM发出刷新命令。 .app_zq_req (1'b0), // input 该高电平有效输入请求向DRAM发出ZQ校准命令。 .app_sr_active (), // output 该输出保留。 .app_ref_ack (), // output 该输出保留。 .app_zq_ack (), // output 该输出保留。 .ui_clk (ui_clk), // output 200M .ui_clk_sync_rst (ui_clk_sync_rst), // output .app_wdf_mask (8'b0), // input [7:0] // System Clock Ports .sys_clk_i (clk_200), //Input Clock Period设置200M,ip核输入200M时钟。 .sys_rst (!sys_rst) // input ); endmodule
`timescale 1ns / 1ps module ddr3_rw( input ui_clk , //用户时钟 参考时钟 input sys_rst , input rst_en , input init_done , //DDR3初始化完成 input app_rdy , //IP核命令接收准备完成信号 input app_wr_data_rdy , //IP核数据接受准备完成信号 input app_rd_data_valid , //IP读数据有效 input [63:0] app_rd_data , //mig读出的数据 [63:0] input wr_en , //写使能 input rd_en , //读使能 output reg [28:0] app_addr , //地址 [28:0] output app_en , //IP发送命令信号使能 output app_wd_wren , //写数据使能 output app_wd_end , //写突发当前时钟最后一个数据 output app_cmd , //读写命令 output reg [63:0] app_data_wr , //写数据 [63:0] output reg [31:0] rd_addr_cnt , //用户读地址计数 [31:0] output reg [31:0] wr_addr_cnt , //用户写地址计数 [31:0] output reg error_flog , //读写错误标志 output reg data_state ); parameter DATA_LENGTH = 32'd1000; parameter IDLE = 3'b000; parameter WRITE = 3'b001; parameter WAIT = 3'b010; parameter READ = 3'b100; reg [2:0] state ; //读写状态 reg [25:0] rd_cnt ; //实际读数据标记 wire rst ; reg error ; ila_0 ila_0_inst ( .clk(ui_clk), // input wire clk .probe0({init_done,app_rdy,app_rd_data_valid,app_rd_data,app_addr,app_en,app_wd_wren,app_wd_end,error_flog,data_state,app_data_wr,rd_cnt,app_wr_data_rdy,app_cmd,state,wr_en,rd_en,wr_addr_cnt,rd_addr_cnt,rst_en,sys_rst,rst,error}) // input wire [399:0] probe0 ); assign rst = rst_en | sys_rst; assign app_en = (((state == WRITE)&&(app_wr_data_rdy&&app_rdy)) ||((state == READ)&&app_rdy)) ? 1'b1:1'b0; assign app_wd_wren = ((state == WRITE)&&(app_wr_data_rdy&&app_rdy)) ? 1'b1:1'b0; assign app_wd_end = app_wd_wren ; assign app_cmd = (state == READ) ? 1'b1:1'b0; always @(posedge ui_clk or posedge rst) if(rst || error_flog) begin state <= IDLE; wr_addr_cnt <= 32'd0; rd_addr_cnt <= 32'd0; app_addr <= 29'd0; app_data_wr <= 64'b0; data_state <= 1'b0 ; end else if(init_done) begin case(state) IDLE : begin if(wr_en) begin state <= WRITE ; end else begin state <= IDLE ; wr_addr_cnt <= 32'd0; rd_addr_cnt <= 32'd0; app_addr <= 29'd0; app_data_wr <= 64'b0; data_state <= 1'b0 ; end end WRITE : begin if(wr_addr_cnt == DATA_LENGTH - 1'b1) state <= WAIT ; else if(app_wr_data_rdy && app_rdy) begin wr_addr_cnt <= wr_addr_cnt + 1'b1; app_addr <= app_addr + 29'd8; app_data_wr <= app_data_wr + 1'b1; data_state <= 1'b1 ; end else begin wr_addr_cnt <= wr_addr_cnt; app_addr <= app_addr ; app_data_wr <= app_data_wr; data_state <= data_state ; end end WAIT : begin if(rd_en) begin state <= READ; app_addr <= 29'b0; end else begin state <= WAIT; app_addr <= app_addr; end end READ : begin if(rd_addr_cnt == DATA_LENGTH - 1'b1) state <= IDLE ; else if(app_rdy) begin rd_addr_cnt <= rd_addr_cnt + 1'b1; app_addr <= app_addr + 29'd8; end else begin rd_addr_cnt <= rd_addr_cnt ; app_addr <= app_addr ; end end default : begin state <= IDLE; wr_addr_cnt <= 32'd0; rd_addr_cnt <= 32'd0; app_addr <= 29'd0; data_state <= data_state ; end endcase end always @(posedge ui_clk or posedge rst) if(rst) rd_cnt <= 26'd0; else if(app_rd_data_valid) begin if(rd_cnt == DATA_LENGTH - 1'b1) rd_cnt <= 26'd0; else rd_cnt <= rd_cnt + 1'b1; end else rd_cnt <= rd_cnt; always @(posedge ui_clk or posedge rst) if(rst) error_flog <= 1'b0; else if((state == READ) && app_rd_data_valid) begin if(rd_cnt != app_rd_data) error_flog <= 1'b1; else error_flog <= 1'b0; end else error_flog <= 1'b0; always @(posedge ui_clk or posedge rst) if(rst) error <= 1'b0; else if(error_flog) error <= 1'b1; else error <= error; endmodule
使用逻辑分析仪查看DDR3写时序。
使用逻辑分析仪查看DDR3读时序。
地址/控制引脚:cs_n,ras_n,we_n等。
字节通道分为T0,T1,T2,T3。每个通道分两小组U和L。
X16和X8型号的dqs:必须在U通道上,必须在N6/N7。
dq:不能在N1,N12,但与dps在同一通道。
dm/dbi:与dqs在同一通道线且只能在N0。
一个Bank只能绑定一组DQ。
reset_n:任何引脚但IO standard必须满足LVCMOS12。
dq低位对应P。高位对应N。dq[0]:p dq[1]:N
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。