本文为明德扬原创及录用文章,转载请注明出处!
1.1 SDRAM简介
SDRAM即同步动态随机存储器,英文为Synchronous Dynamic Random Access Memory;具有容量大、读写速度快、价格相对便宜等优点,但同时控制逻辑比较复杂。
1.1.1 SDRAM示意图
其管脚图如下所示:
	 
 
1.1.2 信号说明
| 
					 信号名  | 
				
					 信号说明  | 
			
| 
					 clk  | 
				
					 SDRAM工作时钟  | 
			
| 
					 cke  | 
				
					 时钟使能信号  | 
			
| 
					 cs_n  | 
				
					 用于屏蔽和使能所有输入端口,但不包括CLK,CKE和DQM,低电平有效  | 
			
| 
					 cas_n  | 
				
					 列地址选通  | 
			
| 
					 ras_na  | 
				
					 行地址选通  | 
			
| 
					 we_n  | 
				
					 写使能,该信号为低时,使能写操作和预充电  | 
			
| 
					 ba  | 
				
					 bank地址  | 
			
| 
					 a  | 
				
					 地址总线  | 
			
| 
					 dqm  | 
				
					 数据掩码  | 
			
| 
					 dq  | 
				
					 数据总线  | 
			
1.1.3 SDRAM中心对齐原则
SDRAM的命令与时钟上升沿是中心对齐的,本设计采用锁相环生成SDRAM工作时钟,SDRAM与初始化模块工作时钟相差180°。这样FPGA产生的信号到SDRAM正好中心对齐,如下图所示:
	
 
1.1.4 SDRAM初始化时序
	
 
SDRAM初始化时序如上图所示,sdr_cmd命令由sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n组合而成;复位后要延时最少100us后才能工作;当A10为高时可以对所有bank进行操作;当到达Tp+3时需要将init_done拉高。
	
 
其模式寄存器配置如上图所示,主要参数设置如下:
a. 模式寄存器的配置是确定SDRAM的工作模式
b. A2、A1、A0用作设置突发长度,本项目设置为4
c. A3用作设置突发类型,本项目设置为Sequential顺序类型
d. A6、A5、A4用作设置列选通潜伏期,本项目设置为3
e. A8、A7设置操作模式,一般为00
f. A9设置写突发模式,本项目为0
g. A12、A11、A10设置为0
1.2 顶层模块设计
1.2.1 SDRAM顶层模块管脚图
	
 
1.2.2 信号说明
| 
					 信号  | 
				
					 说明  | 
			
| 
					 local_addr  | 
				
					 本地地址由行地址列地址bank地址组合而成  | 
			
| 
					 local_data  | 
				
					 写入数据  | 
			
| 
					 local_q  | 
				
					 读出数据  | 
			
| 
					 local_rdreq  | 
				
					 读请求  | 
			
| 
					 local_wrreq  | 
				
					 写请求  | 
			
| 
					 local_reday  | 
				
					 可以进行读写信号  | 
			
| 
					 local_rdata_valid  | 
				
					 读数据有效信号  | 
			
| 
					 init_done  | 
				
					 初始化完成信号  | 
			
| 
					 clk  | 
				
					 输入时钟  | 
			
| 
					 rst_n  | 
				
					 系统复位  | 
			
| 
					 sdr_dq  | 
				
					 SDRAM数据总线,双向端口  | 
			
| 
					 sdr_clk  | 
				
					 SDRAM工作时钟  | 
			
| 
					 sdr_cke  | 
				
					 SDRAM时钟使能  | 
			
| 
					 sdr_cs_n  | 
				
					 片选信号  | 
			
| 
					 sdr_cas_n  | 
				
					 列地址选通  | 
			
| 
					 sdr_ras_n  | 
				
					 行地址选通  | 
			
| 
					 sdr_we_n  | 
				
					 写使能,该信号为低时,使能写操作和预充电  | 
			
| 
					 sdr_ba  | 
				
					 SDRAM bank地址  | 
			
| 
					 sdr_a  | 
				
					 SDRAM地址总线  | 
			
| 
					 sdr_dqm  | 
				
					 数据掩码  | 
			
