2608|2

22

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

国产FPGA测评【八】DDR3读写实验 [复制链接]

  本帖最后由 yyliu 于 2023-2-19 15:34 编辑

声明:1.本帖如有对引用其他网站资源,均附上了网址,针对本帖中可能出现的侵权行为,请及时联系本人修改或删除。

2. 未经本人允许,请勿转载。若本帖存在错误或不足之处,烦请指正,本人会及时修改。

3.本帖代码根据正点原子代码修改,并给出了源码,若对正点原子构成侵权,请及时联系本人删除。


 

0.说明


DDR在高速电路中较为常见,面向服务器、云计算、网络、笔记本电脑、台式机和消费类应用。本帖分为两个部分,第一部分是DDR的硬件设计经验,第二部分是学习正点原子的FPGA开发板DDR读写实验。

学习本帖需要掌握DDR的基础知识,包括DDR读写原理、DDR内存容量的计算、DDR的操作时序、DDR各信号的作用、DDR3和DDR4的区别等。这部分基础知识网上有很多资源,本帖不再一一介绍,默认大家有相关基础。

 

1.DDR硬件设计


DDR的硬件设计笼统的可以分为DDR DIMM设计和MEMORY DOWN设计,DDR DIMM就是我们常在计算机、服务器中见到的内存条,内存条容量易扩展、便于更换和维护,内存条是将内存颗粒焊接在内存条这一PCB上,金手指和信号都必须符合内存条的设计规范,内存条根据使用场合不同还分为UDIMM、RDIMM、LRDIMM等等;而MEMORY DOWN设计不同于内存条,它是将内存颗粒焊接在主板上,能够节约成本,容量也可以选配,但是灵活性不如内存条。一般MEMORY DOWN设计多用于对内存容量需求较小,CPU运算量有限的场合,如消费电子等领域。

正点原子的国产紫光同创FPGA开发板使用的就是MEMORY DOWN的设计方法。下面分别对两种设计方法加以介绍。

1.1 DDR DIMM设计

我们首先以镁光的内存条DDR4 SDRAM SODIMM MTA18ASF2G72HZ-16GB的datasheet为例,简单介绍下信号定义及作用:

由于信号较多,可以按照功能对上述信号进行分组:

1.数据组:MDQS(8:0),DQS(8:0),MDM(8:0),MDQ(63:0),MECC(7:0)

2.地址/命令组:MBA(2:0),MA(15:0),RAS,MCAS,MWE

3.控制组:CS(3:0),MCKE(3:0),MODT(3:0)

4.时钟组:MCK(5:0),CK(5:0)

 

CPU与DDR DIMM信号连接规则:

1.数据组:CPU MDQ数据线与DDR DIMM数据线相连,MDQS数据选取脉冲,一个DQS对应一组数据线MDQ,为了走线方便,数据线组内可以相互交换;但是组间不可以交换;

MECC是数据校验位,一个MDQS对应8bit数据校验;

2.地址/命令组:MBA是选择内存颗粒的BANKS信号,内存颗粒可能有4或8个BANKS信号,对于DDR4来说,还出现了BANK GROUPS。如果我们希望对内存进行读写操作,首先需要选中内存颗粒的BANK GROUPS,再选中这个BANK GROUPS的某一个BANK,再根据行列地址定位到内存单元。

3.控制组:CS信号用于选择某个内存条或者内存条的某几个内存颗粒,只有在CS有效,对内存的操作才能起作用。MCKE是时钟使能信号,对于内存条的设计来说,还有个RANK的概念,对于64bit的计算机来说,如果我们的内存条能够组成多个64bit位宽与CPU交互,则成为多RANK设计。每个RANK单独使用一路时钟使能信号MCKE和MODT信号。

4.时钟组:个RANK单独使用一路时钟使能信号MCK。

 

以上是对DDR信号及互联的介绍,下图给出了Wistron Corporation公司某原理图的DDR DIMM设计案例(侵删):

   

该设计的HOST是INTEL CPU,内存条为DDR3。

