南靖县建设局网站,开发公司工程管理岗好还是设计岗好,seo解释,大兴网站建设制作文章目录 前言1.配套工程简介2.测试内容与策略3. 测试程序分析4.程序结果分析5.一个IP控制两颗DDR36.传送门 前言 以四颗MT41K512M16HA-125AIT颗粒为例#xff0c;介绍如何在一块新制板卡上做关于DDR3的器件测试。前面两篇介绍了什么是DDR#xff0c;并介绍了xilinx给出的FPG… 文章目录 前言1.配套工程简介2.测试内容与策略3. 测试程序分析4.程序结果分析5.一个IP控制两颗DDR36.传送门 前言 以四颗MT41K512M16HA-125AIT颗粒为例介绍如何在一块新制板卡上做关于DDR3的器件测试。前面两篇介绍了什么是DDR并介绍了xilinx给出的FPGA与DDR完美结合的方案MIG IP核,请按照顺序阅读DDR相关文章链接在文末。DDR3颗粒DDR3内存条DDR4颗粒DDR4内存条都可以与FPGA相连DDR芯片选型以及链接形式选型与系统对于数据带宽的要求存储容量的要求对结构的要求息息相关同时不同形式不同代DDR对FPGA选型提出了要求本文介绍DDR3颗粒与FPGA相连实现读写测试。 1.配套工程简介
提供了两套DDR3颗粒测试工程工程文件名是DDR3_2PCS800MHzDDR3_4PCS400MHz对应2片DDR的800Mhz读写测试4片DDR的400Hz读写测试。此外还有DDR4颗粒测试工程和DDR3内存条测试工程。两套DDR3颗粒测试工程主控芯片是xilinx xc7k325tffg900-2颗粒是MT41K512M16HA-125AITvivado版本是2020.2。不同的速度测试实际上只需要修改IP里面的配置即可。2片与4片的区别是一次DDR引脚时钟写入DDR的数据量是32bit和64bit的区别MIG IP是按照8倍突发工作即一个ui_clk用户时钟MIG读取8个地址的数据所以2片与4片会导致MIG IP的数据总线是256bit和512bit的区别。为了读者能够快速应用到自己的场景提供的工程做了区分。需要说明的是工程应用在本地需要注意切换相应的时钟输入切换DDR的UCF文件切换指示灯的链接如果有更多的指示灯则可以接TEST_LENGTH相关的计数器指示一次测试结束或者指示MIG IP的初始化结果。如果FPGA的型号不同或者DDR颗粒不同建议重新创建工程进行测试并且根据对应芯片重新计算TEST_LENGTH。例程都是按照app接口进行控制在DDR3_4PCS400MHz中提供了一个block design可以置顶编译综合布线生成bit后使用tcl的命令便捷读写指定位置用在定位某个确定位置的读写这个block design用的是DDR 的AXI接口。 需要注意本例的DDR颗粒不在MIG IP所直接支持的列表中因为通过查询手册自定义了一个DDR型号如下图所示。
2.测试内容与策略
通过写入和读出判断读写过程是否正确此外工程实践中会遇到当工作频率高的时候DDR读写不稳定 因此必要进行速度测试。此外还应进行容量进行测试。一个测试工程对上述三项全部测试在MIG的平面地址接口中按照地址顺序写入确定的已知值然后在按照相同顺序读出这些已知值做比较相同则常亮led表示测试通过否则led闪烁表示测试失败。
3. 测试程序分析
附verilog测试代码省略了模块例化部分程序步骤解读如下 ①例化clk ip产生200MMIG参考电压输入 ②例化MIG ip通过app接口读写ddr数据 ③写两段式状态机为进行容量测试写至满容量的90%即可。写完切换至读状态若读写无误则一直读写。Wr_addr_cnt或者rd_addr_cnt每计数一次app_addr_begin自增8这是因为当工作频率配置为800MHz且用户时钟ui_clk与工作频率的比值配置为41时ui_clk为200MHz。四片DDR3的数据位宽为64bit由于”“DDRdouble data rate”所以在每一个800MHz周期应该提供128bit数据因此每一个200MHz周期应该向MIG提供512bit数据。而在单一内核中每一个平面地址存储位数为16bit四片即64bit那512bit/64bit8即一个200MHz周期的512bit数据写入了8个平面地址因此此处一次突发即Wr_addr_cnt或者rd_addr_cnt每计数一次app_addr_begin自增8。 该颗粒平面地址空间有1610329bit上一段的描述提到一次突发需要8个地址那么满容量可以进行多少次突发即2^29(满地址)/867108864将TEST_LENGTH设置为32’d60000000即写了60000000/6710886490%的空间这样可以满足容量测试的要求。 ④结合状态机运行状态和MIG返回的指示信号为app接口信号赋值此处应结合各信号含义和接口时序核准。 ⑤用户判错逻辑写入和读出的都是从0开始递增的数据当出错时指示灯闪烁。
parameter TEST_LENGTH 32d60000000;
//***********1.先写后读状态机state machine
parameter IDLE 2d0;
parameter WRITE 2d1;
parameter WAIT 2d2;
parameter READ 2d3;
reg [511:0]my_512_data;
reg [25:0] wr_addr_cnt;
reg [25:0] rd_addr_cnt;
reg [1:0] state;
always (posedge ui_clk or negedge rst_n) beginif((~rst_n)||(error_flag)) begin state IDLE; my_512_data 512d0; wr_addr_cnt 26d0; rd_addr_cnt 26d0; app_addr_begin 30d0; endelse if(init_calib_complete)begin //MIG IP核初始化完成case(state)IDLE:beginstate WRITE;my_512_data 512d0; wr_addr_cnt 26d0; rd_addr_cnt 26d0; app_addr_begin 30d0; endWRITE:beginif((wr_addr_cnt TEST_LENGTH-1) (app_rdy app_wdf_rdy))state WAIT; //写到设定的长度跳到等待状态else if(app_rdy app_wdf_rdy)begin //写条件满足my_512_data my_512_data 1; //写数据自增wr_addr_cnt wr_addr_cnt 1; //写计数自增app_addr_begin app_addr_begin 8; //DDR3 地址自增end else begin //写条件不满足保持当前状态my_512_data my_512_data; wr_addr_cnt wr_addr_cnt;app_addr_begin app_addr_begin; endendWAIT:begin state READ; //下一个时钟跳到读状态rd_addr_cnt 26d0; //读地址复位app_addr_begin 30d0; //DDR3读从地址0endREAD:begin //读到设定的地址长度 if((rd_addr_cnt TEST_LENGTH -1 ) app_rdy)state IDLE; //则跳到空闲状态 else if(app_rdy)begin //若MIG已经准备就绪,则开始读rd_addr_cnt rd_addr_cnt 1d1; //用户地址每次加一app_addr_begin app_addr_begin 8; //DDR3地址加8end else begin //若MIG没准备好,则保持原rd_addr_cnt rd_addr_cnt;app_addr_begin app_addr_begin; endenddefault:beginstate IDLE;my_512_data 512d0;wr_addr_cnt 26d0;rd_addr_cnt 26d0;app_addr_begin 30d0;endendcaseend
end
//********2.根据状态机与MIG指示信号为app信号赋值
assign app_en ((state WRITE (app_rdy app_wdf_rdy))||(state READ app_rdy)) ? 1b1:1b0;
assign app_cmd (state READ) ? 3d1 :3d0;
assign app_wdf_wren(state WRITE (app_rdy app_wdf_rdy)) ? 1b1:1b0;
assign app_wdf_end app_wdf_wren;
assign app_addr app_addr_begin;
assign app_wdf_datamy_512_data;
//****************3.用户判错逻辑
reg [25:0] rd_cnt;
wire rst_n; //复位低有效
reg error_flag;
parameter L_TIME 28d200_000_000;
reg [27:0] led_cnt; //led计数
wire error; //读写错误标记
assign rst_n ~ui_clk_sync_rst;//myrst
always (posedge ui_clk or negedge rst_n) beginif(~rst_n) rd_cnt 0; //若计数到读写长度且读有效地址计数器则?0else if(app_rd_data_valid(rd_cnt TEST_LENGTH - 1))rd_cnt 0; //其他条件只要读有效每个时钟自增1else if (app_rd_data_valid)rd_cnt rd_cnt 1;
end
//判断错误读出数据应为计数递增数据
assign error (app_rd_data_valid (rd_cnt!app_rd_data));
always (posedge ui_clk or negedge rst_n) begin
if(~rst_n)led20;
else if(rd_cnt32d50000000)led21;
end
always (posedge ui_clk or negedge rst_n) beginif(~rst_n) error_flag 0;else if(error)error_flag 1;
end
//读写测试正确指示灯led1常亮反之则闪烁
always (posedge ui_clk or negedge rst_n) beginif((~rst_n) || (~init_calib_complete )) beginled_cnt 28d0;led1 1b0;endelse beginif(~error_flag)led1 1b1;else beginled_cnt led_cnt 28d1;if(led_cnt L_TIME - 1b1) beginled_cnt 25d0;led1 ~led1;endend
end
end4.程序结果分析
正常结果可以看到与上一节MIG IP给出的时序是一致的。 ●写开始时序 ●写结束时序 ●读开始时序 ●读结束时序 测试的结果最好通过读写一定量并且读写指示灯亮确认。当测试异常时应按照DDR是否初始化成功、MIG app接口时序是否正确、MIG ip配置是否正确、状态机运行状态是否异常方面入手分析。DDR初始化不成功init_calib_complete为0可能的原因是时钟输入与MIG IP配置不一致MIG端口没有正确连接DDR的UCF约束有问题。
5.一个IP控制两颗DDR3
如下原理图可以清楚的看到两颗DDR3的相同的控制线连在了一个控制器的相同引脚而数据线是各自连的。在PCB布线的时候通常用fly_by的方式连接DDR3。对于FPGA而言把外部的位宽为16bit的两颗DDR当成了一个位宽为32bit的DDR3来控制。这种往往是为了扩大容量或者为了匹配rank位宽或者为了提升带宽将两片或者四片甚至更多片DDR3放在一起。对于这种场景只需将上一篇IP配置第5步中的data width设置为实际芯片加起来的位宽即可。如两片16bit位宽颗粒相连则设置位宽为32bit即可。其余的用户逻辑且把他当作一片位宽为32bit的DDR3即可。实际上用户存入的32bit数据在实际存放时高位16bit和低位16bit的数据被放到不同的两片DDR3中唯一的关联就是这两个位置的物理值是相等的而已。
6.传送门
我的主页FPGA通信接口专栏汇总导航上一篇MIG IP核的使用DDR3测试工程
END
文章原创首发于CSDN论坛。 欢迎点赞❤❤收藏⭐⭐打赏 欢迎评论区或私信指出错误❌提出宝贵意见或疑问❓。