明德扬吴老师 发表于 2020-2-28 12:20:37

【原创分享】基于FPGA的SDRAM控制器设计——初始化设计

本文为明德扬原创及录用文章,转载请注明出处!1.1 SDRAM简介SDRAM即同步动态随机存储器,英文为Synchronous Dynamic Random Access Memory;具有容量大、读写速度快、价格相对便宜等优点,但同时控制逻辑比较复杂。 1.1.1 SDRAM示意图其管脚图如下所示: http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H445E7.png1.1.2 信号说明
信号名信号说明
clkSDRAM工作时钟
cke时钟使能信号
cs_n用于屏蔽和使能所有输入端口,但不包括CLK,CKE和DQM,低电平有效
cas_n列地址选通
ras_na行地址选通
we_n写使能,该信号为低时,使能写操作和预充电
babank地址
a地址总线
dqm数据掩码
dq数据总线
1.1.3 SDRAM中心对齐原则SDRAM的命令与时钟上升沿是中心对齐的,本设计采用锁相环生成SDRAM工作时钟,SDRAM与初始化模块工作时钟相差180°。这样FPGA产生的信号到SDRAM正好中心对齐,如下图所示:http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H534354.png 1.1.4 SDRAM初始化时序http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H544Y2.pngSDRAM初始化时序如上图所示,sdr_cmd命令由sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n组合而成;复位后要延时最少100us后才能工作;当A10为高时可以对所有bank进行操作;当到达Tp+3时需要将init_done拉高。 http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H55cR.png其模式寄存器配置如上图所示,主要参数设置如下:a.       模式寄存器的配置是确定SDRAM的工作模式b.       A2、A1、A0用作设置突发长度,本项目设置为4c.       A3用作设置突发类型,本项目设置为Sequential顺序类型d.       A6、A5、A4用作设置列选通潜伏期,本项目设置为3e.       A8、A7设置操作模式,一般为00f.      A9设置写突发模式,本项目为0g.       A12、A11、A10设置为0 1.2 顶层模块设计1.2.1 SDRAM顶层模块管脚图http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H6111H.png 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_dqSDRAM数据总线,双向端口
sdr_clkSDRAM工作时钟
sdr_ckeSDRAM时钟使能
sdr_cs_n片选信号
sdr_cas_n列地址选通
sdr_ras_n行地址选通
sdr_we_n写使能,该信号为低时,使能写操作和预充电
sdr_baSDRAM bank地址
sdr_aSDRAM地址总线
sdr_dqm数据掩码
1.2.3 参考代码
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071module 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 local_addr;         input local_data;         output 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 sdr_ba;         output sdr_a;         output sdr_dq;         output sdr_dqm;         output sdr_clk;
         wire phy_clk;         wire rst_n;         wire 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出计划模块管脚图 http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H624146.png 1.3.2 信号说明
信号说明
clk初始化模块工作时钟(100MHz)
rst_n复位
init_done初始化完成信号
init_bus由SDRAM信号组成
1.3.3 参考代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124module 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;    outputinit_bus   ;
    //输出信号reg定义    reg               init_done;    wireinit_bus   ;
    //中间信号定义    reg         cnt      ;    reg               sdr_cke    ;    reg            sdr_cmd    ;    reg            sdr_ba   ;    reg         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 <= 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生成的报告如下所示,说明初始化设置成功。http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H63I24.png http://www.mdy-edu.com/uploads/allimg/200226/1-2002261H64GV.png 以上就是SDRAM控制器初始化设计的思考步骤以及相关代码,更多FPGA资料可以进入明德扬论坛进行学习交流(http://www.fpgabbs.cn/),明德扬专注FPGA设计研究,对FPGA学习感兴趣的朋友快快联系我们吧!
页: [1]
查看完整版本: 【原创分享】基于FPGA的SDRAM控制器设计——初始化设计