1.2.3 参考代码
| 
					 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  | 
				
					 module sdram_top( clk , sys_rst_n , //其他信号,举例dout local_addr, local_data, local_q, local_rdreq, local_wrreq, local_reday, local_rdata_vaild, init_done, sdr_cke, sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n, sdr_ba, sdr_a, sdr_dq, sdr_dqm, sdr_clk ); 
 input clk; input sys_rst_n; input [24:0] local_addr; input [63:0] local_data; output [63:0] local_q; input local_rdreq; input local_wrreq; output local_reday; output local_rdata_vaild; output init_done; output sdr_cke; output sdr_cs_n; output sdr_ras_n; output sdr_cas_n; output sdr_we_n; output [1:0] sdr_ba; output [12:0] sdr_a; output [15:0] sdr_dq; output [1:0] sdr_dqm; output sdr_clk; 
 wire phy_clk; wire rst_n; wire [19:0] init_bus; 
 assign {sdr_cke, sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n, sdr_ba, sdr_a} = init_bus; assign sdr_dqm = 2'b00; 
 sdram_init sdram_init_inst( .clk (phy_clk) , .rst_n (rst_n) , //其他信号,举例dout .init_done (init_done) , .init_bus (init_bus) ); 
 my_pll PLL( .areset (~sys_rst_n) , .inclk0 (clk) , .c0 (phy_clk) , .c1 (sdr_clk) , .locked (rst_n) ); 
 endmodule 
  | 
			
1.3 初始化模块设计
1.3.1 SDRAM出计划模块管脚图
	
 
1.3.2 信号说明
| 
					 信号  | 
				
					 说明  | 
			
| 
					 clk  | 
				
					 初始化模块工作时钟(100MHz)  | 
			
| 
					 rst_n  | 
				
					 复位  | 
			
| 
					 init_done  | 
				
					 初始化完成信号  | 
			
| 
					 init_bus  | 
				
					 由SDRAM信号组成  | 
			
1.3.3 参考代码
| 
					 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  | 
				
					 module sdram_init( clk , rst_n , //其他信号,举例dout init_done, init_bus ); 
 //参数定义 parameter DATA_W = 20 ; parameter T100us = 10_000 ; parameter TRP = 2 ; parameter TRFC = 7 ; parameter TMRD = 2 ; parameter NOP = 4'b0111 ; parameter PRE = 4'b0010 ; parameter REF = 4'b0001 ; parameter LMR = 4'b0000 ; parameter CODE = 13'b000_000_011_0010 ; parameter CNT_MAX = 10_021 ; 
 //输入信号定义 input clk ; input rst_n ; 
 //输出信号定义 output init_done ; output[DATA_W-1:0] init_bus ; 
 //输出信号reg定义 reg init_done ; wire [DATA_W-1:0] init_bus ; 
 //中间信号定义 reg [20:0] cnt ; reg sdr_cke ; reg [3:0] sdr_cmd ; reg [1:0] sdr_ba ; reg [12:0] sdr_a ; 
 wire add_cnt ; wire end_cnt ; 
 assign init_bus = {sdr_cke, sdr_cmd, sdr_ba, sdr_a}; 
 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end end 
 assign add_cnt = init_done == 0; assign end_cnt = add_cnt && cnt==CNT_MAX - 1 ; 
 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin sdr_cke <= 1'b0; end else if(add_cnt&&cnt==10_000-1)begin sdr_cke <= 1'b1; end else sdr_cke <= sdr_cke; end 
 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin sdr_cmd <= NOP; end else if(add_cnt&&cnt==10_001-1)begin sdr_cmd <= PRE; end else if(add_cnt&&cnt==10_003-1)begin sdr_cmd <= REF; end else if(add_cnt&&cnt==10_012-1)begin sdr_cmd <= REF; end else if(add_cnt&&cnt==10_019-1)begin sdr_cmd <= LMR; end else if(add_cnt&&cnt==10_020-1)begin sdr_cmd <= NOP; end else begin sdr_cmd <= NOP; end end 
 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin sdr_a <= 13'd0; end else if(add_cnt&&cnt==10_001-1)begin sdr_a[10] <= 1'b1; end else if(add_cnt&&cnt==10_019-1)begin sdr_a <= CODE; end else begin sdr_a <= 13'd0; end end 
 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin init_done <= 1'b0; end else if(add_cnt&&cnt==10_021-1)begin init_done <= 1'b1; end else begin init_done <= init_done; end end 
 endmodule 
  | 
			
1.4 PLL设置
最后对代码进行仿真,modelsim生成的报告如下所示,说明初始化设置成功。
	
 
	
 
以上就是SDRAM控制器初始化设计的思考步骤以及相关代码,更多FPGA资料可以进入明德扬论坛进行学习交流(http://www.fpgabbs.cn/),明德扬专注FPGA设计研究,对FPGA学习感兴趣的朋友快快联系我们吧!
      














