文章目录
- 一.SDRAM简介(手册分析)
- 1.1存储空间
- 1.2特征
- 1.3引脚
- 1.4内部结构
- 1.5需要关注的一些时间
- 1.6模式寄存器
- 1.7命令真值表
- 二.时序分析(手册分析)
- 2.1Avalon时序
- 2.2行激活时序
- 2.3列读写时序
- 2.4读数据
- 2.5写数据
- 三.初步设计
- 3.1状态转移图
- 3.2模块设计图
- 四.操作步骤
- 五.代码
- 六.仿真&效果
- 七.参考
一.SDRAM简介(手册分析)
- SDRAM(同步动态随机存取存储器)。
1.1存储空间
- 本实验中使用的SDRAM存储空间被分为4个bank(如下图就是一个bank),每个bank选定行地址13位,列地址9位可以确定一个存储单元,每个存储单元16bit。那么它的存储空间就是(4 * (2^13) * (2^9) * 16) = 256M(bit)
1.2特征
-
7.8us刷新一行
-
CAS延迟为2或3
-
突发长度和突发延迟控制
(这里先有印象,具体CAS latency,突发长度和突发类型后续会提到)
1.3引脚
1.4内部结构
1.5需要关注的一些时间
1.6模式寄存器
- 那么突发长度是什么意思?所谓翻译为突发不如翻译成连续。那所谓的“突发”就是当我们对一个地址寻址并操作完成后,不用再去寻址,直接进行操作,那么就可以节省下来很多时间
- 突发长度1、2、4、8、全页都是啥意思呢?那经过前面解释突发,就是连续操作多少个数据;至于全页,是每次写入某个bank512个数据(同一个bank,同一个行地址)
1.7命令真值表
二.时序分析(手册分析)
2.1Avalon时序
2.2行激活时序
-
初始化操作完成后,无论读写都要进行行激活(选bank和行地址)
-
CS片选信号:低有效;
-
BA0,BA1:bank寻址;
-
Address中A0-A12:行地址寻址;
-
RAS行选通低,CAS列选通高:进行行选址;
2.3列读写时序
-
行激活操作后,进行列寻址。因为行列地址是复用的,列寻址的地址线仍然是行地址的A0-A12。上文有提到,通过RAS和CAS高低电平来控制Address是行地址还是列地址。
-
CS片选信号:低有效;
-
Adress中A0-A8:列地址寻址;
-
Adress中A10:是否进行预充电;
-
RAS行选通高,CAS列选通低:进行列选址;
-
WE位低:写命令;WE为高读命令;
2.4读数据
- CAS发完后,经过一段时间才有数据输出,我们之前提到过CAS潜伏周期,根据模式寄存器配置,这里延时对应的周期数
2.5写数据
- 注意:写数据是不需要CAS潜伏周期的
三.初步设计
3.1状态转移图
- 手册上的状态图如上,感觉有些乱,个人简化整理了一下
3.2模块设计图
四.操作步骤
-
Tools -> Platform Designer
-
搜索SDRAM并选择
-
配置参数如下
-
相关延时如下
-
时钟设置为100mHz
-
连线和端口命名
-
Generate
五.代码
- sdram_control模块
/**************************************功能介绍***********************************
Date :
Author : Alegg xy.
Version :
Description:
*********************************************************************************///---------<模块及端口声名>------------------------------------------------------
module sdram_control( input clk ,input rst_n ,//写数据// input wr_req ,input [7:0] wr_data ,input wr_data_vld ,//读数据input rd_req , input rd_ready ,//串口发送模块就绪output [7:0] rd_data ,output rd_data_vld ,//clkinput wr_clk ,input rd_clk ,//avalon_masteroutput [23:0] am_addr ,output am_wr_req_n ,output am_rd_req_n ,output [15:0] am_wr_data ,input [15:0] am_rd_data ,input am_rd_data_vld ,output [1:0] am_be_n ,output am_cs ,input am_waitrequest
);
//---------<参数定义>--------------------------------------------------------- //状态机参数定义localparam IDLE = 4'b0001,//WRITE = 4'b0010,//READ = 4'b0100,//DONE = 4'b1000;//reg [3:0] cstate ;//现态reg [3:0] nstate ;//次态wire IDLE_WRITE ;wire IDLE_READ ;wire WRITE_DONE ;wire READ_DONE ;wire DONE_IDLE ;//fifowire wr_fifo_rd_req ;wire [15:0] wr_fifo_rd_data ;wire wr_fifo_empty ;wire wr_fifo_full ;wire [5:0] wr_fifo_usedw ;wire rd_fifo_wr_req ;wire [15:0] rd_fifo_wr_data ;wire rd_fifo_empty ;wire rd_fifo_full ;wire [5:0] rd_fifo_usedw ;//计数器reg [8:0] cnt_burst ;wire add_cnt_burst ;wire end_cnt_burst ;reg [23:0] cnt_wr_addr ;wire add_cnt_wr_addr ;wire end_cnt_wr_addr ;reg [23:0] cnt_rd_addr ;wire add_cnt_rd_addr ;wire end_cnt_rd_addr ;parameter ADDR_MAX = 512,BURST_MAX = 5;
//---------<内部信号定义>-----------------------------------------------------//fifowrfifo wrfifo_inst (.aclr ( ~rst_n ),.data ( wr_data ),.rdclk ( clk ),.rdreq ( wr_fifo_rd_req ),.wrclk ( wr_clk ),.wrreq ( wr_data_vld && ~wr_fifo_full ),.q ( wr_fifo_rd_data ),.rdusedw( wr_fifo_usedw ),.rdempty( wr_fifo_empty ),.wrfull ( wr_fifo_full ));assign wr_fifo_rd_req = add_cnt_wr_addr && ~wr_fifo_empty;rdfifo rdfifo_inst (.aclr ( ~rst_n ),.data ( rd_fifo_wr_data ),.rdclk ( rd_clk ),.rdreq ( rd_data_vld ),.wrclk ( clk ),.wrreq ( rd_fifo_wr_req && ~rd_fifo_full ),.q ( rd_data ),.rdusedw( rd_fifo_usedw ),.rdempty( rd_fifo_empty ),.wrfull ( rd_fifo_full ));assign rd_data_vld = rd_ready && ~rd_fifo_empty ;assign rd_fifo_wr_data = am_rd_data;assign rd_fifo_wr_req = am_rd_data_vld;//第一段:时序逻辑描述状态转移always @(posedge clk or negedge rst_n)begin if(!rst_n)begincstate <= IDLE;end else begin cstate <= nstate;end end//第二段:组合逻辑描述状态转移规律和状态转移条件always @(*) begincase(cstate)IDLE :beginif (IDLE_WRITE) beginnstate = WRITE;endelse if (IDLE_READ) beginnstate = READ;endelse beginnstate = cstate;endendWRITE :beginif (WRITE_DONE) beginnstate = DONE;endelse beginnstate = cstate;endendREAD :beginif (READ_DONE) beginnstate = DONE;endelse beginnstate = cstate;endendDONE :beginif (DONE_IDLE) beginnstate = IDLE;endelse beginnstate = cstate;endenddefault : nstate = IDLE;endcaseendassign IDLE_WRITE = (cstate == IDLE) && wr_fifo_usedw >= BURST_MAX;assign IDLE_READ = (cstate == IDLE) && rd_req;assign WRITE_DONE = (cstate == WRITE) && end_cnt_burst;assign READ_DONE = (cstate == READ) && end_cnt_burst;assign DONE_IDLE = (cstate == DONE) && 1'b1; //突发计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_burst <= 'd0;end else if(add_cnt_burst)begin if(end_cnt_burst)begin cnt_burst <= 'd0;endelse begin cnt_burst <= cnt_burst + 1'd1;end endend assign add_cnt_burst = (cstate == WRITE || cstate == READ) && ~am_waitrequest;assign end_cnt_burst = add_cnt_burst && cnt_burst == BURST_MAX - 1;//地址计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_wr_addr <= 'd0;end else if(add_cnt_wr_addr)begin if(end_cnt_wr_addr)begin cnt_wr_addr <= 'd0;endelse begin cnt_wr_addr <= cnt_wr_addr + 1'd1;end endend assign add_cnt_wr_addr = (cstate == WRITE) && ~am_waitrequest;assign end_cnt_wr_addr = add_cnt_wr_addr && cnt_wr_addr == ADDR_MAX - 1;always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_rd_addr <= 'd0;end else if(add_cnt_rd_addr)begin if(end_cnt_rd_addr)begin cnt_rd_addr <= 'd0;endelse begin cnt_rd_addr <= cnt_rd_addr + 1'd1;end endend assign add_cnt_rd_addr = (cstate == READ) && ~am_waitrequest;assign end_cnt_rd_addr = add_cnt_rd_addr && cnt_rd_addr == ADDR_MAX - 1;//avalon_master时序 assign am_wr_req_n = ~(cstate == WRITE);assign am_rd_req_n = ~(cstate == READ);assign am_addr = (cstate == WRITE) ? cnt_wr_addr : cnt_rd_addr;assign am_wr_data = wr_fifo_rd_data;assign am_be_n = 2'b00;assign am_cs = 1'b1;endmodule
- 顶层模块(这里有用到PLL,需要100mHz时钟)
/**************************************功能介绍***********************************
Date :
Author : Alegg xy.
Version :
Description:
*********************************************************************************///---------<模块及端口声名>------------------------------------------------------
module top( input clk ,input rst_n ,input rx ,output tx ,input [3:0] key_in ,output sdram_clk ,output [12:0] sdram_addr ,output [1:0] sdram_ba ,output sdram_cas_n ,output sdram_cke ,output sdram_cs_n ,inout [15:0] sdram_dq ,output [1:0] sdram_dqm ,output sdram_ras_n ,output sdram_we_n
);
//---------<参数定义>--------------------------------------------------------- //PLLwire clk_50mhz ;wire clk_100mhz ;wire clk_offset ;wire locked ;//key_debouncewire [3:0] key_out ;//uartwire [7:0] wr_data ;wire wr_data_vld ;wire [7:0] rd_data ;wire rd_data_vld ;wire rd_ready ;//controlwire [23:0] am_addr ;wire am_wr_req_n ;wire am_rd_req_n ;wire [15:0] am_wr_data ;wire [15:0] am_rd_data ;wire am_rd_data_vld;wire [1:0] am_be_n ;wire an_cs ;wire am_waitrequest;
//---------<内部信号定义>-----------------------------------------------------pll pll_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0 ( clk_50mhz ),.c1 ( clk_100mhz ),.c2 ( sdram_clk ),.locked ( locked ));key_debounce u_key_debounce(.clk (clk_50mhz),.rst_n (rst_n),.key_in (key_in),.key_out (key_out) );uart_rx u_uart_rx(.clk (clk_50mhz),.rst_n (rst_n),.rx (rx),.rx_data_vld(wr_data_vld),.rx_data (wr_data) );uart_tx u_uart_tx(.clk (clk_50mhz),.rst_n (rst_n),.tx_data (rd_data),.tx_data_vld(rd_data_vld),.ready (rd_ready),.tx (tx) );sdram_control u_sdram_control(.clk (clk_100mhz),.rst_n (rst_n), .wr_data (wr_data),.wr_data_vld (wr_data_vld),.rd_req (key_out[0]),.rd_ready (rd_ready),.rd_data (rd_data),.rd_data_vld (rd_data_vld),.wr_clk (clk_50mhz),.rd_clk (clk_50mhz),.am_addr (am_addr),.am_wr_req_n (am_wr_req_n),.am_rd_req_n (am_rd_req_n),.am_wr_data (am_wr_data),.am_rd_data (am_rd_data),.am_rd_data_vld (am_rd_data_vld),.am_be_n (am_be_n),.am_cs (am_cs),.am_waitrequest (am_waitrequest) );sdram u0 (.avalon_slave_address (am_addr), // avalon_slave.address.avalon_slave_byteenable_n (am_be_n), // .byteenable_n.avalon_slave_chipselect (am_cs), // .chipselect.avalon_slave_writedata (am_wr_data), // .writedata.avalon_slave_read_n (am_rd_req_n), // .read_n.avalon_slave_write_n (am_wr_req_n), // .write_n.avalon_slave_readdata (am_rd_data), // .readdata.avalon_slave_readdatavalid (am_rd_data_vld), // .readdatavalid.avalon_slave_waitrequest (am_waitrequest), // .waitrequest.clk_clk (clk_100mhz), // clk.clk.reset_reset_n (rst_n), // reset.reset_n.sdram_addr (sdram_addr), // sdram.addr.sdram_ba (sdram_ba), // .ba.sdram_cas_n (sdram_cas_n), // .cas_n.sdram_cke (sdram_cke), // .cke.sdram_cs_n (sdram_cs_n), // .cs_n.sdram_dq (sdram_dq), // .dq.sdram_dqm (sdram_dqm), // .dqm.sdram_ras_n (sdram_ras_n), // .ras_n.sdram_we_n (sdram_we_n) // .we_n);
endmodule
六.仿真&效果
- 仿真代码(这里用到了仿真模型)
`timescale 1ns/1nsmodule tb_top();//激励信号定义 reg clk ;reg rst_n ;reg rx ;reg [3:0] key_in ;//输出信号定义 wire tx ;wire sdram_clk ;wire [12:0] sdram_addr ; wire [1:0] sdram_ba ; wire sdram_cas_n ; wire sdram_cke ; wire sdram_cs_n ; wire [15:0] sdram_dq ; wire [1:0] sdram_dqm ; wire sdram_ras_n ; wire sdram_we_n ;wire clk_50mhz ;wire clk_100mhz ;wire clk_offset ;wire locked ;
//时钟周期参数定义 parameter CLOCK_CYCLE = 20; //模块例化top u_top( .clk (clk),.rst_n (rst_n),.rx (rx),.tx (tx),.key_in (key_in),.sdram_addr (sdram_addr ),.sdram_ba (sdram_ba ),.sdram_cas_n (sdram_cas_n),.sdram_cke (sdram_cke ),.sdram_cs_n (sdram_cs_n ),.sdram_dq (sdram_dq ),.sdram_dqm (sdram_dqm ),.sdram_ras_n (sdram_ras_n),.sdram_we_n (sdram_we_n ));assign sdram_clk = clk_offset;sdr u_sdr( .Dq (sdram_dq), .Addr (sdram_addr), .Ba (sdram_ba), .Clk (sdram_clk), .Cke (sdram_cke), .Cs_n (sdram_cs_n), .Ras_n (sdram_ras_n), .Cas_n (sdram_cas_n), .We_n (sdram_we_n), .Dqm (sdram_dqm));pll pll_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0 ( clk_50mhz ),.c1 ( clk_100mhz ),.c2 ( clk_offset ),.locked ( locked ));
//产生时钟initial clk = 1'b0;always #(CLOCK_CYCLE/2) clk = ~clk;integer i;
//产生激励initial begin rst_n = 1'b1;rx = 0;key_in[0] = 1;#(CLOCK_CYCLE*2);rst_n = 1'b0;#(CLOCK_CYCLE*20);rst_n = 1'b1;#2000;//写数据repeat(5)beginfor (i = 0 ; i < 16 ; i = i + 1) beginrx = {$random} % 1;#20;endend//读数据key_in[0] = 0;#(CLOCK_CYCLE * 200);key_in[0] = 1;#10000;$stop;endendmodule
-
仿真模型
https://download.csdn.net/download/weixin_67803687/88445512 -
仿真效果
-
上板效果
七.参考
https://blog.csdn.net/qq_52215423/article/details/132897181