1.数据组:该设计为了走线方便,数据线大量采用了组内交换和整组交换。从DQS信号有8组来看,此内存条不支持ECC校验。

2.地址命令组:地址线共15根,A10和A16可以复用;内存颗粒有4个BANKS,因此采用两个BANK信号与CPU相连;

3.控制组:时钟组使能共有两组,因此该内存条为双RANK设计。

4.时钟组:时钟组共有两组,时钟源来自CPU。

 

1.2 MEMORY DOWN设计

正点原子提供的原理图就是采用MEMORY DOWN设计方案,直接参考对应内存颗粒和CPU的datasheet即可。内存颗粒和内存条相比,信号数量更少,共有的信号作用都相同,因此设计难度更低一些。

下图是正点原子的内存颗粒原理图(侵删),具体信号和互联不再分析了,参考DDR DIMM的设计:

 

 

对于另一种场景,出于速率和稳定性、成本、布线难度等因素,我们使用可能不止一颗内存颗粒,而是采用多颗内存颗粒组成和DDR DIMM相同的容量。这种场景就需要我们能够组合不同的数量和容量内存颗粒达到项目对内存容量的需求。我们在设计评估时要能列出表格。下图出自英特尔,给出了MEMORY DOWN某设计框图。

 

2. DDR读写实验(出自正点原子)


PGL22系列FPGA自带了DDR3控制器的硬核,可以直接借助IP核来实现对DDR3的读写操作,本次实验将使用紫光公司的LogosIMIC HIP核来实现DDR3读写测试。

HMICHIP是深圳市紫光同创电子有限公司FPGA产品中用于实现对SDRAM读写而设计的IP,通过紫光同创公司Pango Design Suite套件(后文简称PDS)中IPCompiler工具(后文简称IPC)例化生成IP模块。HMICHIP系统框图如下:

2.1 实验任务

 PGA调用ddr3测试数据模块向ddr3控制模块写入数据,写完之后ddr测试数据模块从ddr3控制模块读出所写入的数据,并判断读出的数据与写入数据是否相同,如果相同则LED1灯常亮,否则LED1灯闪烁。

 ddr3控制模块产生读写DDR3IP核用户接口的时序,实现与DDR3IP核的数据及信号交互。ddr3控制模块一方面负责与用户FPGA进行数据交互,另一方面还产生控制DDR3读写的各种时序,并实现对DDR芯片的读写操作。

ddr测试数据模块的作用是写入和读出ddr3控制器的数据并且将读写数据进行比较。

led显示模块是根据读写错误信号的高低来判断是否翻转LED灯的电平,以及显示ddr3初始化完成情况。

 

2.2 程序运行逻辑

module ddr3_rw_top(
    input             sys_clk          , //系统时钟50M
    input             sys_rst_n        , //系统复位
    output            led_error        , //读写错误led灯
    output            led_ddr_init_done, //ddr3初始化完成led灯

    //DDR3接口
    input             pad_loop_in      , //低位温度补偿输入
    input             pad_loop_in_h    , //高位温度补偿输入
    output            pad_rstn_ch0     , //Memory复位
    output            pad_ddr_clk_w    , //Memory差分时钟正端
    output            pad_ddr_clkn_w   , //Memory差分时钟负端
    output            pad_csn_ch0      , //Memory片选
    output [15:0]     pad_addr_ch0     , //Memory地址总线
    inout  [16-1:0]   pad_dq_ch0       , //数据总线
    inout  [16/8-1:0] pad_dqs_ch0      , //数据时钟正端
    inout  [16/8-1:0] pad_dqsn_ch0     , //数据时钟负端
    output [16/8-1:0] pad_dm_rdqs_ch0  , //数据Mask
    output            pad_cke_ch0      , //Memory差分时钟使能
    output            pad_odt_ch0      , //On Die Termination
    output            pad_rasn_ch0     , //行地址strobe
    output            pad_casn_ch0     , //列地址strobe
    output            pad_wen_ch0      , //写使能
    output [2:0]      pad_ba_ch0       , //Bank地址总线
    output            pad_loop_out     , //低位温度补偿输出
    output            pad_loop_out_h     //高位温度补偿输出    
   );

