【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化

这篇具有很好参考价值的文章主要介绍了【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在FPGA中,大规模数据的存储常常会用到DDR。为了方便用户使用,Xilinx提供了DDR MIG IP核,用户能够通过AXI接口进行DDR的读写访问,然而MIG内部自动实现了许多环节,不利于用户深入理解DDR的底层逻辑。
【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化,# Xilinx入门,# Verilog入门,# DDR,fpga开发,Verilog,ddr,Xilinx,AMD

本文以美光(Micron)公司生产的DDR3芯片MT41J512M8RH-093为例,说明DDR芯片的操作过程。
【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化,# Xilinx入门,# Verilog入门,# DDR,fpga开发,Verilog,ddr,Xilinx,AMD

该芯片的datasheet可以从厂商官网下载得到:(https://www.micron.com/-/media/client/global/documents/products/data-sheet/dram/ddr3/4gb_ddr3l.pdf?rev=305217e2f9bd4ef48d7c6f353dfc064c),这个datasheet包含了Micron公司多款DDR芯片,这里MT41J512M8RH-093芯片对应数据位宽×8,总容量4G(512M×8),频率2133(-093)的产品,在表格中需要注意区分,不同产品在时序参数上会有所区别。
【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化,# Xilinx入门,# Verilog入门,# DDR,fpga开发,Verilog,ddr,Xilinx,AMD

DDR芯片的使用关键在于令接口的信号变化满足时序要求,在初始化过程中主要关注下面几个时序参数(来自P33 Table 9: Timing Parameters Used for IDD Measurements – Clock Units与P96 Table 59: Electrical Characteristics and AC Operating Conditions for Speed Extensions (Continued))

* CK(MIN)   0.938 ns
* CL        14 CK
* RCD(MIN)  14 CK
* RC(MIN)   50 CK
* RAS(MIN)  36 CK
* RP(MIN)   14 CK
* FAW       27 CK
* RRD       6  CK
* RFC       279CK
* XPR       > max(5CK, RFC+10ns)
* MRD       > 4 CK
* MOD       > max(12 CK, 15ns)
* ZQinit    < max(512nCK, 640ns)
* DLLK      > 512 CK

从datasheet的P12页的Fig2. Simplified State Diagram可以看到,DDR3芯片在上电(Power applied)后需要经过一系列的初始化步骤(主要包含三个部分Reset Procedure、Initialization、ZQ Calibration),之后进入正常工作状态(idle)。
【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化,# Xilinx入门,# Verilog入门,# DDR,fpga开发,Verilog,ddr,Xilinx,AMD

上图中Command由多个信号的变化构成,在初始化过程主要用到以下几个指令。(来自P118 Table 70: Truth Table – Command)

* COMMAND     | NOP | MRS_1 | MRS_2 | MRS_3 | MRS_4 | ZQCL             
* ddr_cke     | 1 1 |  1 1  |  1 1  |  1 1  |  1 1  |  1 1   
* ddr_dqs_en  |  0  |   0   |   0   |   0   |   0   |   0    
* ddr_dq_en   |  0  |   0   |   0   |   0   |   0   |   0     
* ddr_cs_n    |  0  |   0   |   0   |   0   |   0   |   0     
* ddr_ras_n   |  1  |   0   |   0   |   0   |   0   |   1    
* ddr_cas_n   |  1  |   0   |   0   |   0   |   0   |   1    
* ddr_we_n    |  1  |   0   |   0   |   0   |   0   |   0    
* ddr_ba      | vvv |  010  |  011  |  001  |  000  |  000   
* ddr_addr    | vvv |   28  |   00  |   44  |  124  | a[10]=1      
* ddr_odt     |  0  |   0   |   0   |   0   |   0   |   0   

这里将时钟周期取为最小时钟周期0.938ns,对应时钟频率1066.099MHz。经过计算,Initialization阶段每条指令执行后的等待时间均不超过1us,因此这里将Initialization阶段每条指令执行后的等待时间均简化1us,最终得到的DDR3初始化代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: wjh776a68
// 
// Create Date: 01/05/2024 09:45:15 AM
// Design Name: micron_ddr
// Module Name: micron_ddr_init
// Project Name: micron_ddr
// Target Devices: vu9p
// Tool Versions: 2017.4
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

// ddr3 x8 4Gb MT41J512M8RH-093
/****************************
*  DDR3L-2133 https://www.micron.com/-/media/client/global/documents/products/data-sheet/dram/ddr3/4gb_ddr3l.pdf?rev=305217e2f9bd4ef48d7c6f353dfc064c
* CK(MIN) 0.938 ns
* CL        14 CK
* RCD(MIN)  14 CK
* RC(MIN)   50 CK
* RAS(MIN)  36 CK
* RP(MIN)   14 CK
* FAW       27 CK
* RRD       6  CK
* RFC       279CK
* XPR       >max(5CK, RFC+10ns)
* MRD       >4CK
* MOD       >max(12CK, 15ns)
* ZQinit    <max(512nCK, 640ns)
* DLLK      >512CK
* command all p118
* initial waveform p137
*
* COMMAND     | NOP | MRS_1 | MRS_2 | MRS_3 | MRS_4 | ZQCL             
* ddr_cke     | 1 1 |  1 1  |  1 1  |  1 1  |  1 1  |  1 1   
* ddr_dqs_en  |  0  |       |       |       |       |        
* ddr_dq_en   |  0  |       |       |       |       |         
* ddr_cs_n    |  0  |   0   |   0   |   0   |   0   |   0     
* ddr_ras_n   |  1  |   0   |   0   |   0   |   0   |   1    
* ddr_cas_n   |  1  |   0   |   0   |   0   |   0   |   1    
* ddr_we_n    |  1  |   0   |   0   |   0   |   0   |   0    
* ddr_ba      | vvv |  010  |  011  |  001  |  000  |         
* ddr_addr    | vvv |   28  |   00  |   44  |  124  |  a[10]      
* ddr_odt     |  0  |       |       |       |       |        
***************************************************************/
module micron_ddr_init #(
    parameter CLK_FREQ = 1066.099, // MHz
    parameter _1MS_CYCLE = 10.0**-3 / (1.0 / (CLK_FREQ * 10**6)),
    parameter _1US_CYCLE = 10.0**-6 / (1.0 / (CLK_FREQ * 10**6)),
    parameter integer INITIAL_CYCLE = 200 * _1US_CYCLE,
    parameter integer INITIAL_STABLE_CYCLE = 500 * _1US_CYCLE,
    parameter integer FREE_CYCLE = _1US_CYCLE
) (
    output  reg [15:0]  ddr_addr,
    output  reg [2:0]   ddr_ba,
    output  reg         ddr_cas_n,
    output  reg [0:0]   ddr_ck_n,
    output  reg [0:0]   ddr_ck_p,
    output  reg [0:0]   ddr_cke,
    output  reg [0:0]   ddr_cs_n,
    output  reg [0:0]   ddr_dm,
    inout       [7:0]   ddr_dq,
    inout       [0:0]   ddr_dqs_n,
    inout       [0:0]   ddr_dqs_p,
    output  reg [0:0]   ddr_odt,
    output  reg         ddr_ras_n,
    output  reg         ddr_reset_n,
    output  reg         ddr_we_n,

    input clk

);

