Menu Close

DDR3控制器接口与使用

在完成DDR3控制器生成后,展开新生成ddr3_intf IP核并打开ddr3_intf.v文件,如图1所示。ddr3_intf是新生成的DDR3控制器的IP核。该IP核起到了在APP与DDR3芯片接口之间桥梁的作用。如果仅仅在FPGA上使用DDR3, 学会使用APP与DDR3控制器之间的接口和数据交互是必须要掌握的技能。当然该IP核源文件都可以阅读,是学习DDR3控制器开发的最好范例。

图1

在图1右边的文本编辑框中可以看到DDR3的输入输出接口,APP与DDR3控制器接口的框图见图-2。下面将以ddr3_intf IP 核为基础新建测试DDR3的应用与测试文件。操作步骤如下。

1. 新建测试文件新建测试文件ddr3_top.v.

  • 将ddr3_intf.v的输入、输出部分复制到ddr3_top.v的输入输出部分,并在ddr3_top.v文件中例化ddr3_intf。
  • 新建PLL(sys_pll)并例化。PLL的输入时钟为50MHz, 输出时钟clk_out1为100Mhz作为系统时钟;输出时钟clk_out2为DDR3控制器的参考时钟,时钟频率为200Mhz。如图2所示。

图2

2. ddr3_top.v的代码如下:

module DDR3_top
(

  input                             inclk,
    // Memory interface ports
  output    [13:0]                  ddr3_addr,      // output [13:0]		ddr3_addr
  output    [2:0]                   ddr3_ba,        // output [2:0]		ddr3_ba
  output                            ddr3_cas_n,     // output			ddr3_cas_n
  output                            ddr3_ck_n,      // output [0:0]		ddr3_ck_n
  output                            ddr3_ck_p,      // output [0:0]		ddr3_ck_p
  output                            ddr3_cke,       // output [0:0]		ddr3_cke
  output                            ddr3_ras_n,     // output			ddr3_ras_n
  output                            ddr3_reset_n,   // output			ddr3_reset_n
  output                            ddr3_we_n,      // output			ddr3_we_n
  inout     [15:0]                  ddr3_dq,        // inout [15:0]		ddr3_dq
  inout    [1:0]                    ddr3_dqs_n,     // inout [1:0]		ddr3_dqs_n
  inout    [1:0]                    ddr3_dqs_p,     // inout [1:0]		ddr3_dqs_p
  
      
  output    [1:0]                   ddr3_dm,                    // output [1:0]		ddr3_dm
  output    [0:0]                   ddr3_odt 
  
               
);



  wire                          init_calib_complete ; // output			init_calib_complete

  wire      [26:0]              app_addr;           // input [26:0]		app_addr  
  wire      [2:0]               app_cmd;             // input [2:0]		app_cmd
  wire                          app_en;           // input				app_en
  wire                          app_rdy;            // output			app_rdy
  
  wire      [127:0]             app_wdf_data;        // input [127:0]		app_wdf_data
  wire                          app_wdf_end;        // input				app_wdf_end
  wire                          app_wdf_wren;       // input				app_wdf_wren
  wire                          app_wdf_rdy ;      // output			app_wdf_rdy
   wire     [15:0]              app_wdf_mask;     // input [15:0]		app_wdf_mask
  
  wire      [127:0]             app_rd_data;        // output [127:0]		app_rd_data
  wire                          app_rd_data_end;    // output			app_rd_data_end
  wire                          app_rd_data_valid ;  // output			app_rd_data_valid
 
  


 // reg                               app_sr_req       ;       // input			app_sr_req
 // reg                               app_ref_req    ;      // input			app_ref_req
 // reg                               app_zq_req    ;      // input			app_zq_req
//  wire                              app_sr_active  ;    // output			app_sr_active
//  wire                              app_ref_ack;     // output			app_ref_ack
//  wire                              app_zq_ack;      // output			app_zq_ack
  wire                              ui_clk   ;           // output			ui_clk
  wire                              ui_clk_sync_rst; // output			ui_clk_sync_rst

    // System Clock Ports
  wire                              sys_clk;  //4?1  100M
    // Reference Clock Ports
  wire                              clk_ref ;//200M
  wire                              pll_locked;
          
  wire          nsys_rst=pll_locked;
  
