SDRAM读写控制器设计

SDRAM(Synchoronous Dynamic Ramdom Access Memory),即同步动态随机存储器。

DRAM,动态存储器,是异步的

SDRAM特点:1.动态:即他是采用电容来存储数据的,电容会放电,为了保证数据的可靠性,需要不停的给电容冲电,即不断刷新。

2.随机性,即有地址的,行地址和列地址共用一个端口,地址线要使用分时复用。

SDRAM数据存取原理:

N个存储单元构成一个存储阵列(N=行*列),存储阵列又称为逻辑BANK,4个逻辑BANK又构成了整个SDRAM的存储空间。

所以再SDRAM数据存取的时候,首先要确定逻辑BANK地址,然后确定行地址,然后才是确定列地址,才能进行数据的读取。

下面根据镁光数据手册来了解一些重要参数

  1. SDRAM的容量计算表示容量有256Mb,即存储256Mbit的信息,有4位宽,8位宽,16位宽

任务要求:使用串口向SDRAM写入10个字节的数据,再利用串口将这10个字节的数据发送到电脑上。

  1. 绘制框图

确定好整个设计需要哪几个模块,本次设计中用到的有写模块,读模块,初始化模块,刷新模块(给电容充电),仲裁模块(当几个模块发生冲突时,决定哪个优先。)

下面进行各个模块的设计

  1. 初始化模块的设计

给出初始化模块的时序图

由时序图可以知道,上电后先要等待100us的时间,在等待期间必须使用NOP指令,随后执行预充电指令,预充电指令后需要等待TRP的时间,随后进行自刷新指令,自刷新指令后需要等待TRFC时间,(自刷新指令以及之后的等待时间进行2次)随后进行加载寄存器指令,等待tMRD时间,初始化结束。上述等待时间都要进行NOP指令。

给出初始化模块的输入输出:

该模块儿设计采用状态机设计。

初始化模块写完之后要对顶层模块进行编写以供仿真.

  1. 自动刷新模块

自动刷新模块接口图如图所示,这一模块的设计需要引入仲裁模块,即像仲裁模块发出自动刷新请求,仲裁模块返回刷新使能信号后才能进行刷新操作:本次设计中在顶层文件中处理自动刷新请求,并发出刷新使能信号。

自动刷新的时序图:

部分时序图和注意事项

刷新模块代码:

`timescale 1ns / 100ps
//自动刷新模块
module Sdram_auto_refresh (
    input            sys_clk             ,
    input            sys_rst_n           ,
    input            auto_refresh_en     , //仲裁模块返回来的刷新使能信号
    input            init_end            , //初始化模块


    output  reg          auto_refresh_req    , //向仲裁模块发出刷新请求信号
    output  reg [3:0]   auto_refresh_cmd    ,
    output  reg [12:0]  auto_refresh_addr   ,
    output  wire        auto_refresh_end       
);

//定义自刷新模块的几个状态
reg         [2:0]       auto_refresh_state;

parameter    AREF_IDLE           =   3'b000;         //初始化状态,注意向仲裁模块发送请求信号以及接收到使能信号要在初始化模块完成
parameter    AREF_PRE            =   3'b001;         //预充电状态
parameter    AREF_tRP            =   3'b011;         //等待tRP时间状态
parameter    AREF_AUT0_REFRESH   =   3'b010;         //自刷新状态
parameter    AREF_tRFC           =   3'b110;         //等待tRFC时长状态
parameter    AREF_end            =   3'b111;         //自刷新结束状态

//定义几个命令
parameter NOP = 4'b0111; 
parameter PRECHARGE = 4'b0010;
parameter AUTO_REFRESH = 4'b0001;
parameter LOAD_MODE_REGISTER = 4'b0000;

//各个计数器定义
reg          cnt_tRP    ; //tRP维持两个时钟周期
reg  [2:0]   cnt_tRFC   ;  //tRFC维持7个时钟周期
reg  [1:0]   tRFC_time  ;  //自动刷新次数
reg  [9:0]   cnt_Refresh_interval; //每7.5us进行一次刷新,刷新间隔时间计数

//参数定义
parameter cnt_Refresh_interval_MAX = 10'd749; 


//刷新请求
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) cnt_Refresh_interval <= 0;
    else if( cnt_Refresh_interval == cnt_Refresh_interval_MAX) cnt_Refresh_interval <= 0;
    else cnt_Refresh_interval <= cnt_Refresh_interval + 1'd1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) auto_refresh_req <= 0;
    else if( cnt_Refresh_interval == cnt_Refresh_interval_MAX && init_end == 1'd1 ) auto_refresh_req <= 1;
    else auto_refresh_req <= 0;

//几个状态的跳转
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) begin 
                        auto_refresh_addr <= 13'd0;
                        auto_refresh_state <= AREF_IDLE;
    end
    else case(auto_refresh_state)
        AREF_IDLE: begin 
                        if(init_end == 1'd1 && auto_refresh_en == 1)begin
                    auto_refresh_addr[10] <= 1;
                    auto_refresh_state <= AREF_PRE;
                    auto_refresh_cmd <= PRECHARGE;
        end
          end
        AREF_PRE: begin 
                    auto_refresh_state <= AREF_tRP;
                    auto_refresh_cmd <= NOP;
        end
        AREF_tRP:begin
                    if(cnt_tRP == 1) begin 
                                        auto_refresh_state <= AREF_AUT0_REFRESH;
                                        auto_refresh_cmd <= AUTO_REFRESH;
                    end
                    else begin 
                            auto_refresh_state <= auto_refresh_state;
                            auto_refresh_cmd <= NOP;
                    end
        end
        AREF_AUT0_REFRESH:begin 
                auto_refresh_state <= AREF_tRFC;
                auto_refresh_cmd <= NOP;
        end
        AREF_tRFC:begin
                    if(cnt_tRFC == 3'd6 && tRFC_time == 2'd2)  auto_refresh_state <= AREF_end;
                    else if(cnt_tRFC == 3'd6)begin
                            auto_refresh_state <= AREF_AUT0_REFRESH;
                            auto_refresh_cmd <= AUTO_REFRESH;
                        end
                    else begin
                        auto_refresh_state <= auto_refresh_state;
                        auto_refresh_cmd <= NOP;
                    end
                                  
        end
        AREF_end: auto_refresh_state <= AREF_IDLE;
        default : auto_refresh_state <= AREF_IDLE;
    endcase


//cnt_tRP
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) cnt_tRP <= 0;
    else if(cnt_tRP == 1 && auto_refresh_state == AREF_tRP ) cnt_tRP <= 0;
    else if( auto_refresh_state == AREF_tRP ) cnt_tRP <= cnt_tRP+1;
    else cnt_tRP <= cnt_tRP;

//cnt_tRFC
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) cnt_tRFC <= 0;
    else if(cnt_tRFC == 3'd6 && auto_refresh_state == AREF_tRFC ) cnt_tRFC <= 0;
    else if( auto_refresh_state == AREF_tRFC ) cnt_tRFC <= cnt_tRFC+1;
    else cnt_tRFC<= cnt_tRFC;

//tRFC_time,进行2次自动刷新
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) tRFC_time <= 0;
    else if(tRFC_time == 2'd2 && cnt_tRFC == 3'd6) tRFC_time <= 0;
    else if(auto_refresh_state == AREF_AUT0_REFRESH) tRFC_time <= tRFC_time + 1;
    else tRFC_time <= tRFC_time;

//赋值auto_refresh_end
assign auto_refresh_end = (auto_refresh_state == AREF_end ? 1 : 0 );

endmodule

顶层模块:

`timescale 1ns / 100ps
module SDRAM(
    input clk,
    input rst,
    
    output sys_clk,
    output sys_rst_n,
    output CKE,
    output CS,
    output WE,
    output CAS,
    output RAS,
    output [1:0] DQM,
    output [1:0] BA,
    output [12:0] A,

    inout [15:0] DQ

);  //每个端口的意义参见数据手册