//parameter define 
parameter  APP_ADDR_MIN = 28'd0  ;  //ddr3读写起始地址,以一个16bit的数据为一个单位
//APP_ADDR_MAX = BURST_LENGTH * 8 * (n+1)(n表示突发次数)
parameter  APP_ADDR_MAX = 28'd5120 ;  //ddr3读写结束地址,以一个16bit的数据为一个单位
parameter  BURST_LENGTH = 8'd64    ;  //ddr3读写突发长度,64个128bit的数据
parameter  DATA_MAX = APP_ADDR_MAX - APP_ADDR_MIN;  //读写ddr3的最大数据量

//wire define
wire  [15:0]  wr_data        ;  //DDR3控制器模块写数据
wire  [15:0]  rd_data        ;  //DDR3控制器模块读数据
wire          wr_en          ;  //DDR3控制器模块写使能
wire          rd_en          ;  //DDR3控制器模块读使能
wire          ddr_init_done  ;  //ddr3初始化完成信号
wire          error_flag     ;  //ddr3读写错误标志

////*****************************************************
////**                    main code
////***************************************************** 
//ddr3控制器顶层模块
ddr3_top u_ddr3_top(
 .refclk_in             (sys_clk         ),
 .rst_n                 (sys_rst_n       ),
 .app_addr_rd_min       (APP_ADDR_MIN    ),
 .app_addr_rd_max       (APP_ADDR_MAX    ),
 .rd_bust_len           (BURST_LENGTH    ),
 .app_addr_wr_min       (APP_ADDR_MIN    ),
 .app_addr_wr_max       (APP_ADDR_MAX    ),
 .wr_bust_len           (BURST_LENGTH    ),
 .wr_clk                (sys_clk         ),
 .rd_clk                (sys_clk         ),
 .datain_valid          (wr_en           ),
 .datain                (wr_data         ),
 .rdata_req             (rd_en           ),
 .dataout               (rd_data         ),
 .ddr_init_done         (ddr_init_done   ),
 //DDR3接口
 .pad_loop_in           (pad_loop_in     ),
 .pad_loop_in_h         (pad_loop_in_h   ),
 .pad_rstn_ch0          (pad_rstn_ch0    ),
 .pad_ddr_clk_w         (pad_ddr_clk_w   ),
 .pad_ddr_clkn_w        (pad_ddr_clkn_w  ),
 .pad_csn_ch0           (pad_csn_ch0     ),
 .pad_addr_ch0          (pad_addr_ch0    ),
 .pad_dq_ch0            (pad_dq_ch0      ),
 .pad_dqs_ch0           (pad_dqs_ch0     ),
 .pad_dqsn_ch0          (pad_dqsn_ch0    ),
 .pad_dm_rdqs_ch0       (pad_dm_rdqs_ch0 ),
 .pad_cke_ch0           (pad_cke_ch0     ),
 .pad_odt_ch0           (pad_odt_ch0     ),
 .pad_rasn_ch0          (pad_rasn_ch0    ),
 .pad_casn_ch0          (pad_casn_ch0    ),
 .pad_wen_ch0           (pad_wen_ch0     ),
 .pad_ba_ch0            (pad_ba_ch0      ),
 .pad_loop_out          (pad_loop_out    ),
 .pad_loop_out_h        (pad_loop_out_h  )
 );  

//ddr3测试数据模块  
ddr_test u_ddr_test(
    .clk_50m       (sys_clk         ),    //时钟
    .rst_n         (sys_rst_n       ),    //复位,低有效
    .wr_en         (wr_en           ),    //写使能
    .wr_data       (wr_data         ),    //写数据
    .rd_en         (rd_en           ),    //读使能
    .rd_data       (rd_data         ),    //读数据  
    .data_max      (DATA_MAX        ),    //读写ddr的最大数据量
    .ddr3_init_done(ddr_init_done   ),    //ddr3初始化完成信号
    .error_flag    (error_flag      )     //ddr3读写错误
    );

