- 前言
最近一直在查找关于DDR3的资料,网上也有很多介绍,这篇主要是记录我的学习过程,以防后期遗忘。本篇主要是针对如何运用XILINX的MIG核,因个人能力有限,对DDR3的硬件外围电路和原理只是大概的一个认知,如有错误还望指正。
- 确定芯片的速率和位宽
例如:
DDR3芯片为型号为:MT41K256M16XX-125
FPGA型号为:XC7K325TFFG900-2
1、下图为镁光的DDR3数据手册,主要解释DDR3的数据位宽、容量大小和速度等级
256M16:其中16代表芯片位宽,芯片总的容量为:256M字节*16bit=512M字节
2、查看FPGA中支持DDR3的最大数据速率为1866Mb/s,大多时候都是1600Mb/s。因为DDR3是双边沿采样,所以对应频率为1600/2=800Mhz
3、带宽
DDR3速率是800MHz,因为上下边沿采样,所以速率是2*800=1600MT/S,速率就是1600Mbit/s,因为DDR3是16bit,所以总的带宽为16*1600Mbit/s=3.125GByte/s
- IP核的一些关键时钟配置
1、
上图中1是由输入的system clock通过MIG中的PLL倍频得到的,通过端口
.ddr3_ck_n (ddr3_ck_n),
.ddr3_ck_p (ddr3_ck_p),
输出给DDR3芯片,这个时钟是DDR3接口的实际速率400MHz。
上图中2是用户时钟的接口,显示的比利4:1也就是实际接口的速率的1/4,100MHz;
.ui_clk (ddr_ui_clk),
上图中3是DDR3中型号的选择,位宽的选择和电压选择。
- 输入管脚时钟配置
图中1的位置是选择输入时钟,是根据实际的硬件选择的。
对应端口为,选择的是差分输入
.sys_clk_p (sys_clk_p),
.sys_clk_n (sys_clk_n),
图中2的位置是选择突发类型选择,一般选择顺序突发
- 输入时钟和参考时钟的类型选择
图中1的位置选择系统时钟的类型,根据实际电路选择,这里选择差分时钟,
图中2是选择参考,如果系统时钟配置的是200MHz,那么这里的参考时钟可以选择use system clock。
- MIG的时序图和管脚
- 管脚说明
// Application interface ports
.app_addr (app_addr), // 写数据地址
.app_cmd (app_cmd), // DDR3指令 写:3‘b000;读:3’b001;
.app_en (app_en), // 指令写使能
.app_wdf_data (app_wdf_data), // 写数据
.app_wdf_end (app_wdf_end), // 写数据结束标志
.app_wdf_wren (app_wdf_wren), // 写数据使能
.app_rd_data (app_rd_data), // 读数据
.app_rd_data_end (app_rd_data_end), // 读数据结束标志
.app_rd_data_valid (app_rd_data_valid),// 读数据有效标志
.app_rdy (app_rdy), // 指令准备信号
.app_wdf_rdy (app_wdf_rdy), // 写数据准备信号
对于用户层,只需要知道如何去控制DDR3怎么读写数据,只需要控制以上信号即可。
- 写指令和写数据时序图
从上图可知,只有当app_rdy为高的时候,app_cmd、app_addr以及app_en才有效。
由上图可知,当写指令有效的时候,写数据可以有三种模式给出:
1:第一种是对齐模式,也是大家常用的模式
2:第二种是提前写指令一个周期写入数据
3:第三种是当写指令给出以后,延迟2个周期给出数据
但是在实际情况中我们需要考虑信号app_rdy和app_wdf_rdy的有效性,所以采用以上模式有点儿困难,再次前提下我们需要知道一个事情,那就是写指令和写数据其实是相互独立的,其实就是写数据是写在一个FIFO中,当给出一个写指令,就会从fifo中读出一个数据给DDR3,所以在实际设计中,可以先考虑将写数据先写入,在等待app_rdy为高的时候给出写指令。如下图所示:
其实虽然app_rdy为低,但是这个时候可以先将数据100写进去,等待app_rdy拉高之后就将地址写进去,这个时候写的数据也是有效的。
- 读数据时序图
其实读数据时序很简单,MIG和会将数据的有效标志和数据从IP中输出出来,只需要提前给出读数据的地址就行。
如上图所示,提前给出读数据指令和数据地址,等待一个不固定的时钟周期,IP核就可以出来数据和数据有效标志。
5、程序设计
本次主要是验证读写DDR3,最后做仿真
- 状态图
- 写数据部分的主要代码
WRITE_1:begin
app_cmd <= 3'b000;
app_en <= 1;
app_addr <= wr_addr_cnt;
wr_addr_cnt <= wr_addr_cnt + 8;
app_wdf_wren <= 1;
app_wdf_end <= 1;
app_wdf_data <= 100;
DDR3_STATE <= WRITE_2;
wr_ddr3_cnt <= wr_ddr3_cnt + 1;
end
WRITE_2:begin
if(app_rdy && app_wdf_rdy)begin
if(wr_ddr3_cnt >= WRITE_SIZE)begin
wr_ddr3_cnt <= 16'b0;
app_addr <= wr_addr_cnt;
wr_addr_cnt <= wr_addr_cnt + 8;
app_wdf_wren <= 0;
app_wdf_end <= 0;
app_en <= 0;
app_wdf_data <= app_wdf_data + 1;
DDR3_STATE <= NOP;
end else begin
app_addr <= wr_addr_cnt;
wr_addr_cnt <= wr_addr_cnt + 8;
app_en <= 1;
app_wdf_wren <= 1;
app_wdf_end <= 1;
app_wdf_data <= app_wdf_data + 1;
wr_ddr3_cnt <= wr_ddr3_cnt + 1;
DDR3_STATE <= WRITE_2;
end
end else if(app_rdy == 1 && app_wdf_rdy ==0)begin
app_en <= 0;
end else if(app_rdy == 0 && app_wdf_rdy == 1) begin
app_wdf_wren <= 0;
app_wdf_end <= 0;
end
end
- 读书主要部分代码
READ: begin
app_cmd <= 3'b001;
app_en <= 1;
app_addr <= rd_addr_cnt;
rd_addr_cnt <= rd_addr_cnt + 8;
DDR_RD_CNT <= DDR_RD_CNT + 1;
DDR3_STATE <= READ_0;
end
READ_0: begin
if(app_rdy == 1) begin
if(DDR_RD_CNT >= WRITE_SIZE)
begin
DDR_RD_CNT <= 16'b0;
app_en <= 0;
DDR3_STATE <= NOP_0;
end
else begin
app_addr <= rd_addr_cnt;
rd_addr_cnt <= rd_addr_cnt + 8;
DDR_RD_CNT <= DDR_RD_CNT + 1;
end
end
end
- 仿真模型
图中的DDR3的例子模块是在DDR3中的仿真模块中复制过即可使用,具体模块位置和名字如下:
首先是打开DDR3中的例子工程,找到其中的仿真文件,打开其子目录找到如下模块:
具体的例化模型如下图,双击顶层的模块sim_tb_top,找到下图中的位置
本次工程例化的是16bit的DDR3,可以参照如下进行例化
ddr3_model u_comp_ddr3
(
.rst_n (ddr3_reset_n),
.ck (ddr3_ck_p),
.ck_n (ddr3_ck_n),
.cke (ddr3_cke),
.cs_n (ddr3_cs_n),
.ras_n (ddr3_ras_n),
.cas_n (ddr3_cas_n),
.we_n (ddr3_we_n),
.dm_tdqs (ddr3_dm),
.ba (ddr3_ba),
.addr (ddr3_addr),
.dq (ddr3_dq),
.dqs (ddr3_dqs_p),
.dqs_n (ddr3_dqs_n),
.tdqs_n (),
.odt (ddr3_odt)
);
多位宽的可以查找其它博主进行设计。
5、仿真结果查看
上图是写数据的时序,可以看到我们往地址0里面写的数据是100,地址8里面写的是101
我们查看读数据部分,
查看上图我们给出了读数据的指令,地址从0开始加;
从上图中可以看到读出的第一个数据是100,后面依次验证正确。
6、设计心得
因为这是我第一次写的博客,有很多问题,如果有误,还望指正。DDR3使我们开发设计中经常用到的,所以学会使用它,对我们的帮助很大,前期我也查看了其它博主使用的对齐模式,我自己也测试过,不知道为什么最后仿真总是读不出数据,最后才使用这种模式,大家只需要知道,写指令和写数据其实是两个分开的,没有多大关系,可以先写数据在给指令。这个大概就分享到这里。本篇设计是参考https://blog.csdn.net/m0_52840978/article/details/121304187这个博主的DDR3设计。说的很详细很透彻。