//定义SDRAM的工作状态
reg [3:0] SDRAM_STATE;
parameter SDRAM_IDLE             =     3'b000 ;
parameter SDRAM_HANDLE          =     3'b001 ;  //仲裁模块
parameter SDRAM_AUTO_REFRESH     =     3'b011 ;


assign sys_rst_n = rst;

sdram_clk sdram_clk_Inst(
    .areset(!rst),
    .inclk0(clk),
    .c0(sys_clk)
);

wire [3:0] init_cmd;
wire init_end;
wire [12:0] init_addr;


//例化初始化模块
Sdram_Init Sdram_Init_Inst(
        .sys_clk(sys_clk),
       .sys_rst_n(sys_rst_n),
       .init_cmd(init_cmd),
       .init_addr(init_addr),
       .init_end(init_end)
);



//例化自刷新模块
wire [3:0] auto_refresh_cmd;
wire [12:0] auto_refresh_addr;
wire auto_refresh_req;
wire auto_refresh_end;
reg auto_refresh_en;
Sdram_auto_refresh Sdram_auto_refresh_Inst(
        .sys_clk          (sys_clk),
        .sys_rst_n        (sys_rst_n),
        .auto_refresh_en  (auto_refresh_en),
        .init_end         (init_end),
        .auto_refresh_req (auto_refresh_req),
        .auto_refresh_cmd (auto_refresh_cmd),
        .auto_refresh_addr(auto_refresh_addr),
        .auto_refresh_end (auto_refresh_end)            
);


//SDRAM的几个工作状态
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) SDRAM_STATE <= SDRAM_IDLE;
    else case(SDRAM_STATE)
            SDRAM_IDLE:begin
                if(init_end) SDRAM_STATE <= SDRAM_HANDLE;
                else SDRAM_STATE <= SDRAM_STATE;
            end
            SDRAM_HANDLE:begin
                if(auto_refresh_en) SDRAM_STATE <= SDRAM_AUTO_REFRESH;
                else SDRAM_STATE <= SDRAM_STATE;
            end
            SDRAM_AUTO_REFRESH: begin
                    if(auto_refresh_end) SDRAM_STATE <= SDRAM_HANDLE;
                    else SDRAM_STATE <= SDRAM_STATE;
                end
            default:SDRAM_STATE <= SDRAM_IDLE;
    endcase
    
//刷新使能
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) auto_refresh_en <= 0;
    else if(auto_refresh_req)
        auto_refresh_en <= 1;
    else if(auto_refresh_end)
        auto_refresh_en <= 0;
    else auto_refresh_en <= auto_refresh_en;
    
//赋值地址和命令
assign A = (SDRAM_STATE == SDRAM_IDLE ? init_addr : auto_refresh_addr);
assign {CS,RAS,CAS,WE} = (SDRAM_STATE == SDRAM_IDLE ? init_cmd : auto_refresh_cmd);

endmodule

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值