//利用LED灯指示ddr3读写测试的结果及ddr3是否初始化完成
led_disp u_led_disp(
    .clk_50m            (sys_clk          ),
    .rst_n              (sys_rst_n        ),
    .ddr3_init_done     (ddr_init_done    ),
    .error_flag         (error_flag       ),
    .led_error          (led_error        ),
    .led_ddr_init_done  (led_ddr_init_done)
    );

endmodule

DDR读写实验的顶层模块代码如上所述,u_ddr3_top可以理解为两个部分构成:

1.DDR3接口。这部分是DDR3 PHY接口,物理上直接连接到FPGA的IO并与DDR内存颗粒连接。

2.ddr3控制器顶层模块。这部分信号可以与其他模块交互,如ddr3测试数据模块u_ddr_test,通过这部分交互信号,ddr3测试数据模块能够对DDR3进行读写操作。

3.LED指示灯模块u_led_disp十分简单,就是将ddr3测试数据模块成功或者失败的标志位传出与LED指示灯模块相连,作为LED指示灯模块的控制信号。

DDR3测试数据模块主要就是一些业务逻辑,通过DDR3顶层模块预留出来的接口,对其进行读写操作即可,总的来说难度不大。

比较复杂的是DDR3顶层模块ddr3_top,其包含了DDR IP核的调用,要想运用好该IP核还需要理解DDR的读写时序。下面给出了DDR3顶层模块代码。

module ddr3_top(
    input              refclk_in        ,//外部参考时钟输入
    input              rst_n            ,//外部复位输入

    input   [27:0]     app_addr_rd_min  ,//读ddr3的起始地址
    input   [27:0]     app_addr_rd_max  ,//读ddr3的结束地址
    input   [7:0]      rd_bust_len      ,//从ddr3中读数据时的突发长度
    input   [27:0]     app_addr_wr_min  ,//读ddr3的起始地址
    input   [27:0]     app_addr_wr_max  ,//读ddr3的结束地址
    input   [7:0]      wr_bust_len      ,//从ddr3中读数据时的突发长度
    //用户     
    input              wr_clk           ,//wfifo写时钟
    input              rd_clk           ,//rfifo读时钟
    input              datain_valid     ,//数据有效使能信号
    input   [15:0]     datain           ,//有效数据
    input              rdata_req        ,//请求数据输入
    output  [15:0]     dataout          ,//rfifo输出数据

    output             ddr_init_done    ,//DDR初始化完成
    input              pad_loop_in      ,
    input              pad_loop_in_h    ,
    output             pad_rstn_ch0     ,
    output             pad_ddr_clk_w    ,
    output             pad_ddr_clkn_w   ,
    output             pad_csn_ch0      ,
    output [15:0]      pad_addr_ch0     ,
    inout  [16-1:0]    pad_dq_ch0       ,
    inout  [16/8-1:0]  pad_dqs_ch0      ,
    inout  [16/8-1:0]  pad_dqsn_ch0     ,
    output [16/8-1:0]  pad_dm_rdqs_ch0  ,
    output             pad_cke_ch0      ,
    output             pad_odt_ch0      ,
    output             pad_rasn_ch0     ,
    output             pad_casn_ch0     ,
    output             pad_wen_ch0      ,
    output [2:0]       pad_ba_ch0       ,
    output             pad_loop_out     ,
    output             pad_loop_out_h
   );

