当前位置:   article > 正文

DDR2/3 SDRAM学习笔记_随路时钟

随路时钟

随路时钟概念

Dq(数据总线)与Dqs(时钟信号)构成随路时钟。
在Dqs上升或下降沿翻转Dq数据总线信号。
注意:dq与dqs为双线信号。两个信号都由发送方发送。dqs为数据同步信号
在这里插入图片描述
ODT引脚:片上终端电阻,数据线接上拉电阻

DDR与DDR2区别

时钟

DDR外部IO时钟频率与内部存储时钟频率一致。
DDR2外部IO时钟是内部存储时钟频率的两倍。

片外驱动调校(OCD)

DDR2在初始化过程中配置模式寄存器前添加新EMRS选项:可选OCD功能。
目的是让DQS与DQ数据信号之间的偏差降低到最小。

片内终结(ODT)

DDR2:ODT功能让信号被电路的终端吸收,不会在电路上形成反射对后面信号造成影响。ODT将终结电阻移植到芯片内部。
在这里插入图片描述

前置CAS、附加潜伏期、写入潜伏期

DDR2中读写指令可以紧随行激活发送,但读写操作没有提前,为了避免造成命令冲突,引入附加潜伏期。

RL(读潜伏期)= AL(附加潜伏期)+CL(列选通潜伏期)
从写入命令发出到第一个数据输入潜伏期  WL(写入潜伏期)=RL-1=AL+CL-1;
SDRAM无AL。
  • 1
  • 2
  • 3

在这里插入图片描述
tDQSS:发出写指令到写数据之间的时间。
在这里插入图片描述

DDR2与DDR3区别

DDR3可以根据温度变化的自刷新频率。

参数

CL(寻址时序):DDR2 CL:2~5	  AL(附加延迟):0 ~4
			 DDR3 CL:5~11    AL(附加延迟): 0、CL-1、CL-2   CWD(写入延迟):由具体的工作频率而定
  • 1
  • 2

引脚

DDR3新增重置(Reset)功能: 初始化、重新配置模式寄存器。
ZQ: 该引脚通过命令集指令用相应的时钟周期对导通电阻和ODT电阻进行重新校准。
  • 1
  • 2

参考电压信号VREF

DDR3中,使用两个参考电压。VREFCA(命令与地址信号)、VREFDQ(数据总线)。

预读概念

bit (位)

			           突发长度		
DDR_SDRAM(2bit预读): 2   4   8	   内部结构导致,从内部总线32位中一次读出至少216位数据
DDR2_SDRAM(4bit预读) 4       8     一次至少读出416位,2个完整的时钟周期读出
DDR3_SDRAM(8bit预读)         8
  • 1
  • 2
  • 3
  • 4

使用突发长度时读写只能顺序地址;不使用读写长度时,读写地址可随机但是要连续写指令。
在这里插入图片描述

在这里插入图片描述

DDR3主要引脚

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电阻进行重新校准。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

vivado IP核DDR3 SDRAM设置

在这里插入图片描述
在这里插入图片描述

PHY to Controller Clock Ratio:在这里插入图片描述

DDR3读写实验

DDR3模块设计

在这里插入图片描述

DDR3时序设计

在这里插入图片描述

DDR3顶层模块代码

`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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158

DDR3读写模块代码

`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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181

DDR3读写实际波形

使用逻辑分析仪查看DDR3写时序。
在这里插入图片描述使用逻辑分析仪查看DDR3读时序。
在这里插入图片描述

DDR4 IP 时钟

在这里插入图片描述

vivado IP核PLL设置

请添加图片描述
请添加图片描述
在这里插入图片描述

X16 DDR4芯片引脚选址

在这里插入图片描述
地址/控制引脚: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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/696270
推荐阅读
相关标签
  

闽ICP备14008679号