Spartan6 FPGA DDR3自建写测试平台

FPGA


先简单总结一下前面建立FPGA DDR3 IP Core,以及简单简述一下DDR3 IP Core的信号。

1.DDR3 IP core建立的时候,如果网上没有搭建这个IP核的资料,我们要怎么搭建呢? 
Spartan6 FPGA DDR3自建写测试平台
2.打开后得到这个文档,点击Click here,可以获得这个IP Core的搭建设置方法 
Spartan6 FPGA DDR3自建写测试平台
3.点击Click here后,得到User Guide手册 
Spartan6 FPGA DDR3自建写测试平台


DDR3 IP Core各个信号,查看MCB这个文档Spartan6 FPGA DDR3自建写测试平台
他的引脚信号分布 
Spartan6 FPGA DDR3自建写测试平台
我们控制的就是右边的IOB信号。左边的信号有几个端口就要看你创建IP核的时候的Port设置了。 
Spartan6 FPGA DDR3自建写测试平台因为我之前创建IP核的时候是将他设置成了2个64bit的Port。所以这里是有P0和P1信号端口。 
Spartan6 FPGA DDR3自建写测试平台
接口的分类

Spartan6 FPGA DDR3自建写测试平台 
Spartan6 FPGA DDR3自建写测试平台


command path 中比较有用的几个信号 
(c3_p0_cmd_clk),//cmd FIFO的用户时钟,上升沿有效 
(c3_p0_cmd_en), //该高电平有效信号是用于写入的写入使能信号 
(c3_p0_cmd_instr),//指令端口 
(c3_p0_cmd_bl),//突发长度,0-63 
(c3_p0_cmd_byte_addr),//字节开始的地址,他的后面几位不能为0 
(c3_p0_cmd_empty),//FIFO的空标志,高有效 
(c3_p0_cmd_full),//FIFO的满标志

由MCB的手册可知,这些信号都是Command path信号 
Spartan6 FPGA DDR3自建写测试平台 
那我们如何向DDR3写入command呢?打开目录,找到command path timing,找到他的时序图,根据手册时序图写程序就可以向DDR3写入指令。 
Spartan6 FPGA DDR3自建写测试平台 
Spartan6 FPGA DDR3自建写测试平台
command path的读写时序。

写时序 
Spartan6 FPGA DDR3自建写测试平台

注意:这里需要注意时钟,这里有好几个时钟,command path timing(write)时钟是cmd_clk,这个时钟主要是用来检测cmd_en信号的,而我们如果需要将instr指令端口信号写入DDR3,则使用的是Wr_clk

我们看看cmd_clk和wr_clk手册怎么说的吧

cmd_clk 
Spartan6 FPGA DDR3自建写测试平台 
wr_clk 
Spartan6 FPGA DDR3自建写测试平台

write_path_timing 
Spartan6 FPGA DDR3自建写测试平台

那cmd和wirte是怎么协调的呢?

Spartan6 FPGA DDR3自建写测试平台
我们可以看到在command path timing 时序和write path timing都可以看到cmd和write都有调用到FIFO。cmd_FIFO存储的是命令指令,write data fifo里面存储是要写入到DDR3中的数据。那我们要往DDR3写入数据,那么DDR3先读入cmd_instr的数据。先知道是读操作还是写操作。得知是写操作后,会去访问Write Data FIFO里面的数据,将Write FIFO里面的数据写入DDR3 FIFO。读操作,就是讲Read FIFO里面的数据读出来。因此,在写命令的时候,我们需要确保DDR3的Wr_data_FIFO里面是有数据的。所以我们要将上面的步骤反过来,先向Write data fifo写入想要DDR3芯片内部数据,之后再向cmd fifo中写入相应的写指令。这样的话,我们的时序图可以这么写 
Spartan6 FPGA DDR3自建写测试平台 
cmd_en也就是去检测wr_en的下降沿。


代码的实现

Spartan6 FPGA DDR3自建写测试平台
将顶层文件DDR3的command 引脚和 write引脚引出来。 
因为我们是仿真时序,所以我们新建一个wr_trig来控制wr_en。 
Spartan6 FPGA DDR3自建写测试平台 
仿真时序图

新建一个ddr3_drive文件。 
Spartan6 FPGA DDR3自建写测试平台 
上图是ddr3_drive的引脚信息。因为我们是仿真,所以我们将instr直接固定成3'b000写模式,将Bl,mask也固定。