//wire define
    wire  [32-1:0]    axi_awaddr     ;
    wire  [7:0]       axi_awlen      ;
    wire  [2:0]       axi_awsize     ;
    wire  [1:0]       axi_awburst    ;
    wire              axi_awlock     ;
    wire              axi_awready    ;
    wire              axi_awvalid    ;
    wire              axi_awurgent   ;
    wire              axi_awpoison   ;
    wire  [128-1:0]   axi_wdata      ;
    wire  [16-1:0]    axi_wstrb      ;
    wire              axi_wvalid     ;
    wire              axi_wready     ;
    wire              axi_wlast      ;
    wire              axi_bready     ;
    wire  [32-1:0]    axi_araddr     ;
    wire  [7:0]       axi_arlen      ;
    wire  [2:0]       axi_arsize     ;
    wire  [1:0]       axi_arburst    ;
    wire              axi_arlock     ;
    wire              axi_arpoison   ;
    wire              axi_arurgent   ;
    wire              axi_arready    ;
    wire              axi_arvalid    ;
    wire  [128-1:0]   axi_rdata      ;
    wire              axi_rlast      ;
    wire              axi_rvalid     ;
    wire              axi_rready     ;
    wire              axi_clk        ;
    wire [10:0]       wfifo_rcount   ;//rfifo剩余数据计数
    wire [10:0]       rfifo_wcount   ;//wfifo写进数据计数
    wire              wrfifo_en_ctrl ;//写FIFO数据读使能控制位
    wire              wfifo_rden     ;//写FIFO数据读使能
    wire              pre_wfifo_rden ;//写FIFO数据预读使能

//*****************************************************
//**                    main code
//*****************************************************
//因为预读了一个数据所以读使能wfifo_rden要少一个周期通过wrfifo_en_ctrl控制
assign wfifo_rden = axi_wvalid && axi_wready && (~wrfifo_en_ctrl) ;
assign pre_wfifo_rden = axi_awvalid && axi_awready ;