localparam [27:0] NOP_CMD =  {11'b11000111000, 16'h0000, 1'b0};
localparam [27:0] MRS1_CMD = {11'b11000000010, 16'h0028, 1'b0};
localparam [27:0] MRS2_CMD = {11'b11000000011, 16'h0000, 1'b0};
localparam [27:0] MRS3_CMD = {11'b11000000001, 16'h0044, 1'b0};
localparam [27:0] MRS4_CMD = {11'b11000000000, 16'h0124, 1'b0};
localparam [27:0] ZQCL_CMD = {11'b11000110000, 16'h0400, 1'b0};

reg ddr_cke_p1, ddr_cke_p2;
reg ddr_dqs_i, ddr_dqs_o, ddr_dqs_en;
reg ddr_dq_i, ddr_dq_o, ddr_dq_en;

    OBUFDS OBUFDS_ck (
      .O(ddr_ck_p),   // 1-bit output: Diff_p output (connect directly to top-level port)
      .OB(ddr_ck_n), // 1-bit output: Diff_n output (connect directly to top-level port)
      .I(clk)    // 1-bit input: Buffer input
   );
   
   IOBUFDS #(
      .DQS_BIAS("FALSE")  // (FALSE, TRUE)
   )
   IOBUFDS_dqs_inst (
      .O(ddr_dqs_o),     // 1-bit output: Buffer output
      .I(ddr_dqs_i),     // 1-bit input: Buffer input
      .IO(ddr_dqs_p),   // 1-bit inout: Diff_p inout (connect directly to top-level port)
      .IOB(ddr_dqs_n), // 1-bit inout: Diff_n inout (connect directly to top-level port)
      .T(ddr_dqs_en)      // 1-bit input: 3-state enable input
   );
   
   IOBUF IOBUF_dq_inst (
     .O(ddr_dq_o),   // 1-bit output: Buffer output
     .I(ddr_dq_i),   // 1-bit input: Buffer input
     .IO(ddr_dq), // 1-bit inout: Buffer inout (connect directly to top-level port)
     .T(ddr_dq_en)    // 1-bit input: 3-state enable input
  );
  
  ODDRE1 #(
      .IS_C_INVERTED(1'b1),  // Optional inversion for C
      .IS_D1_INVERTED(1'b0), // Unsupported, do not use
      .IS_D2_INVERTED(1'b0), // Unsupported, do not use
      .SRVAL(1'b0)           // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
   )
   ODDRE1_cke_inst (
      .Q(ddr_cke),   // 1-bit output: Data output to IOB
      .C(clk),   // 1-bit input: High-speed clock input
      .D1(ddr_cke_p1), // 1-bit input: Parallel data input 1
      .D2(ddr_cke_p2), // 1-bit input: Parallel data input 2
      .SR(1'b0)  // 1-bit input: Active High Async Reset
   );

//OBUFDS OBUFDS_dqs (
//      .O(ddr_dqs_p),   // 1-bit output: Diff_p output (connect directly to top-level port)
//      .OB(ddr_dqs_n), // 1-bit output: Diff_n output (connect directly to top-level port)
//      .I(ddr_dqs)    // 1-bit input: Buffer input
//   );

    reg [15:0]  ddr_addr_r;
    reg [2:0]   ddr_ba_r;
    reg         ddr_cas_n_r;
    reg [0:0]   ddr_cs_n_r;
    reg [0:0]   ddr_dm_r; // no ref
    reg [0:0]   ddr_odt_r;
    reg         ddr_ras_n_r;
    reg         ddr_we_n_r;
    reg         ddr_dq_en_r; 
    reg         ddr_dqs_en_r; 
    
   initial begin
       {ddr_cke_p2, ddr_cke_p1, ddr_dqs_en, ddr_dq_en, ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n, ddr_ba, ddr_addr, ddr_odt} <= NOP_CMD;
       {ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= NOP_CMD;
   end

    always @(negedge clk) begin
        ddr_addr  <=  ddr_addr_r  ;
        ddr_ba      <=  ddr_ba_r    ;
        ddr_cas_n  <=  ddr_cas_n_r ;
        ddr_cs_n  <=  ddr_cs_n_r  ;
        ddr_dm      <=  ddr_dm_r    ;
        ddr_odt      <=  ddr_odt_r   ;
        ddr_ras_n  <=  ddr_ras_n_r ;
        ddr_we_n  <=  ddr_we_n_r  ;
        ddr_dq_en   <=  ddr_dq_en_r;
        ddr_dqs_en  <=  ddr_dqs_en_r;

    end


   reg [5:0] cs = 0, ns;
   reg [31:0]  initial_cnt = 0;
   reg [31:0]  initial_stable_cnt = 0;
   reg [31:0]  freerun_cnt = 0;
   reg [3:0]   initial_cmd_ptr = 0;
   reg [27:0] initial_cmd_seq[0:5] = '{NOP_CMD, MRS1_CMD, MRS2_CMD, MRS3_CMD, MRS4_CMD, ZQCL_CMD};
   reg initial_finish = 0;

   always @(negedge clk) begin
       cs <= ns;
   end

   always @(*) begin
       case (cs)
       0: begin
           if (initial_cnt == INITIAL_CYCLE) begin // wait 200us
               ns = 1;
           end else begin
               ns = 0;
           end
       end
       1: begin // wait 500us 
           if (initial_stable_cnt == INITIAL_STABLE_CYCLE) begin // wait 500us
               ns = 2;
           end else begin
               ns = 1;
           end
       end
       2: begin
           ns = 3;
       end
       3: begin
           if (freerun_cnt == FREE_CYCLE) begin
               if (initial_finish) begin
                   ns = 4;
               end else begin
                   ns = 2;
               end
           end else begin
               ns = 3;
           end
       end
       4: begin
           // finish initial, enter idle state
       end
       default: begin
           ns = 0;
       end
       endcase
   end

   always @(negedge clk) begin
       case (ns)
       0: begin
           initial_cnt <= initial_cnt + 1;
       end
       default: begin
           initial_cnt <= 0;
       end
       endcase
   end

   always @(negedge clk) begin
       case (ns)
       1: begin
           initial_stable_cnt <= initial_stable_cnt + 1;
       end
       default: begin
           initial_stable_cnt <= 0;
       end
       endcase
   end

   always @(negedge clk) begin
       case (ns)
       3: begin
           freerun_cnt <= freerun_cnt + 1;
       end
       default: begin
           freerun_cnt <= 0;
       end
       endcase
   end

   always @(negedge clk) begin
       case (ns)
       2: begin
           if (initial_cmd_ptr == 6 - 1) begin
               initial_finish <= 1;
           end else begin
               initial_finish <= 0;
           end
           initial_cmd_ptr <= initial_cmd_ptr + 1;
       end
       endcase
   end


   always @(negedge clk) begin
       case (ns)
       0: begin
           ddr_reset_n <= 1'b0;
           {ddr_cke_p2, ddr_cke_p1}    <= 2'b0;
           ddr_dqs_en_r <= 1'b0;
           ddr_dq_en_r  <= 1'b0;
       end
       1: begin
           ddr_reset_n <= 1'b1;
           {ddr_cke_p2, ddr_cke_p1}    <= 2'b0;
           ddr_dqs_en_r <= 1'b0;
           ddr_dq_en_r <= 1'b0;
       end
       2: begin
           {ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= initial_cmd_seq[initial_cmd_ptr];
       end
       3: begin
           {ddr_cke_p2, ddr_cke_p1, ddr_dqs_en_r, ddr_dq_en_r, ddr_cs_n_r, ddr_ras_n_r, ddr_cas_n_r, ddr_we_n_r, ddr_ba_r, ddr_addr_r, ddr_odt_r} <= NOP_CMD;
       end
       default: begin
           ddr_reset_n <= 1'b1;
       end
       endcase
   end


endmodule

上述代码已在Vivado 2017.4中进行了仿真测试,可替换ddr示例工程中的example_top自行仿真。
【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化,# Xilinx入门,# Verilog入门,# DDR,fpga开发,Verilog,ddr,Xilinx,AMD
下一节 【DDR】基于Verilog的DDR控制器的简单实现(二)——写操作文章来源地址https://www.toymoban.com/news/detail-786660.html

到了这里,关于【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于FPGA的4x4矩阵键盘控制器verilog开发实现

    欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 目录 一、理论基础 二、核心程序 三、测试结果        基于FPGA的4x4矩阵键盘控制器是一种使用FPGA(现场可编程门阵列)来实现对4x4矩阵键盘进行控制的设备。该控制器能够有效地降低硬件资源的使用,提高系

    2024年02月11日
    浏览(51)
  • 基于AHB协议的SRAM控制器的Verilog实现(详解代码)(一)——sram_core的实现

    目录  一、sramc(sram_controller)的总框架和模块划分 Features of sramc 结构框图和信号描述 二、sram_core的Verilog实现 动手开敲前的构思 Verilog代码和代码分析 三、sram_core的仿真验证 下载链接 sram因为其高读写速度常常作为CPU和嵌入式IC的缓存,是一个数字系统中必不可少的存在,因此

    2024年01月16日
    浏览(49)
  • 【FPGA】十三、Vivado MIG IP核实现DDR3控制器(1)

    文章目录 前言 一、DDR3基础知识 二、MIG  IP核的配置 三、DDR3 IP核用户端接口时序 1、DDR3 IP核接口说明 2、DDR3 IP核读写时序 ① 写命令时序:  ② 写数据时序:  ③ 读数据时序: 总结         我们在进行FPGA开发应用当中,经常会用到存储器来保存数据,常用的存储器有RO

    2024年02月16日
    浏览(82)
  • m基于FPGA的FOC控制器verilog实现,包括CLARK,PARK,PID及SVPWM,含testbench

    目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件 Quartus II 12.1(64-Bit) ModelSim-Altera 6.6d Starter Edition 仿真结果如下: 整个系统的结构如下所示: 1、采集到两相电流 2、经过clarke变换后得到两轴正交电流量, 3、经过旋转变换后得到正交的电流量

    2024年02月15日
    浏览(53)
  • 基于FPGA的电风扇控制器verilog,视频/代码

    名称:基于FPGA的电风扇控制器verilog 软件:QuartusII 语言:Verilog 代码功能: 基于FPGA的电风扇控制器  运用 EDA SOPO实验开发系统设计一个基于FPGA的电风扇定时开关控制器,能实现手动和自动模式之间的切换。要求:  (1)KI为电源开关由电源开关控制电风扇的开关,即当K1为高电平“

    2024年02月07日
    浏览(55)
  • verilog实现I2C控制器 (小梅哥思路)----详细解析

    模块框图如下所示 输入输出信号: 整体的思路如下: 通过输入的命令组合,完成一次8字节数据的传输。定义了6种命令, WR 写数据请求 (6’b000_001) STA 起始位请求(6’b000_010) RD 读数据请求(6’b000_100) STO 停止位请求(6’b001_000) ACK 应答位请求(6’b010_000) NACK 无应答请求(

    2024年02月03日
    浏览(53)
  • 基于EDA的电烤箱控制器设计Verilog代码Quartus 新起点FPGA开发板

    名称:基于EDA的电烤箱控制器设计Verilog代码Quartus  新起点FPGA开发板(文末获取) 软件:Quartus 语言:Verilog 代码功能: 基于EDA的电烤箱控制器设计 主要研究内容 设计一个电烤箱控制器电路,要求具有三档加热功能,分别表示烧烤加热为低火、中火、高火。具有复位开关、启动

    2024年02月01日
    浏览(45)
  • 从零开始 verilog 以太网交换机(二)MAC接收控制器的设计与实现

    🔈声明: 😃博主主页:王_嘻嘻的CSDN主页 🧨 从零开始 verilog 以太网交换机系列专栏:点击这里 🔑未经作者允许,禁止转载,侵权必删 🚩关注本专题的朋友们可以收获一个经典交换机设计的全流程,包括设计与验证(FPGA);以太网MAC的基础知识。新手朋友们还将获得一个

    2024年01月19日
    浏览(56)
  • 紫光同创 FPGA 开发跳坑指南(四)—— DDR3 控制器 IP 的使用

    DDR3 是一种大容量的存储器件,采用了预取技术和双边沿采样技术,以实现高速数据存储与读取,在视频处理中可以用来缓存 1 帧或多帧图像。 目录 一、紫光 DDR3 IP 的安装 二、紫光 DDR3 IP 的配置 三、DDR3 IP 的使用 3.1 DDR3 写操作 3.2 DDR3 读操作         在 Pango Design Suit 中,选

    2024年01月25日
    浏览(51)
  • 基于Vivado软件实现电梯控制器仿真设计

    Contents 1设计目的及要求 2 1.1设计要求 2 1.2设计H的 2 2工作原理和系统框图 2 3各部分选定方案及电路组成、相关器件说明 2 3.1各部分选定方案 2 3.2相关器件说明 3 4调试过程 8 4.1调试步骤 8 4.2调试过程中出现的错误及修正方案 8 5功能测试 10 6设计结论 12 7设计心得与总结 12 7.1设

    2024年02月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包