ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

5分钟搞定FPGA时钟:Xilinx MMCM配置指南

5分钟搞定FPGA时钟:Xilinx MMCM配置指南 FPGA新手必看5分钟搞定Xilinx Clocking Wizard的MMCM配置附Vivado截图有没有这样一种经历写好了一个漂亮的状态机仿真全绿上板之后DDR读写乱掉、串口数据对不上甚至整个工程跑飞。我刚开始做FPGA那会儿第一块板卡子的教训就是——时钟没配好。直接从板卡晶振拉了一个100M引脚出来以为接上去就完事结果所有同步逻辑全部亚稳态上线抓了整整两天波形才意识到问题出在时钟树。从那以后凡是涉及跨时钟、倍频、分频、相位偏移的场景我都老老实实打开Vivado里的Clocking Wizard配置MMCM。别小看这个IP它是Xilinx FPGA整个时钟网络的枢纽把板级进来的低速时钟转变成你想要的、低抖动、不同频率、不同相位的时钟信号。这篇文章就把配置MMCM的全过程、背后逻辑、踩坑点一次性讲清楚新手照着做就能出活。1. MMCM到底是什么为什么你的FPGA离不开它1.1 从接线到时钟树关于FPGA时钟的认知升级很多新手最初理解时钟就是一个引脚连到always (posedge clk)上。但实际上FPGA内部的时钟网络远比这复杂。芯片内部有成千上万个触发器FF如果每个FF都直接从板级晶振引脚拉一根长线过去电源完整性和信号完整性问题足以让整个设计崩溃。所以Xilinx在芯片内部内置了专门的时钟资源包括全局时钟缓冲器BUFG、时钟管理模块CMT等。你用Clocking Wizard配置MMCM本质是让工具帮你例化并连接这部分专用硬件资源而不是自己写逻辑去生成时钟。MMCM的全称是Mixed-Mode Clock Manager混合模式时钟管理器是Xilinx 7系列及其之后器件包括Zynq的核心时钟组件。它能在内部对输入时钟做倍频Multiply、分频Divide、相位调整Phase Shift、占空比修正Duty Cycle Correction。很多初学ASIC的同学第一次看到MMCM的输出列表会犯迷糊为什么同一个MMCM可以同时输出好几个不同频率的时钟这正是因为MMCM内部有多个分频器配合内部的VCO压控振荡器工作频率每次输出的频率都是VCO频率除以各自的输出分频系数。1.2 MMCM内部的关键路径VCO、分频器和反馈环路为了在配置时心里有数你得知道MMCM的几个核心参数是怎么配合的输入时钟CLKIN从专用时钟引脚或者普通IO进入必须经过BUFG或IBUF频率范围一般从几MHz到几百MHz具体看器件手册。DIVCLK_DIVIDE前置分频先把输入时钟分频这个值主要用于压低进入PFD鉴频鉴相器的频率常见值为1。CLKFBOUT_MULT_F反馈倍频这是最关键的倍频系数决定内部VCO的输出频率典型范围是2到64支持小数。VCO频率计算方式是输入时钟 ÷ DIVCLK_DIVIDE × CLKFBOUT_MULT_F。这条频率必须落在器件规定的VCO范围内例如7系列一般是600MHz到1440MHz具体型号有细微差异。CLKOUT0~6每一个输出通道配置各自的输出分频系数CLKOUT_DIVIDE_F把VCO频率分频到你想要的频率。你可以把VCO想象成一个水塔输入时钟就是自来水倍频器相当于水泵先把水抽到水塔输出分频器则是水塔下面接的各个水龙头每个水龙头可以按需调流量。这样的架构决定了MMCM的输出频率之间天然存在数学关系并不是随便填几个频率都行Vivado的Clocking Wizard会在你填目标频率时自动计算合法的分频系数我们后面会看到。2. Vivado里Clocking Wizard配置全流程5分钟上手的实操路径2.1 创建IPIP Catalog里的入口打开Vivado工程在左侧Flow Navigator找到IP Catalog如果界面布局不同可以在Tools菜单里找到。在搜索框输入Clocking Wizard双击打开配置窗口。先注意IP核名字下方显示的版本Vivado 2020.2里通常是7.2不同版本的界面微妙差异但核心选项卡基本一致。进入配置页后你会看到一个多步骤的向导结构。Clocking Wizard支持两类配置风格Clock Network Options时钟网络选项包括单端时钟差分时钟MMCMPLL等。Output Clock Options输出时钟选项设置每个输出的频率、相位、占空比。要真正生成MMCM关键是在第二步Clocking Features里勾选MMCM而不是PLL并设置恰当的输入时钟频率。2.2 第一步输入时钟设置从板级事实出发我习惯在动手配置前先把板卡原理图打开看清楚时钟输入是单端还是差分频率是多少。不同板卡差别很大比如很多开发板用50MHz或100MHz单端有源晶振也有用200MHz差分时钟给高速接口的。打开Clocking Wizard的Page 1重点设置Input Clock Information输入时钟信息输入频率填入晶振的实际值比如100MHz。如果是差分输入选择差分Differential并确保使用了专用的时钟引脚对例如一个MRCC或SRCC引脚对。Source时钟源一般选External外部由板级时钟进入如果你想把MMCM级联、从头一个MMCM的输出接到下一个MMCM需要选Global bufferBUFG或MMCM/PLL output。这里有一个新手容易忽略的点输入时钟的专用引脚约束。Vivado在综合和实现时会自动检查你给的时钟约束create_clock是否落在了FPGA的专用时钟引脚上。如果你把一个普通GPIO接上晶振信号工具会报错或者给出严重警告因为GPIO进入内部路径不是走全局时钟网络连线延迟和抖动都会显著增大。所以配置IP之前最好先把XDC约束里的时钟主约束写好例如create_clock -period 10.000 -name sys_clk [get_ports clk_100m]这里period单位是ns10ns对应100MHz。如果你用的是XDC记得把这句和引脚分配的set_property放一起。2.3 第二步选MMCM并配置输出时钟频率翻到Page 2Clocking Features这是核心配置区。我的习惯操作顺序是先在左上方的Clocking Options区域把Clock Management设置为MMCM。在MMCM Settings区域查看自动计算的频率关系。这里还有一个Frequency Synthesis选项选Simple还是Advanced建议新手保持默认的Simple让工具根据目标频率自动找系数。向下找到Output Clocks区域逐个使能你需要的输出通道填目标频率。举个例子假设我在做一个视频处理项目输入时钟是100MHz需要产生以下几个时钟输出通道用途目标频率clk_out1逻辑主时钟150MHzclk_out2DDR控制器时钟200MHzclk_out3串口/慢速外设时钟25MHzclk_out4MIPI或PHY字节时钟50MHz这是一个非常典型的MMCM多输出应用场景。Clocking Wizard拿到目标频率后会计算VCO频率和各个分频系数。比如它可能选择VCO频率 100MHz ÷ 1 × 3 600MHzclk_out1 600MHz ÷ 4 150MHzclk_out2 600MHz ÷ 3 200MHzclk_out3 600MHz ÷ 24 25MHzclk_out4 600MHz ÷ 12 50MHz。如果不看内部计算只看到最终数字新手很容易以为这些输出是独立设置的其实它们背后被同一个VCO锁着。这就是为什么在Clocking Wizard里修改一个输出频率另一个输出频率往往会被联动调整的原因。填完频率后还要注意相位Phase和占空比Duty CyclePhase相位以输入时钟周期为单位可设置为0度、90度、180度、270度等单位是度。对DDR、SDRAM这类源同步接口非常关键例如DDR3的DQS相对时钟经常需要90度相移。Duty Cycle占空比默认50%一般不需要动。只有像某些ADC/DAC驱动时钟要特殊占空比时才改。2.4 第三步复位与锁定信号的处理Clocking Wizard会自动生成两个重要信号reset和locked。配置页里一般会有Reset Type选择同步复位还是异步复位。我一般选Active High高有效并接一个小脉冲释放逻辑。Locked信号MMCM锁定完成后输出为高。上板时我会在main逻辑里用locked信号做系统复位。具体做法是rst_sys !locked只有当MMCM在几百微秒内锁定后整个同步逻辑才开始工作。这一点至关重要特别是新手在写testbench时可能忽略。你的仿真环境里如果首先生成了MMCM必须等待locked变高之后再去驱动其他逻辑。如果无视locked直接拉高复位释放硬件上大概率会出现莫名其妙的启动问题。2.5 生成后的代码与例化模板配置完成后点击OK会弹出Generate Output Products选Out-of-context per IP或Global都可以建议选Out-of-context per IP编译速度快很多。生成完毕后选择Open IP Example Design可以看官方给的例化示例。不过我更推荐的做法是在source里找到生成的.v文件直接看它的顶层例化模板把实例名和端口拷贝到自己的顶层设计里clk_wiz_0 instance_name ( .clk_out1(clk_150m), .clk_out2(clk_200m), .clk_out3(clk_25m), .clk_out4(clk_50m), .locked(locked_inst), .clk_in1(clk_100m) );注意Clocking Wizard的例化模板通常没有reset端口默认复位是被禁用或做了内部处理的如果你需要复位功能得在配置页里勾选Reset端口。这个细节能省很多定位问题的时间。3. 配置过程中最容易被忽略的为什么选型逻辑与约束原理3.1 为什么MMCM的VCO频率必须落在规定范围配置MMCM时最烦的就是工具弹红字VCO frequency out of range。这说明你要求输出的频率组合在当前输入频率下找不到合法的倍频/分频组合。这是MMCM本身硬件结构决定的天花板。比如Artix-7系列VCO频率范围一般是600MHz~1440MHz如果你输入100MHz想得到一个260MHz的输出工具会尝试让VCO780MHz再÷3这没问题但如果你想得到一个5MHz的低速时钟而其他输出又要求1200MHz的VCO此时5MHz通道的出路就是从VCO分频240倍这在部分器件上不一定支持工具就会警告。所以配置MMCM的前置思维是先把所有输出频率列出来评估它们之间是否成倍数关系。如果差异太大比如一个150MHz一个1kHz就不太适合让它们共享同一个MMCM。1kHz这类极低频率时钟跑全局时钟网络不仅浪费还会因为时钟树资源限制报错。我的做法是低速时钟如1MHz以下用逻辑分频产生只在局部使用并加上(* max_fanout *)限制真正的跨模块时钟才交MMCM管。3.2 为什么必须用全局时钟缓冲BUFG连接MMCM输出每次生成Clocking Wizard工程你会看到输出端口上自动例化了BUFG例如原语名称是BUFGCE/BUFG。Vivado自动加BUFG的原因是MMCM输出信号进入FPGA内部后想要驱动分布在芯片各处的触发器必须走全局时钟网络。Xilinx 7系列的全局时钟引脚数量有限而且每条全局时钟网络的走线资源不可动态改道所以Clocking Wizard会通过约束文件帮你分配。生成后的.xdc约束里会看到类似这样的行set_property CLOCK_DEDICATED_ROUTE ANY_CMT_COLUMN ... [get_nets clk_out1_net]一般情况下不用手动修改Vivado会帮你处理好。但如果发现实现Implementation时出现Clock not arriving at MMCM一类的错误九成是引脚没有落在专用时钟输入引脚上或者某个BUFG被你手动挪走了。3.3 为什么不建议用always块自己写分频器代替MMCM有些新手为了提高可控性喜欢写这种代码reg [3:0] cnt; always (posedge clk_100m) begin cnt cnt 1b1; end assign clk_25m cnt[1];这个写法在仿真里完全没问题但上板后会产生一个严重问题clk_25m是从普通触发器输出拉出去的它不能进入全局时钟网络任何连到clk_25m的触发器都会有明显的时钟偏斜clock skew。更麻烦的是cnt[1]的翻转是在时钟沿之后Tco时间后才稳定这会导致下游采样时序非常紧张。我亲眼见过有人用这种造时钟的方式驱动UART逻辑结果误码率忽高忽低无法稳定通信。正确做法就是使用Clocking Wizard或者至少用BUFGCE原语把各种生成的时钟缓冲后走全局网络。4. 深入Clocking Wizard的每个配置页字段级拆解与建议值4.1 Page 1时钟输入、输入源与优化选项Clocking Wizard的配置在一起第一页涉及了顶层架构选择。重点字段如下字段含义推荐做法Component NameIP实例名见名知意如clk_wiz_pll_200mInput Clock Source时钟源类型板级晶振选External级联MMCM选BUFGInput Clock Frequency输入频率必须与XDC中create_clock一致Clocking FeaturesMMCM/PLL选择本教程选MMCMJitter Optimization抖动优化方式一般选Balanced或Minimize Output JittersPhase Alignment相位对齐多输出时钟如果要求对齐选Align output clocks with input如果一个工程内有多个MMCM/PLL我建议给每个Clocking Wizard的Component Name加前缀比如clk_wiz_core、clk_wiz_ddr。因为MMCM配置错误时Report里会显示出错MMCM的位置命名清晰能让你一眼定位到是哪块电路出了问题。别用Clk_gen_0这种带下划线连续数字的名字最终综合报告看多了你会疯。输入时钟频率的填写要和实际晶振完全一致。这里有个高级坑如果你的板子用了XPLL或者数字时钟管理器前级做了时钟分频/倍频实际的输入频率已经不是晶振频率本身。遇到这种情况建议先用IBERT集成误码率测试或ILA实际测量确认进入MMCM引脚的真实波形频率再填写到IP配置里。4.2 Page 2输出时钟、相位和复位逻辑Page 2是使用频率最高的页面。每个输出通道都有一个Used复选框只有勾选后才会实际生成节省资源和功耗的时钟网络。我实际项目里下面是高频的组合如果做DDR3/DDR4一般默认给出ui_clk用户接口时钟和ui_addn_clk附加时钟它们必须和MIG的时钟同源否则两个MMCM的反馈环路之间存在PLL相位差会导致读写错误。如果做PCIe或SerDes则PHY侧的时钟经常需要两个不同相位的125MHz或100MHz例如txoutclk和rxoutclk。如果做普通逻辑我习惯把所有模块需要的频率先列个表主频、接口时钟、低速总线时钟、采样时钟然后以VCO最合理的范围来选择MMCM输出。宁可少而全不要多而杂因为每多一个时钟输出就意味着一根全局时钟网络的占用。在复位逻辑部分Clocking Wizard提供Safe Clock Startup选项默认是勾上的意思是MMCM在锁定前不会输出时钟避免上电时输出毛刺导致逻辑初始化错乱。务必保持勾选。对于locked信号我还会在顶层加一级同步处理reg [1:0] locked_sync; always (posedge clk_150m) begin if (!locked) locked_sync 2b00; else locked_sync {locked_sync[0], 1b1}; end assign sys_rst_n locked_sync[1];这里其实就是把异步的locked信号同步到目标时钟域再作为系统的异步复位释放信号绝不要直接把MMCM输出的locked信号接进触发器复位端了事。4.3 低电平复位还是高电平复位取决于你的板卡Clocking Wizard里对reset端口方向有明确定义默认是Active High。你可以在核心代码里习惯用高有效也可以转成低有效。实际做项目时我见过很多开发板把FPGA的复位按键做成低有效。建议统一规定你的系统复位信号命名。如果板卡按键是低有效底层取反后送进Clocking Wizard的reset端口。如果这个细节没处理好上电后MMCM可能会一直被复位永远不会锁定后面所有逻辑休眠看起来就像死了机。这类问题排查起来极其隐蔽因为综合布线都不报错。5. MMCM配置过程中的高频踩坑连报错信息都在骗你5.1 约束文件里没有create_clock新建Vivado工程从模板生成Clocking Wizard后立刻打开约束文件检查是否导入了create_clock和set_property PACKAGE_PIN。很多新手会先把MMCM配置好再去分配引脚结果综合时发现Clock input pin has no clock buffer一类错误或者更糟的是实现后的时序报告里出现了一大堆未约束路径。时序约束是FPGA设计的灵魂特别是MMCM这类时钟产生模块。一份最小化的时钟约束至少包含set_property PACKAGE_PIN E3 [get_ports clk_100m] set_property IOSTANDARD LVCMOS33 [get_ports clk_100m] create_clock -period 10.000 -name sys_clk [get_ports clk_100m]如果板级时钟进入了MRCC/SRCC引脚Vivado会自动利用引脚边上的BUFG但要create_clock之后工具才能识别出这是一条时钟路径。没有create_clockMMCM的锁定和输出时序就无从谈起。5.2 MMCM锁定后locked信号不拉高的常见原因上板之后用ILA抓locked发现它永远停在0。别急着怀疑MMCM坏了先排查这几个点输入时钟是否真正到达MMCM引脚。用ILA观测是不可能的因为没有输出时钟到ILA。最简单是用Vivado的Hardware Manager里Bscan或者加一个ChipScope。如果工程还没生成BIT可以在MMCM输出时钟后分出一路去驱动一个翻转计数器再看LED是否闪烁。复位信号是否被长按。如果你的reset逻辑被莫名其妙拉高MMCM当然不会锁。输入时钟频率是否真的和配置一致。有些板卡晶振标注50MHz但实际是66MHz可能出现频率超范围MMCM一直在重新锁定。我记得有个案子板子回来后死活锁不上后来用示波器看晶振引脚发现焊接虚焊导致频率捕捉不到不是FPGA的问题。所以遇到locked拉不高第一步永远是上示波器量输入时钟别看波形是不是干净、频率对不对。5.3 高速设计中必须关注的抖动MMCM输出时钟虽然比普通逻辑分频干净得多但依然存在抖动jitter。在Clocking Wizard的Output Clock Settings里可以展开看每个输出频率上的总抖动估计值。7系列在不同配置下的抖动可以从几十飞秒到几皮秒不等。对带有ADC/DAC的FPGA系统这个值是关键参数。举个例子如果你用MMCM输出245.76MHz时钟驱动一个高速ADC总抖动如果超过50ps会对SNR造成可见损失。此时可以尝试降低MMCM的PLL带宽Locking/Pl属性或者改用专用的时钟芯片方案。Vivado里有一个Minimize Output Jitters选项它会通过优化VCO倍增系数来降低抖动代价可能是占用更多时钟网络资源。务必要看它实际算出的抖动值而不是只信数据手册。5.4 多路输出时钟之间的异步处理MMCM输出的多个时钟虽然频率有数学关系但并不一定是同源同步的关系——比如150MHz和25MHz之间每一个150MHz时钟沿并不都对应一个25MHz时钟沿。所以跨时钟域CDC处理必须要做的。很多新手从MMCM拿到多个时钟后就直接在顶层用其中一个时钟域的复位信号去复位另一个时钟域的寄存器这会导致亚稳态。正确做法每个时钟域用对应的locked同步复位信号所有跨时钟信号用异步FIFO或双触发器同步。在配置阶段就想清楚哪些模块工作在哪个时钟域而不是等布局布线后看着时序违例列表发呆。6. 验证配置是否正确综合报告、仿真与上板实测6.1 综合报告里的时钟网络信息综合完成后打开Report - Report Clocks可以清晰看到MMCM的输出时钟树。检查下列事项MMCM的名字和实例名是否对应所有输出时钟的频率是否是预期值每个输出时钟是否连接到了正确的BUFG资源时钟源是否是同一个输入时钟跨域路径是否被正确约束。我习惯再打开Report Timing Summary重点看Clock Skew列。如果某个寄存器路径上clock skew异常偏大就检查该路径上是否混用了BUFG和BUFHCE等不同层级资源。MMCM关闭了跨区域时钟路径时skew一般都在几十皮秒级如果出现几百皮秒甚至纳秒级的skew说明时钟约束或者MMCM配置有严重问题。6.2 仿真时不要用真实MMCM模型除非你想被卡死Clocking Wizard生成的仿真模型和真机行为几乎一致包括锁定时间和VCO启动过程。仿真一个复杂的SOC工程时如果你直接例化MMCM并一直等到锁定testbench会显得非常漫长。我个人的做法是仿真阶段用虚拟时钟代替MMCMreg clk_100m; initial clk_100m 0; always #5 clk_100m ~clk_100m; // 100MHz这样仿真速度极快好处是测试逻辑本身不受MMCM锁定等待时间干扰。但注意必须在综合前把仿真用的时钟替换回真正的MMCM输出否则上板失败。为了不遗漏我一般用宏开关控制ifdef SIMULATION assign clk_150m clk_100m; // 仿真直接给 else clk_wiz_0 u_clk_wiz (...); // 综合用MMCM endif这种双轨设计适合逻辑量大的工程但不适用于频率关系敏感的设计。如果验证DDR或者MIG必须用真实MMCM模型仿真。6.3 上板实测ILA抓取锁定和输出时钟上板验证前写一个最简单的状态机用MMCM输出的150MHz时钟驱动一个计数器并用locked作为复位。如果MMCM工作正常计数器应该连续递增。用ILA或直接观察LED就可以知道MMCM通了没有。这里有个细节ILA本身也有一个采样时钟你必须保证ILA的时钟来源也是一个稳定的MMCM输出不能直接把系统时钟拿来当ILA时钟再分频。例如你想抓MMCM的locked信号和计数器值ILA时钟就用clk_150m。否则ILA自身时钟没有你什么都看不到。我第一次调MMCM时在这浪费了半个下午——因为ILA时钟我用了100MHz原始时钟但ILA采样模块的时钟树却被工具优化掉导致采样空白。后来把ILA时钟切换到MMCM输出后一切正常。7. 扩展应用多MMCM级联与复杂时钟树的经典设计7.1 什么时候需要级联多个MMCM单个MMCM最多可以输出7路时钟CLKOUT0~CLKOUT6很多设计一个MMCM就够。但遇到以下情况要考虑级联需要同时输出一个极高频率时钟如DDR3的800MHz和一个极低频率时钟如1MHzVCO频率折中后两边分频系数都太大抖动指标差。需要先对输入时钟做去抖动净化cleanup再进入另一个MMCM做频率合成。某个MMCM的相位偏移范围不够另一个MMCM专门做精密相位调整。级联时要注意把第一个MMCM的输出时钟作为第二个MMCM的输入源必须在第二个Clocking Wizard的配置里选择Global buffer / MMCM input作为Source并且第一个MMCM的输出要分配一个BUFG连接过去。7.2 跨器件与IntelAltera的时钟资源对比有些工程师在Xilinx和Intel FPGA之间切换最容易踩的就是MMCM和Altera的PLL/IOPLL参数命名差异。Altera的PLL对应输入inclk0、输出c0/c1/c2配置工具一般直接给目标频率而Xilinx的MMCM还要考虑VCO范围和反馈系数。这不算谁好谁坏但用Xilinx时我建议始终关注VCO范围这个中间值。7.3 低功耗设计下MMCM的时钟门控MMCM支持动态切换输出频率并不能频率是硬件固定的。但你可以通过输出通道上自带的CLKOUT_EN功能或者外加BUFGCE来控制某路时钟是否跑起来。例如视频系统中空闲时不使能给DDR的200MHz时钟能显著降低功耗。实现方式有两种一是配置Clocking Wizard时勾选对应输出通道的Enable Clock Output并引出clkout0_stop控制信号二是在MMCM之后用BUFGCE原语。用BUFGCE时注意时钟门控的使能信号切换必须避开时钟边沿否则会切出毛刺。安全做法是用目标时钟域逻辑打两拍后再去门控。8. 最后再分享几个实用心得从前面的内容可以看出MMCM配置本身不难难点在于理解时钟网络和约束之间环环相扣。我自己踩过多个项目后总结了几条习惯供参考第一每次新建IP时都把MMCM的目标频率组合先写在笔记本上包括VCO频率、各输出频率、相位。然后到Clocking Wizard里一对比工具算出来不一样就说明有问题别直接点OK。第二locked信号必须做跨时钟域同步处理如果直接使用会导致复位释放瞬间亚稳态。这条在高速设计里尤其重要。第三仿真和综合用两套时钟是省时间的常规操作但一定要确保综合前切回真实MMCM。第四打开Implementation后的报告逐一核对Clocking Wizard生成的XDC约束是否被正常使用。如果约束被disable整个MMCM的输出时钟频率可能和你配置的完全不同。第五仿真时不建议随便改MMCM的startup period参数生成的.xci文件里的很多参数是工具自动算的手动改会导致IP异常。就让它自动生成千万别改成快速锁定模式来加速仿真否则上板行为和仿真不一致定位问题成本更高。MMCM不是FPGA里最复杂的部分但它串联了时钟输入、约束、时序收敛、复位设计好多基础环节。把这篇文章里的流程走一遍从新建IP到上板点亮计数器你会对FPGA的时钟体系有个整体的认识。希望这些内容对你有帮助。如果有MMCM配置相关的疑问欢迎留言交流我可以结合具体场景再做一些实操演示。
返回列表