sys_pll  sys_pll_inst
 (
  // Clock out ports
.clk_out1   (sys_clk),//ratio 2:1 200M,4:1 ---100Mhz 
.clk_out2   (clk_ref),//200M
  // Status and control signals
.reset      (1'b0),
.locked     (pll_locked),
 // Clock in ports
.clk_in1    (inclk)   //50M
 );


 ddr3_intf u_ddr3_intf (

    // Memory interface ports
    .ddr3_addr                      (ddr3_addr),  // output [13:0]		ddr3_addr
    .ddr3_ba                        (ddr3_ba),  // output [2:0]		ddr3_ba
    .ddr3_cas_n                     (ddr3_cas_n),  // output			ddr3_cas_n
    .ddr3_ck_n                      (ddr3_ck_n),  // output [0:0]		ddr3_ck_n
    .ddr3_ck_p                      (ddr3_ck_p),  // output [0:0]		ddr3_ck_p
    .ddr3_cke                       (ddr3_cke),  // output [0:0]		ddr3_cke
    .ddr3_ras_n                     (ddr3_ras_n),  // output			ddr3_ras_n
    .ddr3_reset_n                   (ddr3_reset_n),  // output			ddr3_reset_n
    .ddr3_we_n                      (ddr3_we_n),  // output			ddr3_we_n
    .ddr3_dq                        (ddr3_dq),  // inout [15:0]		ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n),  // inout [1:0]		ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p),  // inout [1:0]		ddr3_dqs_p
   
      
    .ddr3_dm                        (ddr3_dm),  // output [1:0]		ddr3_dm
    .ddr3_odt                       (ddr3_odt),  // output [0:0]		ddr3_odt
    
    // Application interface ports
    .init_calib_complete            (init_calib_complete),  // output			init_calib_complete
    
    .app_addr                       (app_addr),  // input [27:0]		app_addr
    .app_cmd                        (app_cmd),  // input [2:0]		app_cmd
    .app_en                         (app_en),  // input				app_en
    .app_rdy                        (app_rdy),  // output			app_rdy
    
    
    .app_wdf_data                   (app_wdf_data),  // input [127:0]		app_wdf_data
    .app_wdf_end                    (app_wdf_end),  // input				app_wdf_end
    .app_wdf_wren                   (app_wdf_wren),  // input				app_wdf_wren
    .app_wdf_rdy                    (app_wdf_rdy),  // output			app_wdf_rdy
    .app_wdf_mask                   (app_wdf_mask),  // input [15:0]		app_wdf_mask
    
    .app_rd_data                    (app_rd_data),  // output [127:0]		app_rd_data
    .app_rd_data_end                (app_rd_data_end),  // output			app_rd_data_end
    .app_rd_data_valid              (app_rd_data_valid),  // output			app_rd_data_valid
  
  
    .app_sr_req                     (1'b0),  // input			app_sr_req
    .app_ref_req                    (1'b0),  // input			app_ref_req
    .app_zq_req                     (1'b0),  // input			app_zq_req
    .app_sr_active                  (),  // output			app_sr_active
    .app_ref_ack                    (),  // output			app_ref_ack, refresh
    .app_zq_ack                     (),  // output			app_zq_ack
    
    .ui_clk                         (ui_clk),  // output			ui_clk
    .ui_clk_sync_rst                (ui_clk_sync_rst),  // output			ui_clk_sync_rst
    
    // System Clock Ports
    .sys_clk_i                       (sys_clk),
    // Reference Clock Ports
    .clk_ref_i                      (clk_ref),// reference
    .sys_rst                        (nsys_rst) // input sys_rst
    );
    
  //application   
ddr_rd_wr  ddr_rd_wr_inst
(
.app_addr           (app_addr), 
.app_cmd            (app_cmd), 
.app_en             (app_en), 
.app_rdy            (app_rdy),

.app_wdf_data       (app_wdf_data), 
.app_wdf_end        (app_wdf_end), 
.app_wdf_wren       (app_wdf_wren), 
.app_wdf_rdy        (app_wdf_rdy), 
.app_wdf_mask       (app_wdf_mask),

.app_rd_data        (app_rd_data),
.app_rd_data_end    (app_rd_data_end),
.app_rd_data_valid  (app_rd_data_valid),

.clk                (ui_clk),   //100M
.rst_n              (!ui_clk_sync_rst),
.error_flag         (error_flag),
.end_flag           (end_flag)    

);

endmodule

ddr3_top.v的文件中 ddr_rd_wr例化部分是新建文件ddr_rd_wr.v,该文件利用ddr_intf接口进行DDR3存储器读写测试, 后面的章节会详细介绍.

3. DDR 控制器接口描述:

表1

Signal name Direction Description 描述
app_addr[ADDR_WIDTH – 1:0] input This input indicates the address for

the current request.

当前请求地址,[ROW+BA+COL)
app_cmd[2:0] input  This input selects the command for

the current request.

当前请求命令,000–写,001–读
app_en input This is the active-High strobe for the

app_addr[], app_cmd[2:0],

app_sz, and app_hi_pri inputs.

高电平有效的选通信号,使能APP的地址,命令等
app_rdy output This output indicates that the UI is ready

to accept commands.If the signal is deasserted

when app_en is enabled, the current app_cmd

and app_addr must be retried until app_rdy

is asserted.

指示当前的UI准备好接收新命令,如果在app_en使能后该信号撤销,命令及地址需重新发送
app_hi_pri input This active-High input elevates the priority

of the current request.

提升当前命令的优先级,常规设计中一般不使用
app_rd_data

[APP_DATA_WIDTH – 1:0]

output This provides the output data from read

commands.

读到的数据
app_rd_data_end output This active-High output indicates that the

current clock cycle is the last cycle of

output data on app_rd_data[].

This is valid only when

app_rd_data_valid is active-High.zai

当前时钟的数据为最后一笔数据,只有在app_rd_data_valid 为高电平时才有效
app_rd_data_valid output This active-High output indicates

that app_rd_data[] is valid.

高电平指示app_rd_data[] 有效
app_sz input This input is reserved and

should be tied to 0.

保留,输入0

表2

Signal name Direction Description 描述
app_wdf_data

[APP_DATA_WIDTH – 1:0]

input This provides the data for write

commands.

写命令之后跟的写数据
app_wdf_end  input  This active-High input indicates that

the current clock cycle is the last cycle

of input data on app_wdf_data[].

当前时钟的写数据为最后写命令的最后一笔数据. 是写数据与auto_precharge的组合
app_wdf_mask

[APP_MASK_WIDTH – 1:0]

input This provides the mask for

app_wdf_data[].

每个字节对应的屏蔽位,每个bit对于数据的一个字节,高电平有效.
app_wdf_rdy  output This output indicates that the write data

FIFO is ready to receive data. Write data

is accepted when app_wdf_rdy = 1’b1

and app_wdf_wren = 1’b1.

指示写数据缓冲区FIFO可以接收新数据,写数据在

app_wdf_rdy = 1’b1与app_wdf_wren = 1’b1.都有效是写数据才会被接受

app_wdf_wren input This is the active-High strobe for

app_wdf_data[].

写使能

写数据在app_wdf_rdy = 1’b1与app_wdf_wren = 1’b1.都有效是写数据才会被接受

app_correct_en_i input When asserted, this active-High signal

corrects single bit data errors.

This input is valid only when ECC is

enabled in the GUI. In the example

design, this signal is always tied to 1.

在ECC有效的情况下,如果该位有效可以纠正一位错误
app_sr_req input This input is reserved and should be

tied to 0.

保留,接0
app_sr_active output This output is reserved. 保留
app_ref_req  input This active-High input requests that

a refresh command be issued to the DRAM.

请求刷新命令

表3

Signal name Direction Description 描述
app_ref_ack Output This active-High output indicates that the

Memory Controller has sent the requested

refresh command to the PHY interface

高电平指示刷新命令已经送到DDR接口
app_zq_req Input This active-High input requests that a ZQ

calibration command be issued to the DRAM.

数据端口校准命令.

可以由应用程序发起

ui_clk Output This UI clock must be a half or quarter of the

DRAM clock.

用户时钟,是DDR控制器提供给APP的时钟,与DDR控制器的地址,数据及控制信号同步.

必须是一半(1/2)或1/4 的DDR时钟频率

init_calib_complete Output PHY asserts init_calib_complete when

calibration is finished.

校准完成后输出高电平.

可以用来指示DDR控制器的读写操作可以开始.

app_ecc_multiple_err[7:0] Output This signal is applicable when ECC is enabled

and is valid along with app_rd_data_valid.

The app_ecc_multiple_err[3:0] signal is

non-zero if the read data from the external

memory has two bit errors per beat

of the read burst. The SECDED algorithm

does not correct the corresponding read data

and puts a non-zero value on this signal

to notify the corrupted read data at the UI.

只有在ECC使能的情况下有效,在每个突发读时app_ecc_multiple_err[3:0]在检查到数据有2位错时输出非零值。如果采用SECDED算法,该机制并不纠错,只是输出一个非零值。
ui_clk_sync_rst Output  This is the active-High UI reset. 高电平有效的UI复位信号
app_ecc_single_err[7:0]  Output This signal is applicable when ECC is enabled

and is valid along with app_rd_data_vali.

The app_ecc_single_err signal is non-zero

if the read data from the external memory

has a single bit error per beat of the

read burst.

只有在ECC使能的情况下有效,在每个突发读时app_ecc_multiple_err[3:0]在检查到数据有1位错时输出非零值。如果采用SECDED算法,该机制并不纠错,只是输出一个非零值。

DDR3控制器的主要接口分为3组,分别地址命令的写入, 读数据命令,写数据命令. 注意这些接口主要用于FPGA内部应用程序与DDR控制器的接口,而不是FPGA应用程序与DDR3芯片的直接接口.其它的接口有refresh和ZQ calibration接口也是需要APP通过DDR控制器发给DDR3 SDRAM芯片. 通过以上接口可以实现APP与DDR_CTRL 中FIFO的交互. DDR控制器控制FIFO的另一端与DDR3芯片交互.

FPGA内APP与DDR控制器接口示意图,如图2,

图2  FPGA_APP 与DDR控制器主要接口示意图

总结:在以生成的DDR控制器的基础上,学习APP-DDR Control之间的接口,例化DDR3控制器,并插入读写模块形成完整的应用程序。更过的内容请阅读后续文章。

 

 

 

 

Posted in FPGA, FPGA, FPGA 教材教案, FPGA硬件资源, IC, 元器件, 存储器, 教材与教案, 文章, 资料区

2 Comments

  1. 8班王飞飞

    老师好,在学习中遇到一些问题,请老师解答:
    1、使用FPGA内部PLL生成的200M时钟作为ddr控制器的参考时钟,请问这里的参考时钟的频率是根据什么确定的呢?ddr控制器参考时钟必须使用200M时钟吗?
    2、200M ddr控制器参考时钟,具体是用在哪里呢?有哪些具体作用呢?

    • William

      使用FPGA内部PLL生成的200M时钟作为ddr控制器的参考时钟,请问这里的参考时钟的频率是根据什么确定的呢?
      ddr控制器参考时钟必须使用200M时钟吗?
      A:参考时钟200M 是由于artix芯片所决定的, 是必须的。 原因:这个参考时钟用来做MIG IP 的 IO delay 的,aritx芯片要求必须使用200M时钟,作为IO delay的。 高端的芯片有使用300M, 400M的。

      200M ddr控制器参考时钟,具体是用在哪里呢?有哪些具体作用呢?
      A:在 Ip 核中的mig_7series_v4_1_iodelay_ctrl.v 文件中的 340 – 357 行的位置,用来控制原语 IDELAYCTRL的。

发表回复

相关链接