尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Vivado MIG IP核配置FPGA DDR4读写全流程详解:从参数选型到仿真验证

Vivado MIG IP核配置FPGA DDR4读写全流程详解:从参数选型到仿真验证 我第一次想用MIG调DDR4的时候第一反应是去翻Vivado官方手册。结果翻开UMG586一千多页瞬间就没了脾气。后来踩了几个星期的坑才明白日常开发里真正需要搞透的配置路径就那么几条MIG已经把DDR4最复杂的物理层、训练校准算法全部封装好了我们要做的只是把图形界面里的参数选对、管脚约束别瞎改、仿真验证别偷懒。这篇文章就把我自己配置Vivado MIG IP核驱动FPGA DDR4的完整过程拆开讲一遍从整体设计思路、关键参数怎么选到XDC约束怎么写、仿真和板级验证怎么做全部按实操顺序来适合刚入手DDR4开发板、或者正在自研板卡想验证DDR4读写链路的朋友直接参考。文章里所有内容都以Vivado 2022.2为例如果你的版本不同部分界面布局会略有差异但核心思路完全一致。1. 先把全局盘明白DDR4接口为什么非得靠MIG1.1 DDR4接口的复杂度比你想象的高得多很多人觉得DDR4接口不就是“把读写命令发给内存条”嘛远没有这么简单。DDR4正常工作依赖一整套初始化训练流程包括CKE上电时序、ZQ校准、MR寄存器配置、Write Leveling写级联、Read Leveling读级联、DQS Gate训练等等。这一串流程走完控制器才知道每个字节通道的DQ/DQS相位偏差是多少、窗口偏移该补偿多少然后才能开始正常的读写操作。如果从零开始写RTL控制器你得把JEDEC标准里几百页的时序参数吃透光是一个tRCD、tRP、tRFC之间的约束关系就够让人头大。更麻烦的是DDR4颗粒的时序参数不是死的温度电压变化时还要做动态刷新和重训练这些逻辑放在用户逻辑里实现完全不现实。所以Xilinx在Vivado里给了MIG这个现成的免费IP核它的本质是PHY物理层、Memory Controller存储控制器、训练校准算法全部封装好的软核。在UltraScale系列器件上MIG还会调用硬核DDR Memory控制器7系列则用软核PHY加硬核IO实现。对我们开发者来说MIG就像一个“内存黑盒翻译器”用户接口侧是简单好用的读写信号DDR4内存条侧由它去处理所有物理时序和训练细节。1.2 动手前先定三个决策接口类型、运行频率、数据位宽配置MIG之前有几个决策必须先想清楚不然进到向导里会反复纠结。第一个是接口类型。MIG对外提供三种接口AXI4、AXI4-Lite和Native User Interface也叫Native UI或App接口。AXI4适合需要高吞吐、持续读写的场景比如视频帧缓存、网络报文缓存AXI4-Lite适合量小的配置类访问Native UI最底层信号全部是app_*前缀控制粒度最细适合搞自定义协议或者对延迟特别敏感的应用。我的建议是如果你不打算接AXI总线互联就用Native UI它最直接调试波形也最容易看懂如果后续要跟Zynq的PS端或者DMA IP互通用AXI4更省事。第二个是运行频率。JEDEC标准里DDR4有1600、1866、2133、2400、2666、2933、3200等多个档位淘宝上常见的DDR4内存条标称默认2666意思是等效数据率2666MT/s。注意这里有个坑DDR是双沿采样2666MT/s对应的实际时钟频率是1333MHzMIG配置界面里说的“Memory Clock”指的是等效数据率还是实际频率一定要看清楚。第三个是数据位宽。目前常见的DDR4颗粒有x8和x16两种组织方式。x8颗粒凑64位数据总线需要8颗x16颗粒需要4颗。MIG配置时要把“Data Width”选成跟硬件颗粒组一致选错的话要么管脚不够用要么带宽达不到预期。1.3 时钟和复位拓扑差分时钟优先复位必须同步处理MIG对时钟非常敏感。在配置页面的“System Clock”选项里有“No Buffer”“Single Ended”“True Differential”三种模式。如果板子上给DDR4提供的是LVDS差分时钟一定要选True Differential这样MIG内部会自动用IBUFDS把差分信号转单端。如果把差分时钟选成了Single Ended综合能过但实现阶段几乎必然报管脚约束或时钟资源相关错误而且抓都抓不到。还有参考时钟选项“Reference Clock”这个主要用于PHY内部延迟链的参考。通常可以跟System Clock共用也可以单独给一个200MHz左右的时钟。7系列器件上MIG对参考时钟频率有一定要求Vivado向导会自动校验并给出允许范围如果输入的参考时钟不满足条件页面会红字提示照着改就行。复位信号也容易埋雷。MIG的sys_rst信号是低有效异步复位但不是随便拉低再拉高就能用。它必须与System Clock同步之后送给MIG而且上电后要保证至少200us的稳定低电平时间做DDR4初始化。很多人在仿真里直接给sys_rst拉高拉低结果初始化根本没起来还以为是配置错了。正确做法是用一个简单的同步器把外部复位同步到MIG的时钟域至少打两拍再送进去。2. MIG配置界面逐项拆解照着填就行2.1 新建IP核的第一步选对IP类型和版本在Vivado左侧IP Catalog搜索框里输入DDR会出现两个容易混淆的条目一个是“DDR3 SDRAM (MIG)”另一个是“DDR4 SDRAM (MIG)”。不要手滑选成DDR3虽然它俩界面长得几乎一样但从配置参数到生成的时序约束完全是两套东西。选定DDR4 MIG后IP核名字保持默认的mig_7series_0或者dDR4_0就行但注意IP核所在路径不要带中文。这里给大家一个血的教训我最早一个工程放在D盘新建的“DDR4测试”文件夹里Vivado的IP核生成脚本对中文路径支持非常差综合时疯狂报错最后只能把整个工程搬家重来。关于Vivado版本如果你用的是7系列器件DDR4的MIG在Vivado 2019.2之后才比较稳定2020.1以后全面成熟如果你用UltraScale系列建议直接上2022.2或更新的版本。老版本Vivado的MIG对DDR4支持有限尤其是高频率颗粒生成时就会报“not supported”所以不要在一个老版本上死磕。2.2 配置页面的关键参数从Mode到Controller OptionsMIG向导打开后第一个要选的是“Mode”是Normal还是AXI4。这里说的AXI4就是对外接口类型。我这次工程用Native UI选Normal对外接口在后面的页面里再细化。“Memory Selection”页面选择颗粒型号。Vivado内置了不少常见厂商的DDR4模型Micron、Samsung、SK Hynix都有。如果你的板子用的是内存条插槽颗粒型号选择DDR4 DIMM类型数据宽度一般64bit如果用的是板载DDR4颗粒就选Component类型宽度按实际颗粒组来。找不到完全一样的型号没关系选一个同厂家、同容量、同速度等级、同数据宽度、同bank数的近似型号即可MIG只是拿这个模型做时序计算和仿真不是写死在硬件里。“Controller Options”页面里有几个参数需要仔细看。Memory Clock决定实际运行频率我习惯保守一点优先选2400或2133跑通了再往上调。因为对FPGA来说DDR4跑到2666需要高速等级器件配合良好的PCB信号完整性如果时序收敛不了降频率是性价比最高的解法。Burst Length选8DDR4是预取8n架构BL8是默认最优值不要动它。CAS Latency和CWL根据频率自动生成不要手动改改乱了初始化训练会出事。2.3 Address Mapping和Bank Group别小看这两个下拉框“Address Mapping”这个选项容易被忽略但它直接影响后续读写测试能不能顺利对上地址。默认选项是“ROW_BANK_COL”也就是地址先按行、再按bank、再按列变化。这个顺序在逻辑地址上是连续的做图像缓存、帧缓存这类按顺序突发访问的场景非常友好。如果把映射改成“BANK_ROW_COL”逻辑上的连续地址会被拆散到不同bank虽然理论上能利用bank并行性但用户逻辑访问时地址计算极其别扭而且MIG内部调度的收益并不明显。DDR4的Bank Group选项也跟带宽相关。DDR4每个die里有4个Bank Group每个BG包含4个Bank。如果MIG配置界面里出现“Bank Group”选项说明颗粒大概率支持BG并行调度。保持默认即可这个参数跟颗粒物理结构绑定不是性能调优参数。2.4 IP生成后的三个关键产物模板、XDC、用户接口信号点击Generate之后MIG会生成一堆文件。其中三个最重要第一天接触MIG的人务必搞清楚。第一个是实例化模板在Sources面板里找到生成的.v/.vhd文件右键Open IP Example Design可以看到完整可综合的example工程。强烈建议第一次调DDR4的人先跑一遍example design它的顶层把MIG的复位、时钟、用户接口全连好了还带一个简单testbench。第二个是管脚约束文件通常以“_pins.xdc”结尾里面是MIG根据你选的颗粒和FPGA封装自动计算的管脚位置。第三个是时序约束文件负责输入延迟、输出延迟、时钟约束等等。用户接口侧有一套app_*信号用Native UI时主要关心这几个app_addr32位地址、app_cmd命令0是写1是读、app_en命令有效、app_rdyMIG准备好接收命令、app_wdf_data、app_wdf_wren、app_wdf_rdy写数据通道有效和就绪、app_rd_data、app_rd_data_valid、app_rd_data_end。这套握手和AXI的valid/ready双向拉低机制不一样命令通道握手是app_en拉高且app_rdy为高时生效写数据通道握手是app_wdf_wren拉高且app_wdf_rdy为高时生效两边要分别看不要误以为拉到一起才是有效。3. 管脚约束与Implement逃生路线别再被红色吓住3.1 管脚分配不是你写了物理引脚就万事大吉MIG生成管脚约束时是根据FPGA封装的DDR4专用管脚自动分配的。如果板卡原理图遵循了Xilinx DDR4设计规范这些自动分配的管脚直接可用。问题多出现在自定义板卡上硬件工程师很可能为了布线方便把DQ/DQS的管脚顺序打乱了。DDR4的DQ和DQS是分Byte Group组织的每个Byte Group包含8个DQ位和1对DQS差分信号。MIG的管脚约束允许同一个Byte Group内部的DQ位进行交换也允许一对DQS的P/N互换但绝对不允许把不同Byte Group的DQ混在一起。这是很多人改XDC时犯的致命错误拿着板卡原理图一看“DQ0在L14引脚DQ1在M14引脚”就直接把MIG生成的约束文件里的引脚值改了根本不看这个位置原本属于哪个Byte Group。结果实现阶段报出大量管脚冲突或者内部逻辑无法连接的错误。正确做法先找到MIG生成的_pins.xdc里面每个PACKAGE_PIN后面都跟着对应的信号名比如dqi[0]、dqi[1]。对照板卡原理图确认每个DQ/DQS信号确实连到了对应的Byte Group管脚上。如果硬件改了DQ顺序只需在同组内修改PACKAGE_PIN值即可不要动信号名和IOSTANDARD等属性。3.2 DRC rtstat-2和Implement Design变红的真实原因热词里反复出现“vivado 报错 drc rtstat-2”和“vivado implement design变红”这两个确实是我见过最多人卡住的地方。rtstat-2这个DRC错误讲得直白一点就是异步时钟域约束缺失或者时钟资源冲突。在MIG设计里最常见的有三种诱因。第一System Clock选了True Differential但顶层模块里没有把差分时钟正确连到MIG的sys_clk_p/sys_clk_n端口导致IBUFDS资源缺失。第二设计里还有其他异步时钟域但没有声明set_clock_groups -asynchronousVivado默认把它们当作相关时钟来约束结果一堆路径违例。第三多个时钟源接到了同一个BUFG资源造成复用冲突。Implement Design变红则复杂一些。Vivado的Implement包括Opt Design、Place Design、Route Design三个子步骤任意一个跑不完、跑不过、或者时序严重违例都会让整个步骤红掉。不要一红就慌着清工程先点开Implementation窗口底部的Log看具体是哪个子步骤报错。很多时候是时序违例导致Route后WNS最差负时序裕量为负Vivado判定失败。遇到这种情况先回MIG配置降一档频率或者检查XDC里有没有过紧的输入输出延迟约束。3.3 XDC约束要点时序约束不是装饰品MIG生成的XDC分两类一类是管脚约束另一类是时序约束。时序约束文件里最核心的就是set_input_delay和set_output_delay它们告诉综合工具DDR4颗粒的建立保持时间窗口工具才能合理优化PHY内部延迟链。很多新手把这两行约束删掉或者乱改觉得“我在仿真里明明能跑通”结果上板后读写数据时对时错。我建议第一次上手XDC文件一个字符都别改直接用example design提供的整套约束。等整个链路跑通后再根据自己的应用需求增加额外约束。如果想验证DDR4在板卡上的时序质量可以打开Vivado的Memory Calibration Debug工具在Hardware Manager里能看到每个Byte Group的校准窗口余量这是判断硬件信号完整性的第一手资料比看WNS有用得多。4. 仿真与板级验证初始化通过才算成功一半4.1 先跑example design仿真看懂初始化状态机MIG的example design自带一套仿真环境和testbench路径通常在IP所在目录的example_design/sim下。仿真前需要确认Vivado已经编译了对应器件的仿真库尤其是DDR4的memory model。如果没编译仿真会报找不到单元库跑不起来。仿真时间不要设太短。DDR4的初始化训练要经历上电延时、DQS训练、地址训练等多个阶段在ModelSim或Vivado Simulator里跑完整轮可能要看几十万到上百万个时钟周期。我第一次跑只设了10us结果一直看到init_calib_complete拉高后来把仿真时间拉到100us才看到完整过程。仿真窗口里主要盯着init_calib_complete信号它拉高代表训练完成。如果一直拉不高基本可以判定配置参数或颗粒型号选得不对先回配置页面检查。4.2 用ILA抓板级波形写一组读一组别偷懒example design的testbench在板级也能用但真正上板调试还是要靠ILA。建议抓取这些信号clkUI时钟、app_rdy、app_wdf_rdy、app_cmd、app_addr、app_en、app_wdf_wren、app_wdf_data、app_rd_data_valid、app_rd_data。触发条件可以设成app_en拉高这样能抓到完整的命令握手过程。写读测试的逻辑很简单初始化完成后先对某个地址写一串递增数据再对同一地址发起读命令把读回来的数据跟写进去的对比。这个操作看着基础但能暴露不少隐藏问题。比如我遇到过写地址和数据分别握手成功但app_addr和app_wdf_data没有对齐导致数据写到了错误地址读回来全是0排查了很久才发现是写数据通道延迟拍数没匹配上。另一个典型问题是burst length导致的地址伪错。DDR4 BL8一次突发传输8个数据如果测试逻辑只写了单个数据读回来会看到8个数只有第一个数是对的后面7个全是随机值。这不是MIG配置问题是测试逻辑忽略了DDR的突发特性。正确做法是每次读写都按8的倍数地址对齐或者把MIG的地址线按burst方式递增。4.3 常见问题速查表直接对照排查现象可能原因排查手段init_calib_complete一直为低颗粒型号配置不对、时钟频率超限、sys_rst复位时序不满足检查MIG配置确认时钟种类和频率复位拉低至少200us后再释放仿真中命令握手成功但读数据全为0写了10但没按BL8突发对齐、地址计算错误、interface连接错误检查app_addr递增规律用ILA对比写入和读出的地址区间上板后数据偶发错误时序裕量不足、电源噪声、PCB信号完整性差用Memory Calibration Debug看各byte group窗口余量必要时降频或调整参考时钟Implement后WNS严重为负MIG运行频率接近器件极限、XDC被改坏先降频验证再检查XDC是否有误改最后考虑调整约束优先级rtstat-2报错时钟资源冲突、异步时钟域未声明检查sys_clk连接、BUFG使用情况、set_clock_groups设置5. 折腾完这一圈我的一些实在心得搞了一轮MIG配DDR4之后我最想分享的一条经验是配置IP核本身并不难难的是不跳步。很多人为了省时间跳过example design仿真直接改自己的逻辑上板结果初始化都没过就在找代码bug白白浪费好几天。老老实实先把example design在Vivado里综合、实现、生成比特流下载到板子上看到init_calib_complete拉高再动自己的逻辑这个节奏是最稳的。另外一个小技巧Vivado里右键生成的MIG IP核可以直接“Open IP Example Design”它会自动帮你建好一个独立工程里面带完整的仿真和约束。第一次接触DDR4的朋友哪怕不用它做最终设计也可以拿它当“标准答案”对照检查自己的配置和例化哪里不一样。最后提醒一句DDR4跑不上高频九成是硬件问题而非软件问题。软件上能做的降频、改约束都是治标想跑到颗粒标称的2666PCB的走线等长、参考层完整性、终端电阻配置都是硬门槛。我在自研板卡上调到2400就遇到了读数据偶尔翻转的问题最后是硬件改了走线版本才彻底解决这个教训分享给大家参考。
返回列表