//ddr3读写控制器模块
rw_ctrl_128bit  u_rw_ctrl_128bit
(
 .clk                 (axi_clk          ),
 .rst_n               (rst_n            ),
 .ddr_init_done       (ddr_init_done    ),
 .axi_awaddr          (axi_awaddr       ),
 .axi_awlen           (axi_awlen        ),
 .axi_awsize          (axi_awsize       ),
 .axi_awburst         (axi_awburst      ),
 .axi_awlock          (axi_awlock       ),
 .axi_awready         (axi_awready      ),
 .axi_awvalid         (axi_awvalid      ),
 .axi_awurgent        (axi_awurgent     ),
 .axi_awpoison        (axi_awpoison     ),
 .axi_wstrb           (axi_wstrb        ),
 .axi_wvalid          (axi_wvalid       ),
 .axi_wready          (axi_wready       ),
 .axi_wlast           (axi_wlast        ),
 .axi_bready          (axi_bready       ),
 .wrfifo_en_ctrl      (wrfifo_en_ctrl   ),
 .axi_araddr          (axi_araddr       ),
 .axi_arlen           (axi_arlen        ),
 .axi_arsize          (axi_arsize       ),
 .axi_arburst         (axi_arburst      ),
 .axi_arlock          (axi_arlock       ),
 .axi_arpoison        (axi_arpoison     ),
 .axi_arurgent        (axi_arurgent     ),
 .axi_arready         (axi_arready      ),
 .axi_arvalid         (axi_arvalid      ),
 .axi_rlast           (axi_rlast        ),
 .axi_rvalid          (axi_rvalid       ),
 .axi_rready          (axi_rready       ),
 .wfifo_rcount        (wfifo_rcount     ),
 .rfifo_wcount        (rfifo_wcount     ),
 .app_addr_rd_min     (app_addr_rd_min  ),
 .app_addr_rd_max     (app_addr_rd_max  ),
 .rd_bust_len         (rd_bust_len      ),
 .app_addr_wr_min     (app_addr_wr_min  ),
 .app_addr_wr_max     (app_addr_wr_max  ),
 .wr_bust_len         (wr_bust_len      )
 );

 //ddr3IP核模块
 ddr3_ip u_ddr3_ip (
  .pll_refclk_in    (refclk_in      ), // input
  .top_rst_n        (rst_n          ), // input
  .ddrc_rst         (0              ), // input
  .csysreq_ddrc     (1'b1           ), // input
  .csysack_ddrc     (               ), // output
  .cactive_ddrc     (               ), // output
  .pll_lock         (               ), // output
  .pll_aclk_0       (axi_clk        ), // output
  .pll_aclk_1       (               ), // output
  .pll_aclk_2       (               ), // output
  .ddrphy_rst_done  (               ), // output
  .ddrc_init_done   (ddr_init_done  ), // output
  .pad_loop_in      (pad_loop_in    ), // input
  .pad_loop_in_h    (pad_loop_in_h  ), // input
  .pad_rstn_ch0     (pad_rstn_ch0   ), // output
  .pad_ddr_clk_w    (pad_ddr_clk_w  ), // output
  .pad_ddr_clkn_w   (pad_ddr_clkn_w ), // output
  .pad_csn_ch0      (pad_csn_ch0    ), // output
  .pad_addr_ch0     (pad_addr_ch0   ), // output [15:0]
  .pad_dq_ch0       (pad_dq_ch0     ), // inout [15:0]
  .pad_dqs_ch0      (pad_dqs_ch0    ), // inout [1:0]
  .pad_dqsn_ch0     (pad_dqsn_ch0   ), // inout [1:0]
  .pad_dm_rdqs_ch0  (pad_dm_rdqs_ch0), // output [1:0]
  .pad_cke_ch0      (pad_cke_ch0    ), // output
  .pad_odt_ch0      (pad_odt_ch0    ), // output
  .pad_rasn_ch0     (pad_rasn_ch0   ), // output
  .pad_casn_ch0     (pad_casn_ch0   ), // output
  .pad_wen_ch0      (pad_wen_ch0    ), // output
  .pad_ba_ch0       (pad_ba_ch0     ), // output [2:0]
  .pad_loop_out     (pad_loop_out   ), // output
  .pad_loop_out_h   (pad_loop_out_h ), // output 
  .areset_0         (0              ), // input
  .aclk_0           (axi_clk        ), // input
  .awid_0           (0              ), // input [7:0]
  .awaddr_0         (axi_awaddr     ), // input [31:0]
  .awlen_0          (axi_awlen      ), // input [7:0]
  .awsize_0         (axi_awsize     ), // input [2:0]
  .awburst_0        (axi_awburst    ), // input [1:0]
  .awlock_0         (axi_awlock     ), // input
  .awvalid_0        (axi_awvalid    ), // input
  .awready_0        (axi_awready    ), // output
  .awurgent_0       (axi_awurgent   ), // input
  .awpoison_0       (axi_awpoison   ), // input
  .wdata_0          (axi_wdata      ), // input [127:0]
  .wstrb_0          (axi_wstrb      ), // input [15:0]
  .wlast_0          (axi_wlast      ), // input
  .wvalid_0         (axi_wvalid     ), // input
  .wready_0         (axi_wready     ), // output
  .bid_0            (               ), // output [7:0]
  .bresp_0          (               ), // output [1:0]
  .bvalid_0         (               ), // output
  .bready_0         (axi_bready     ), // input 
  .arid_0           (0              ), // input [7:0]
  .araddr_0         (axi_araddr     ), // input [31:0]
  .arlen_0          (axi_arlen      ), // input [7:0]
  .arsize_0         (axi_arsize     ), // input [2:0]
  .arburst_0        (axi_arburst    ), // input [1:0]
  .arlock_0         (axi_arlock     ), // input
  .arvalid_0        (axi_arvalid    ), // input
  .arready_0        (axi_arready    ), // output
  .arpoison_0       (axi_arpoison   ), // input 
  .rid_0            (               ), // output [7:0]
  .rdata_0          (axi_rdata      ), // output [127:0]
  .rresp_0          (               ), // output [1:0]
  .rlast_0          (axi_rlast      ), // output
  .rvalid_0         (axi_rvalid     ), // output
  .rready_0         (axi_rready     ), // input
  .arurgent_0       (axi_arurgent   ), // input
  .csysreq_0        (1'b1           ), // input
  .csysack_0        (               ), // output
  .cactive_0        (               )  // output
);

//ddr3控制器fifo控制模块
 ddr3_fifo_ctrl u_ddr3_fifo_ctrl (
    .rst_n               (rst_n && ddr_init_done    ) ,  //复位
    //输入源接口
    .wr_clk              (wr_clk                    ) ,  //写时钟
    .rd_clk              (rd_clk                    ) ,  //读时钟
    .clk_100             (axi_clk                   ) ,  //用户时钟 
    .datain_valid        (datain_valid              ) ,  //数据有效使能信号
    .datain              (datain                    ) ,  //有效数据 
    .rfifo_din           (axi_rdata                 ) ,  //用户读数据 
    .rdata_req           (rdata_req                 ) ,  //请求像素点颜色数据输入
    .rfifo_wren          (axi_rvalid                ) ,  //ddr3读出数据的有效使能
    .wfifo_rden          (wfifo_rden||pre_wfifo_rden) ,  //ddr3 写使能
    //用户接口
    .wfifo_rcount        (wfifo_rcount              ) , //rfifo剩余数据计数
    .rfifo_wcount        (rfifo_wcount              ) , //wfifo写进数据计数
    .wfifo_dout          (axi_wdata                 ) , //用户写数据
    .pic_data            (dataout                   )   //rfifo输出数据
    );

endmodule

ddr3控制器顶层模块主要完成ddr3读写控制器模块、FIFO控制模块和ddr3IP核的例化。

ddr3IP核模块一边与用户端进行交互,另一边对芯片进行操作,以实现数据的存储。

FIFO控制模块负责对输入和输出的数据进行时钟域的切换和位宽的转换。

ddr3读写控制器模块负责与ddr3IP核模块的命令和地址的交互,根据FIFO控制模块中fifo的剩余数据量来切换DDR3的读写命令和地址。这部分的理解大家可以参考DDR3规范。


下图是DDR3命令真值表:

 

DDR3各个命令都是由时序要求的,如下图的写时序要求:

大家对时序或者程序中的参数有不理解的,可以参考DDR3规范和本案例的DDR3颗粒规格数。

对于程序细节的理解,有一部分我也需要好好消化下,先把方法交给大家。 

 

3.总结


本帖前半部分结合我的经验给出了DDR硬件设计方法,还有很多原理图的设计细节以及PCB布局布线要求,如FLY-BY走线等没法一一详尽;后面结合正点原子的代码,梳理了程序框架以及理解的方法,大家可以自行深入学习。工作闲暇我也需要对这部分内容的一些细节好好消化下。

针对实物仿真,大家手头如果有开发板,可以先从修改读写测试模块开始并观察现象,从能够对DDR用起来,再到细节的深入理解,这需要一个过程,毕竟DDR的时序和状态机跳转都有一定难度。

最新回复

ddr测试数据模块的作用是写入和读出ddr3控制器的数据并且将读写数据进行比较,比较的结果是如何验证的呢   详情 回复 发表于 2023-2-26 08:43
点赞 关注(1)
 
 

回复
举报

1701

帖子

0

TA的资源

五彩晶圆(初级)

沙发
 

ddr测试数据模块的作用是写入和读出ddr3控制器的数据并且将读写数据进行比较,比较的结果是如何验证的呢

点评

你好!读写测试模块产生一个标志位给LED显示模块,作为LED灯的控制信号。如果比较成功了,就置位,比较不成功就置零,这样就能控制LED的亮暗了通过其他方式也是可以对比的,比如通过串口将读出的数据打印出来,还可  详情 回复 发表于 2023-2-26 08:59
 
 
 

回复

22

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
火辣西米秀 发表于 2023-2-26 08:43 ddr测试数据模块的作用是写入和读出ddr3控制器的数据并且将读写数据进行比较,比较的结果是如何验证的呢

你好!读写测试模块产生一个标志位给LED显示模块,作为LED灯的控制信号。如果比较成功了,就置位,比较不成功就置零,这样就能控制LED的亮暗了



通过其他方式也是可以对比的,比如通过串口将读出的数据打印出来,还可以通过紫光的内嵌逻辑分析仪去查看波形


 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表