ddr3_drive代码:

    module ddr3_drive(
//system signal
input                   s_clk                   ,       
input                   s_rst_n                 ,       
//DDR3 User Interface
output wire             p0_cmd_en               ,       
output wire [2:0]       p0_cmd_instr            ,       
output wire [5:0]       p0_cmd_bl               ,       
output wire [29:0]      p0_cmd_byte_addr        ,       
output reg              p0_wr_en                ,       
output wire [7:0]       p0_wr_mask              ,       
output reg [63:0]       p0_wr_data              ,       
//Debug
input                   wr_trig 
);


//========================================================================\
// =========== Define Parameter and Internal signals =========== 
//========================================================================/
reg                             p0_wr_en_r1                     ;      //用于捕获wr_en的下降沿 


//=============================================================================
//**************    Main Code   **************
//=============================================================================
always  @(posedge s_clk or negedge s_rst_n) begin
        if(s_rst_n == 1'b0)
            p0_wr_en <= 'd0;
        else if(p0_wr_data >= 'd15)
            p0_wr_en <= 'd0;
        else if(wr_trig == 1'b1)
            p0_wr_en <= 1'b1;
end

always  @(posedge s_clk or negedge s_rst_n) begin
        if(s_rst_n == 1'b0)
            p0_wr_data <= 'd0;
        else if(p0_wr_en == 1'b1)
            p0_wr_data <= p0_wr_data + 1'b1;
end


always  @(posedge s_clk) begin
       p0_wr_en_r1 <= p0_wr_en;
end

assign p0_cmd_en = ~p0_wr_en & p0_wr_en_r1;
assign p0_cmd_instr = 3'b000;//write
assign p0_cmd_bl = 'd15;
assign p0_cmd_byte_addr = 'd0;
assign p0_wr_mask = 8'b0;

    endmodule 

顶层文件将ddr3_drive文件例化进去。 
Spartan6 FPGA DDR3自建写测试平台 
注意:这里给ddr3_drive的是ddr3例化文件给出的user clock和user reset。reset是高电平有效的,即高电平复位。所以给ddr3_drive传入的是~c3_rst0。需要去一次反。 
Spartan6 FPGA DDR3自建写测试平台

让ddr3_drive的信号与ddr3的例化文件信号一致。 
Spartan6 FPGA DDR3自建写测试平台 
将cmd_clk和wr_clk都用c3_clk0传入。

在top文件中再声明一下即可。 
Spartan6 FPGA DDR3自建写测试平台


接下来就是写仿真的脚本文件了

主要就是去产生一个wr_trig信号 
代码如下

initial begin
    wr_trig = 0;
    @(posedge c3_calib_done)
    #10_0000;//10ns
    wr_trig = 1;
    #25600;
    wr_trig = 0;
end

因为ddr3的操作要在calib_done完成后(calib_done是指MCB初始化完成的信号)才能读写ddr3.所以top文件也需要将c3_calib_done引出,在tb文件中例化进来。 
Spartan6 FPGA DDR3自建写测试平台


接着因为我们需要查看ddr3_drive_inst,u_mig_39_2的信号,为了提高效率,我们通过tcl脚本添加。 
Spartan6 FPGA DDR3自建写测试平台 
在工程文件中有fdo和udo两个文件。这就相当于我们平时自己写的do文件。fdo是ISE产生的,一般不改变,udo是ISE给用户添加的do文件。udo也就是user do的意思。 
Spartan6 FPGA DDR3自建写测试平台 
将分组和添加信号的脚本卸载udo文件中。 
Spartan6 FPGA DDR3自建写测试平台 
点击开始仿真。


波形的分析

Spartan6 FPGA DDR3自建写测试平台
我们要先找到wr_trig信号。因为真正的数据端口是ddr3_dq引脚,我们主要查看的是wr_trig拉高后的ddr3_dq引脚信号。看波形我们可以知道wr_trig引脚在34855200ps后拉高。我们就去看这个时间后的打印信息。 
Spartan6 FPGA DDR3自建写测试平台
注意:因为我们FPGA DDR3 IP是64bit port,而我们DDR3实际是16bit的port。所以我们这里是并不是0000,0001,0002这样下去。 
Spartan6 FPGA DDR3自建写测试平台 
而是这样四个一组的。 
因为我们测试是0-15,所以最终到0x0f,看打印信息,可知仿真正确。 
Spartan6 FPGA DDR3自建写测试平台

 

欢迎关注微信公众号:文鸿开源工作室 
Spartan6 FPGA DDR3自建写测试平台

相关文章: