ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Lattice FPGA时钟分频实战:Diamond PLL IP核配置与Verilog代码解析

Lattice FPGA时钟分频实战:Diamond PLL IP核配置与Verilog代码解析 1. 为什么时钟分频值得单独拿出来讲做FPGA开发的人都有一个共识时钟是整个系统的“心跳”。心跳不稳后面所有的逻辑都是空中楼阁。我刚开始接触Lattice FPGA的时候觉得分频嘛不就是计数器翻转一下的事儿写个always块数到一半翻转输出搞定。后来踩了几次坑才发现事情远没有这么简单。用计数器做分频在低频场景下确实能用但一旦频率上到几十兆甚至上百兆问题就来了。首先是抖动Jitter计数器分频出来的时钟边沿位置取决于计数器的复位状态和逻辑延迟抖动大得离谱。其次是占空比如果你想要一个严格的50%占空比奇数分频用计数器实现起来就很别扭。再就是时钟偏斜Skew分频出来的时钟和源时钟之间的相位关系不确定跨时钟域的时候容易出问题。Lattice Diamond里内置了PLL锁相环IP核可以直接调用不需要你从零写锁相环的模拟电路。PLL出来的时钟抖动小、占空比准、相位可控而且还能做倍频和相位偏移。这篇文章就围绕“用Diamond内置PLL IP核实现精准时钟分频”这个主题把整个流程从IP配置到Verilog代码解析再到实际调试中会遇到的问题完整地梳理一遍。这篇文章适合谁看如果你刚开始学Lattice FPGA或者之前一直用计数器做分频但遇到了瓶颈又或者你手头有个项目需要多路不同频率的时钟那这篇内容应该能帮到你。我会尽量把每一步的操作意图和背后的原理都讲清楚不只是告诉你“点哪个按钮”而是让你明白“为什么要这么点”。2. PLL IP核的核心原理与选型考量2.1 PLL到底在做什么PLL的全称是Phase-Locked Loop中文叫锁相环。它的核心思想其实不复杂用一个压控振荡器VCO产生高频振荡然后通过反馈环路让这个振荡的频率和相位锁定到参考时钟上。锁定之后你就可以通过分频器从VCO的输出得到各种不同频率的时钟。打个比方PLL就像一个调速器。参考时钟是你要跟随的节奏VCO是你手里的节拍器。你不断调整节拍器的速度直到它和参考节奏完全同步。同步之后你可以在节拍器的基础上加速或减速得到你想要的任何节奏。Lattice FPGA里的PLL是硬核资源也就是说它是芯片里专门做好的模拟电路模块不占用通用的逻辑资源。你通过Diamond的IP核生成工具配置好参数工具会自动生成对应的Verilog/VHDL封装和约束文件。你只需要在顶层模块里例化这个IP核把参考时钟接进去把需要的时钟引出来就行了。2.2 为什么不用计数器分频这里有必要展开说一下为什么我强烈建议在需要精准时钟的场景下用PLL而不是计数器。计数器分频的本质是“数拍子”。假设源时钟是100MHz你想得到25MHz那就数4个周期输出翻转一次。逻辑上没问题但实际波形上输出时钟的边沿是由计数器的翻转逻辑决定的而计数器的翻转又依赖于触发器的建立保持时间。这意味着输出时钟的边沿会带有逻辑延迟而且这个延迟会随温度、电压、工艺角变化。更关键的是计数器分频出来的时钟其抖动直接继承了源时钟的抖动再加上逻辑门带来的额外抖动累积起来就很可观了。PLL不一样。PLL内部的VCO是一个模拟振荡器它的相位噪声特性比数字逻辑好得多。而且PLL的反馈环路会持续校正输出频率和相位使得输出时钟的抖动被压制在很低的水平。对于高速接口、ADC/DAC采样、DDR内存控制这类对时钟质量敏感的应用PLL几乎是唯一的选择。还有一个容易被忽略的点时钟树。FPGA内部的时钟资源是有限的专用的时钟网络Clock Tree可以保证时钟到达各个触发器的偏斜最小。如果你用计数器分频输出的是一个普通信号它走的是通用布线资源偏斜大、延迟不确定。而PLL的输出可以直接连接到全局时钟网络偏斜控制在几十皮秒级别。2.3 Diamond中PLL IP核的几种模式Lattice Diamond的PLL IP核在IPexpress里叫“PLL”或者“Clock Wizard”之类的名字不同版本叫法略有差异通常支持几种工作模式标准模式最基本的锁相环模式输入参考时钟输出一路或多路不同频率的时钟。零延迟缓冲模式PLL的反馈路径从输出时钟引脚回采可以补偿时钟到引脚的延迟适合需要输出时钟与输入时钟严格对齐的场景。扩频模式用于降低电磁干扰EMI通过轻微调制输出频率来分散能量。对于大多数时钟分频的应用标准模式就够了。如果你需要输出时钟和输入时钟之间有确定的相位关系可以考虑零延迟缓冲模式。扩频模式一般用在消费类电子产品通过EMC认证的场景日常开发用得少。选型的时候还要注意一点不是所有的Lattice FPGA型号都带PLL。比如一些低端的CPLD或者小容量的FPGA可能没有PLL硬核或者只有一个PLL。选芯片之前一定要查数据手册确认PLL的数量和输出路数够不够用。3. Diamond中PLL IP核的配置实操3.1 新建IP核与参数设置打开Diamond在左侧的“File List”或者“Process”面板里找到“IPexpress”工具。不同版本的Diamond入口位置可能不太一样但一般都在Tools菜单下或者有一个专门的IP核生成向导。点击进入IPexpress之后选择“PLL”或者“Clock”相关的IP核。接下来会看到一个参数配置界面主要需要设置以下几项参考时钟频率Input Clock Frequency这是你从外部晶振或者上一级时钟源输入到PLL的时钟频率。比如你的板子上焊了一个25MHz的晶振那这里就填25MHz。注意单位有些版本是MHz有些是Hz填错了后面全错。输出时钟频率Output Clock Frequency你需要PLL输出多少频率的时钟。比如你想要100MHz的系统时钟就填100MHz。Diamond会自动计算VCO频率和分频系数。VCO频率范围这个一般不需要手动填工具会根据输入和输出频率自动计算。但你要留意一下VCO的频率必须落在芯片手册规定的范围内通常是几百MHz到一千多MHz。如果工具提示VCO频率超出范围说明你的输入输出组合不合理需要调整。输出时钟数量根据你的项目需求选择需要几路输出时钟。Lattice的PLL一般支持2到4路输出具体看型号。相位偏移Phase Shift如果你需要输出时钟相对于参考时钟有特定的相位关系可以在这里设置。单位通常是度或者皮秒。比如你需要一个90度相移的时钟用于正交解调就在这里填90。占空比Duty Cycle默认是50%。如果你的应用需要非50%的占空比可以在这里调整。但要注意有些PLL的输出分频器不支持任意占空比具体看芯片手册。配置完成之后点击“Generate”或者“Finish”Diamond会自动生成IP核的Verilog/VHDL文件、约束文件和一个示例顶层模块。3.2 生成的文件结构解析IP核生成之后你会在项目目录下看到几个新文件。以Verilog为例通常包括pll_ip.vIP核的封装模块里面例化了Lattice原语的PLL硬核并且把参数传递进去。pll_ip_tmpl.v一个示例顶层模块展示了如何例化这个IP核。pll_ip.lpc约束文件里面包含了PLL相关的时序约束和引脚约束。pll_ip.ngo或者类似的网表文件这是综合后的网表Diamond在布局布线时会用到。pll_ip.v是你需要重点关注的文件。它通常长这样module pll_ip ( input wire clk_in, // 参考时钟输入 input wire rst_n, // 复位信号低有效 output wire clk_out0, // 输出时钟0 output wire clk_out1, // 输出时钟1 output wire locked // PLL锁定指示 ); // Lattice PLL原语例化 EHXPLLL #( .PLLRST_ENA(DISABLED), .INTFB_WAKE(DISABLED), .STDBY_ENABLE(DISABLED), .DPHASE_SOURCE(DISABLED), .OUTDIVIDER_MUXA(DIVA), .OUTDIVIDER_MUXB(DIVB), .OUTDIVIDER_MUXC(DIVC), .OUTDIVIDER_MUXD(DIVD), .CLKI_DIV(1), .CLKFB_DIV(1), .CLKOP_DIV(8), .CLKOS_DIV(16), .CLKOS2_DIV(4), .CLKOS3_DIV(2), .FEEDBK_PATH(CLKOP), .CLKOP_ENABLE(ENABLED), .CLKOS_ENABLE(ENABLED), .CLKOS2_ENABLE(ENABLED), .CLKOS3_ENABLE(ENABLED), .CLKOP_CPHASE(0), .CLKOS_CPHASE(0), .CLKOS2_CPHASE(0), .CLKOS3_CPHASE(0), .CLKOP_FPHASE(0), .CLKOS_FPHASE(0), .CLKOS2_FPHASE(0), .CLKOS3_FPHASE(0), .FIN(0), .CLKOP_TRIM_POL(RISING), .CLKOP_TRIM_DELAY(0), .CLKOS_TRIM_POL(RISING), .CLKOS_TRIM_DELAY(0), .OUTDIVIDER_MUXA(DIVA), .OUTDIVIDER_MUXB(DIVB), .OUTDIVIDER_MUXC(DIVC), .OUTDIVIDER_MUXD(DIVD) ) pll_inst ( .CLKI(clk_in), .CLKFB(clk_out0), // 反馈时钟 .RST(~rst_n), .CLKOP(clk_out0), .CLKOS(clk_out1), .CLKOS2(), .CLKOS3(), .LOCK(locked) ); endmodule这段代码里EHXPLLL是Lattice ECP5系列FPGA的PLL原语名称。不同系列的FPGA原语名称可能不同比如ECP3系列可能是EHXPLLBMachXO系列可能是PLL_BASE之类的。Diamond的IP核生成工具会自动帮你选对原语你不需要手动改。关键参数说明CLKI_DIV输入时钟分频系数。如果你输入的参考时钟频率太高超过了PLL的输入范围可以在这里先分频。CLKFB_DIV反馈时钟分频系数。通常和CLKI_DIV配合使用决定VCO的频率。CLKOP_DIV、CLKOS_DIV等输出时钟分频系数。VCO频率除以这些系数就是各路输出时钟的频率。FEEDBK_PATH反馈路径选择。CLKOP表示从主输出时钟反馈CLKOS表示从副输出时钟反馈INT表示内部反馈。CLKOP_CPHASE、CLKOS_CPHASE粗相位调整单位是VCO周期数。CLKOP_FPHASE、CLKOS_FPHASE细相位调整单位是皮秒级。3.3 参数计算的实际案例假设你的板子上有一个25MHz的晶振你需要三路时钟100MHz给系统逻辑50MHz给外设接口12.5MHz给低速传感器。首先确定VCO频率。Lattice ECP5的VCO频率范围通常是400MHz到1200MHz。我们选一个合适的VCO频率比如800MHz。然后计算各路输出的分频系数100MHz输出800MHz / 100MHz 8所以CLKOP_DIV 8。50MHz输出800MHz / 50MHz 16所以CLKOS_DIV 16。12.5MHz输出800MHz / 12.5MHz 64所以CLKOS2_DIV 64。接下来计算输入和反馈分频系数。输入时钟是25MHzVCO是800MHz所以倍频系数是800/25 32。这个32可以拆成CLKI_DIV和CLKFB_DIV的组合。通常CLKI_DIV设为1CLKFB_DIV设为32。但有些PLL的反馈分频器范围有限可能需要拆成CLKI_DIV 2CLKFB_DIV 16效果是一样的。在Diamond的IP配置界面里你不需要手动算这些工具会自动帮你算好。但理解这些参数的含义在调试的时候会很有用。比如PLL不锁定的时候你可以检查一下VCO频率是不是超出了范围或者分频系数是不是设成了0。4. Verilog代码解析与顶层集成4.1 IP核例化与信号连接IP核生成好之后你需要在顶层模块里例化它。例化的时候要注意几个关键点第一参考时钟必须从专用的时钟输入引脚进来。Lattice FPGA的时钟输入引脚通常有专门的标识比如PCLK或者GCLK。如果你把参考时钟接到普通IO上PLL可能无法锁定或者抖动会很大。在约束文件里要用LOCATE语句把参考时钟绑定到正确的引脚。第二复位信号的处理。PLL的复位通常是异步低有效但建议在复位信号上做一下同步处理避免亚稳态。我一般会用一个简单的同步复位电路reg rst_n_sync1, rst_n_sync2; always (posedge clk_in or negedge rst_n) begin if (!rst_n) begin rst_n_sync1 1b0; rst_n_sync2 1b0; end else begin rst_n_sync1 1b1; rst_n_sync2 rst_n_sync1; end end然后把rst_n_sync2接到PLL的复位引脚。第三locked信号的使用。PLL锁定之后locked会拉高。这个信号非常重要你应该用它来复位后续的逻辑。在locked拉高之前PLL的输出时钟是不稳定的如果这时候后续逻辑已经开始工作可能会出现不可预期的行为。我通常会把locked信号也做一下同步然后作为系统复位的释放条件。wire locked; wire sys_rst_n rst_n_sync2 locked;4.2 多路时钟的跨时钟域处理PLL输出多路时钟之后不同时钟域之间的信号传递就需要特别小心。比如100MHz域产生的数据要传给50MHz域直接传肯定会出问题因为50MHz域的触发器可能采到100MHz域信号的中间态。常见的跨时钟域处理方法有几种两级触发器同步适合单比特信号。在目标时钟域用两级触发器串联第一级采到亚稳态的概率被第二级大幅降低。异步FIFO适合多比特数据。用双口RAM加格雷码指针实现安全的跨时钟域数据传输。握手协议适合对延迟不敏感的控制信号。用请求和应答信号来协调两个时钟域的操作。这里不展开讲跨时钟域的细节但你要记住一点PLL给了你多路时钟不代表你可以随意跨时钟域。该做的同步处理一个都不能少。4.3 时钟约束的编写IP核生成的时候Diamond会自动生成一个约束文件里面包含了PLL相关的时序约束。但有时候你需要手动补充一些约束特别是当你把PLL输出时钟引到外部引脚或者用于高速接口的时候。一个典型的时钟约束长这样FREQUENCY NET clk_in 25.000000 MHz; FREQUENCY NET clk_out0 100.000000 MHz; FREQUENCY NET clk_out1 50.000000 MHz; FREQUENCY NET clk_out2 12.500000 MHz;这些约束告诉Diamond的时序分析引擎这些时钟网络的频率是多少以便它计算建立保持时间是否满足。如果你有跨时钟域的路径还需要写MULTICYCLE或者FALSE PATH约束。比如从100MHz域到50MHz域的路径如果用了两级触发器同步那第一级触发器的输出到第二级触发器的输入之间应该设FALSE PATH因为亚稳态是不可避免的时序分析没有意义。FALSE PATH FROM NET sync_reg1* TO NET sync_reg2*;约束文件写得好不好直接影响到布局布线的结果和时序收敛的难度。我见过很多项目逻辑代码没问题但时序就是过不去最后发现是约束写错了或者漏写了。5. 常见问题与排查技巧实录5.1 PLL不锁定怎么办PLL不锁定是最常见的问题。locked信号一直为低后续逻辑无法正常工作。排查思路如下第一步检查参考时钟。用示波器或者逻辑分析仪测一下参考时钟引脚看有没有波形频率对不对幅度够不够。Lattice FPGA的时钟输入通常要求LVCMOS或者LVDS电平如果电平不匹配PLL可能无法识别。第二步检查VCO频率。在Diamond的IP配置界面里看看工具计算出来的VCO频率是不是在芯片手册规定的范围内。如果超出范围调整输入分频或输出分频系数把VCO频率拉回合法区间。第三步检查复位信号。PLL的复位引脚是不是一直处于复位状态有些开发板的复位按键是常闭的或者复位极性搞反了。用万用表或者逻辑分析仪确认一下复位引脚的电平。第四步检查电源和地。PLL是模拟电路对电源噪声很敏感。如果FPGA的PLL电源引脚没有好好滤波或者地平面不完整PLL可能无法锁定。这种情况在自制板子上比较常见。第五步检查约束文件。参考时钟有没有绑定到正确的引脚时钟频率约束有没有写对如果约束文件里把参考时钟约束成了错误的频率Diamond可能会优化掉PLL或者产生错误的配置。5.2 输出时钟抖动大怎么办PLL输出时钟抖动大通常有以下几个原因参考时钟本身抖动大。PLL会放大参考时钟的抖动特别是高频段的抖动。如果参考时钟来自一个质量很差的晶振或者走线很长没有匹配PLL输出也好不到哪去。电源噪声。PLL的电源引脚需要良好的去耦通常建议放一个0.1uF和一个10uF的电容尽量靠近引脚。VCO频率选择不当。VCO频率越高抖动通常越大。在满足输出频率要求的前提下尽量选低一点的VCO频率。输出分频系数太大。输出分频系数越大输出时钟的抖动相对于VCO抖动的放大倍数就越大。如果可能尽量用较小的输出分频系数。5.3 时序不收敛的排查思路时序不收敛是FPGA开发中的老大难问题。PLL相关的时序问题通常集中在以下几个方面跨时钟域路径没有正确处理。如果你从100MHz域直接传信号到50MHz域没有做同步时序分析会报错。解决方法就是加两级触发器同步或者用异步FIFO。时钟约束不完整。Diamond不知道某些时钟的频率就无法正确分析时序。用FREQUENCY NET把所有时钟网络都约束上。逻辑级数太深。两个触发器之间的组合逻辑级数太多导致建立时间不够。解决方法是在组合逻辑中间插入流水线寄存器把长路径打断。布局布线拥塞。如果FPGA的某个区域逻辑太密集布线资源不够会导致延迟增加。可以尝试调整布局约束或者优化代码减少资源占用。5.4 常见问题速查表问题现象可能原因排查方法解决方案PLL不锁定参考时钟缺失或频率错误示波器测参考时钟引脚检查晶振和引脚约束PLL不锁定VCO频率超出范围查看IP配置界面的VCO频率调整分频系数PLL不锁定复位信号一直有效逻辑分析仪测复位引脚检查复位电路和极性输出时钟抖动大电源噪声示波器测电源纹波增加去耦电容输出时钟抖动大参考时钟质量差频谱仪测参考时钟相位噪声更换晶振或优化走线时序不收敛跨时钟域未同步查看时序报告中的违例路径加同步器或异步FIFO时序不收敛时钟约束缺失检查约束文件补充FREQUENCY约束时序不收敛逻辑级数太深查看时序报告的路径延迟插入流水线寄存器5.5 几个容易忽略的实操细节第一个细节IP核生成之后如果你修改了参数重新生成记得把旧的约束文件删掉或者更新。我有一次改了输出频率但约束文件还是旧的结果时序分析一直报错查了半天才发现是约束没更新。第二个细节PLL的locked信号不要直接用作全局复位。locked信号本身可能带有毛刺而且它的释放时机和时钟域不一定对齐。最好把locked信号同步到目标时钟域之后再作为复位的释放条件。第三个细节如果你用了多路输出时钟注意各路时钟之间的相位关系。默认情况下各路输出时钟的相位是对齐的但如果你设置了相位偏移就要在跨时钟域处理时考虑这个偏移。第四个细节Diamond的IP核生成工具会生成一个_tmpl.v的模板文件里面有一个完整的示例顶层。我建议你先把这个模板综合一遍确认IP核本身没问题然后再把它集成到你的项目里。这样可以排除是IP核配置的问题还是你顶层代码的问题。6. 从PLL到系统时钟架构的延伸思考6.1 多PLL级联与时钟域规划稍微复杂一点的FPGA项目往往不止一个PLL。比如你有一个高速接口需要125MHz的参考时钟一个处理器子系统需要200MHz还有一个低速外设需要10MHz。如果这些频率之间的比例关系比较复杂一个PLL可能搞不定这时候就需要多个PLL级联。级联的方式有两种一种是PLL1的输出作为PLL2的参考输入另一种是多个PLL共享同一个参考时钟各自独立输出。第一种方式可以实现频率的精细调整但会引入额外的抖动。第二种方式抖动更小但要求参考时钟的频率满足所有PLL的输入范围。在做时钟域规划的时候我一般会遵循几个原则尽量减少时钟域的数量。每增加一个时钟域就多一组跨时钟域路径需要处理。把相关逻辑放在同一个时钟域里。比如一个数据采集模块和它的数据处理模块尽量用同一个时钟避免跨时钟域。异步时钟域之间一定要有同步机制。不管是两级触发器还是异步FIFO不能省。给每个时钟域分配独立的复位信号。复位信号的释放要和对应的时钟同步。6.2 PLL在高速接口中的应用PLL在高速接口里的作用更加关键。比如DDR内存控制器需要PLL产生与数据同步的时钟而且相位关系要求非常严格。Lattice FPGA通常有专门的DDR PLL或者SERDES PLL这些PLL的参数配置和普通PLL不太一样需要参考对应的IP核文档。再比如LVDS接口需要PLL产生高速串行时钟和低速并行时钟两者之间有固定的分频比。Lattice的LVDS IP核通常会内部例化PLL你只需要配置好频率和相位参数就行。对于这些高速接口PLL的抖动指标直接决定了接口的误码率。在选择PLL参数的时候要特别关注相位噪声和抖动指标不能只看频率对不对。6.3 时钟切换与动态重配置有些应用需要在运行时切换时钟频率比如低功耗模式下降低时钟频率高性能模式下提高时钟频率。Lattice的PLL支持动态重配置可以通过配置接口在运行时修改分频系数。动态重配置的流程一般是先让PLL进入待机模式然后通过配置接口写入新的分频系数最后让PLL重新锁定。这个过程需要小心处理因为PLL在重配置期间输出时钟是不稳定的后续逻辑必须暂停工作。时钟切换还有一个更简单的方案用两个PLL分别产生两个频率的时钟然后用一个多路选择器MUX在两者之间切换。但要注意切换的时候可能会产生毛刺需要用专门的时钟切换电路比如无毛刺时钟MUX来处理。6.4 时钟树资源的分配FPGA内部的时钟树资源是有限的。Lattice FPGA通常有多个全局时钟网络Global Clock Network和区域时钟网络Regional Clock Network。全局时钟网络可以到达芯片上的任何触发器偏斜最小但数量有限。区域时钟网络只能到达芯片的某个区域偏斜稍大但数量更多。在分配时钟的时候优先级应该是全局时钟网络 区域时钟网络 通用布线资源。PLL的输出应该优先分配到全局时钟网络。如果你有多个PLL输出但全局时钟网络不够用可以把频率最高的时钟分配到全局网络频率较低的分配到区域网络。在Diamond的约束文件里可以用LOCATE语句把时钟信号绑定到特定的时钟网络。比如LOCATE NET clk_out0 SITE GCLK0;具体的网络名称和可用资源要查对应芯片的文档。7. 我在实际项目中踩过的坑说几个我实际项目中遇到的坑都是文档里不会写的。第一个坑PLL的参考时钟引脚和普通IO引脚在布局布线时是分开的。有一次我画板子的时候把25MHz晶振接到了普通IO上结果PLL死活不锁定。后来查手册才发现那个引脚根本不支持时钟输入。重新画板子把晶振接到专用的时钟输入引脚问题解决。所以画原理图的时候一定要查清楚哪些引脚支持时钟输入。第二个坑PLL的locked信号在复位释放的瞬间可能会有毛刺。我有一次直接用locked作为后续逻辑的复位释放条件结果系统偶尔会跑飞。后来在locked后面加了两级触发器同步问题消失。这个毛刺在仿真里不一定能看出来但在实际硬件上确实存在。第三个坑Diamond的IP核生成工具在修改参数后有时候不会自动更新约束文件。我有一次把输出频率从100MHz改成80MHz但约束文件里还是100MHz结果时序分析一直报违例。后来手动删掉旧的约束文件重新生成才恢复正常。所以每次修改IP核参数之后都要检查一下约束文件有没有同步更新。第四个坑PLL的电源引脚一定要好好滤波。我有一次用了一块便宜的开发板PLL输出时钟的抖动特别大后来在PLL电源引脚旁边加了一个0.1uF和一个10uF的电容抖动明显改善。如果板子已经做好了没法加电容可以尝试降低VCO频率或者换一个质量好一点的晶振。第五个坑跨时钟域路径的约束不能偷懒。我有一次觉得两级触发器同步已经做了就没写FALSE PATH约束结果时序分析一直报违例。虽然功能上没问题但时序报告里一堆红色看着很难受。后来补上约束报告干净了心里也踏实了。这些坑说到底都是对细节的关注不够。FPGA开发就是这样大框架对了细节没处理好照样出问题。PLL作为时钟系统的核心每一个参数、每一个约束、每一个连接都值得反复检查。8. 写在最后的一些个人体会PLL这个东西刚入门的时候觉得神秘用多了之后觉得就是个参数配置的工具。但真正把PLL用好的关键不在于你会不会点那个配置界面而在于你理解时钟在整个系统中的角色。时钟不只是让触发器工作的节拍器它还是整个系统的同步基准。时钟的质量直接影响到系统的稳定性、可靠性和性能。一个抖动大的时钟可能会让高速接口误码率飙升一个相位不对的时钟可能会让数据采样出错一个约束不完整的时钟可能会让时序分析给出错误的结果。所以我在做每一个项目的时候都会花时间把时钟架构想清楚需要几个时钟域每个时钟域的频率是多少它们之间的相位关系是什么跨时钟域的信号怎么处理PLL的参考时钟从哪里来电源和地怎么处理这些问题想清楚了后面的代码和调试就会顺利很多。Lattice Diamond的PLL IP核工具已经做得比较成熟了大部分参数都可以自动计算生成的代码也基本可以直接用。但工具再方便也替代不了你对原理的理解。知道每个参数背后的含义知道每个约束的作用知道每个问题的排查方向这些才是真正让你在项目中游刃有余的东西。如果你刚开始用Lattice FPGA我建议你找一个带PLL的开发板把PLL的输出接到示波器上亲眼看看不同配置下时钟波形的变化。这种直观的感受比看多少文档都管用。等你对PLL的行为有了直觉再回头看那些参数和约束就会发现一切都顺理成章了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进