资讯动态

UltraScale架构下LVDS接收:IDELAYE3可编程输入延迟详解

发布时间:2026/9/17 13:16:51 来源:尧图企业网站定制
作为一个常年折腾高速接口的FPGA工程师LVDS这个主题我已经写成一个系列了前面十篇把LVDS电平标准、IBUFDS/OBUFDS、差分端接、以及7系列里IDELAYE2的用法都过了一遍。这第十一篇开始要把重心挪到Xilinx UltraScale系上重点聊可编程输入延迟。之所以值得单独开一篇是因为从7系列到UltraScaleXilinx的IO延迟架构发生了不少实质性变化很多在7系列里养成的习惯到了UltraScale上直接套用是会踩坑的。这篇文章主要解决三个问题UltraScale系的可编程输入延迟到底改变了什么、IDELAYE3怎么例化、以及在实际LVDS接收链路里怎么把它用起来。适合正在做LVDS接收、或者从7系列往UltraScale迁移的工程师。1. LVDS接收难在哪先搞清楚你要解决的问题1.1 数据与时钟的skew从哪来LVDS接收最核心的诉求其实就一句话在正确的时间点把差分线上的数据采下来。听上去简单但实际板子上跑起来数据相对于时钟的相位关系永远是“不太对”的。先说skew的来源。第一类是PCB走线引入的差分对内两条线长度不一致会引入skew数据组与时钟之间的长度差也会引入skew。第二类是芯片本身的差异发送端芯片内部的输出路径、FPGA接收端IO buffer的延迟都会有几十到几百皮秒的偏差。第三类是封装和板级连接带来的尤其是BGA封装不同引脚到die内部的走线长度天然不同。举个我实际遇到的例子一块板子上有8路LVDS数据线加1路时钟从ADC送到FPGA。PCB设计时已经尽量做等长了但实测下来数据与时钟之间的skew最大和最小能差到400ps以上。如果数据速率是500Mbps一个bit周期是2ns理论上采样窗口应该是2ns但去掉setup/hold时间后实际有效窗口可能只有1.2ns左右。400ps的skew听起来不大但已经吃掉三分之一的余量了如果PCB上再有个别走线绕线绕得多一点整个链路就非常脆弱。没有可编程延迟的时候大家靠什么调最原始的办法是改PCB走线长度但这在调试阶段根本不现实。稍微聪明一点的办法是调整FPGA内部PLL的相移把采样时钟整体移一个角度。这个办法的问题在于它只能对时钟整体做固定相移没法照顾到每根数据线的个体差异——8路数据线各自的skew不一样你不可能给PLL同时配8个不同的相移。这时候可编程输入延迟的价值就体现出来了每一根数据线后面单独配一个延迟链按需调整这一路的延迟把每路数据都挪到采样窗口的正中间。这是源同步接口调试的标准做法也是UltraScale系可编程输入延迟存在的最根本理由。1.2 没有可编程延迟时你是怎么凑合用的我知道有工程师在低速率场景下是硬凑的数据速率不高、时序余量足够大直接用一个全局时钟采样不调任何延迟也能跑。比如100Mbps以下的LVDS一个bit周期10ns参考时钟随便偏移个几百ps问题不大。但一旦速率上去比如DDR模式跑到600Mbps甚至1Gbps以上问题就完全不一样了。在双倍速率下一个bit周期不到2ns数据的变化沿一个接着一个采样点必须精确落在眼图中心。这个时候如果没有可编程输入延迟你只能反复改约束文件里的offset值、改PLL相位或者干脆靠运气——这在工程上是不可接受的。所以我的建议非常直接只要你的LVDS数据速率超过了200Mbps或者你希望这套设计具备量产可复制性那就不要省这个延迟链。UltraScale系的可编程输入延迟在资源上几乎不增加什么成本但对时序收敛的帮助是非常大的。2. UltraScale系最大的变化IDELAYE2到IDELAYE32.1 为什么说IDELAYE3是“新一代”延迟原语7系列里的可编程输入延迟原语叫IDELAYE2配合一个独立的IDELAYCTRL模块由外部参考时钟校准延迟链的精度。IDELAYE2的延迟范围是0到31个tap参考时钟200MHz时每个tap大概78ps。实际使用时IDELAYCTRL的参考时钟必须稳定否则延迟值会漂。到了UltraScale架构Xilinx把这一整套方案做了重构新原语叫IDELAYE3。最直观的变化有几点第一不再需要独立的IDELAYCTRL模块IDELAYE3自身集成了校准相关的逻辑顶层设计少了一个需要额外注意的模块布线布局的负担也小一些。第二延迟分辨率大幅提升。IDELAYE3支持两种精度模式高精度模式下每个tap的延迟值比7系列的78ps小一个数量级左右。这意味着你可以做的延迟调节粒度更细眼图中心找得更准。当然具体数值跟参考时钟、器件型号、speed grade都有关使用时要查对应器件的SelectIO用户手册。第三支持TIME和COUNT两种延迟设置格式。TIME模式直接用皮秒数写延迟值工具会帮你换算成tap数COUNT模式直接写tap数。这是个非常实用的改进工程上大家习惯用时间单位思考问题比如“我想延迟1.5ns”TIME模式直接写1500就完了不用自己心算tap数。第四CNTVALUEIN和CNTVALUEOUT成为标准接口配合LOAD信号可以动态修改延迟值。这意味着你可以实现在系统运行过程中扫描不同延迟值、寻找最佳采样点——这在前几代的方案里实现起来要麻烦得多。2.2 两种精度模式怎么选IDELAYE3的高精度实测优点明显但并非所有场合都需要一上来就开最高精度。Vivado的配置界面里会提供类似精度的选项具体描述在各代器件族的SelectIO用户手册里都会给出。我的经验是这么选的低速接口、时序本身比较宽松的用低精度模式就够了功耗和复杂度都低一些真正的高速接口、对采样点位置敏感的用高精度模式。另外如果你打算做动态延迟扫描希望每个tap步进小一点、扫出来的眼图曲线平滑一点那么高精度模式是更好的选择。还有一点要说明高精度模式下参考时钟的要求也会更严格一些。设计时一定要留出干净的时钟资源给IDELAYE3别用一个被别的逻辑搅得千疮百孔的时钟去伺候它。2.3 TIME格式与COUNT格式写ps还是写tap这是实际工程师最常问的问题之一。TIME格式下你在例化时给的是“我想延迟多少皮秒”Vivado会根据目标器件的延迟特性、参考时钟频率自动换算成tap数。好处是设计代码可阅读性强、可移植性也好同一个模块从Kintex UltraScale换到Virtex UltraScale延迟时间值不用改。COUNT格式下你得自己操心tap数和时间之间的关系换器件就得重新算。但这里有个容易踩的坑TIME和COUNT格式在静态例化时都成立但到了动态调整环节实际修改延迟时你往CNTVALUEIN写入的永远是tap计数不是皮秒数。也就是说不管当初例化时用的是TIME还是COUNT动态配置接口写入的值一定是COUNT维度的。我建议的习惯是顶层参数用时间单位来定义这样代码语义清楚但在内部实现动态扫描逻辑时明确把tap数作为底层操作单位并统一记录“当前延迟多少tap”作为全局状态。这样代码好看逻辑也清晰不会在调试时被单位搞晕。3. 实操例化IDELAYE3搭最小LVDS接收链路3.1 工程准备与器件选型提醒动手前先确认你的器件支持。UltraScale系包括Kintex UltraScale、Virtex UltraScale、Zynq UltraScale等的HP bank和HR bank都支持LVDS输入但可编程输入延迟的资源在每个IO bank上是固定的例化前最好在Vivado里先跑一次IO planning确认你用的引脚位置有足够的延迟资源。另外提醒一句做PCB选型和FPGA选型时一定要把LVDS支持的bank电压和bank类型一起查了。有的低端器件、或者某些bank只支持LVCMOS不支持LVDS的差分输入标准。Xilinx的选型手册里会明确标出每个bank支持的IO标准建议在项目立项阶段就确认清楚别等板子画完了才发现引脚不支持。还有一个小建议尽量把同一组LVDS信号放在同一个bank、甚至连续的引脚上。这样做除了走线方便更关键的是同一个bank内的延迟特性一致性更好调试时互相参考的价值更大。3.2 完整的例化代码与参数解析下面给一个我在实际工程里常用的例化代码完整展示IDELAYE3在LVDS接收链路中的一个应用方式。// 模块lvds_rx_chan // 功能单通道LVDS数据接收带可编程输入延迟 IBUFDS #( .DIFF_TERM (TRUE), .IBUF_LOW_PWR(FALSE) ) ibufds_data_inst ( .I (lvds_p), .IB (lvds_n), .O (data_raw) ); IDELAYE3 #( .DELAY_FORMAT (TIME), .DELAY_SRC (IDATAIN), .DELAY_TYPE (VAR_LOAD), .DELAY_VALUE (1200), // 初始延迟单位由DELAY_FORMAT决定 .REFCLK_FREQUENCY (300.0), .HIGH_PRECISION_MODE (TRUE), .UPDATE_MODE (ASYNC) ) idelaye3_data_inst ( .IDATAIN (data_raw), .DATAOUT (data_delayed), .CLK (delay_ctrl_clk), .RST (idelay_rst), .LOAD (idelay_load), .CNTVALUEIN (idelay_cnt_in), .CNTVALUEOUT (idelay_cnt_out), .CE (idelay_ce), .INC (idelay_inc), .EN_VTC (1b1), .ODATAIN (1b0), .CLKDIV (1b0), .CASC_IN (1b0), .CASC_RETURN (1b0), .CASC_OUT () ); ISERDESE3 #( .DATA_WIDTH (8), .DDR_MODE (TRUE), .IS_CLK_INVERTED (1b0) ) iserdese3_data_inst ( .D (data_delayed), .CLK (clk_p), .CLKB (clk_n), .RST (idelay_rst), .Q (data_parallel) );注意几个关键点的选择。DELAY_SRC设置为IDATAIN代表接收来自IO的原始输入信号。这个参数看似不起眼实际决定了模块在芯片内部取哪个信号做延迟。常规LVDS接收场景一定选IDATAIN。DELAY_TYPE设置为VAR_LOAD因为我想做动态延迟调整。如果只需要固定的延迟值可以选FIXED省掉动态控制相关接口的连线。但从工程复用角度我基本都按VAR_LOAD来设计因为后续做自动眼图扫描的时候不用改RTL只改控制逻辑就行。REFCLK_FREQUENCY这里我给的是300.0MHz。这个频率范围需要参考目标器件手册确认不同器件支持的范围不同。实际使用中最好用专用的参考时钟不要图省事从别的逻辑上分频取一个时钟过来。另外提一个参数UPDATE_MODE设置为ASYNC时延迟值的更新不需要等一个固定周期生效适合快速调整同步模式则更稳妥适合在确定性要求高的场景用。这个参数要和你的控制逻辑时序对齐别一会儿ASYNC一会儿SYNC会把自己绕晕。例化的代码位置也有讲究。IDELAYE3属于IO资源最好放在顶层或者IO模块层级不要深埋在复杂逻辑里。这样综合后布局布线时工具能更准确地识别IO路径时序约束也好写。我的习惯是一个LVDS通道一个子模块子模块内部只放IBUFDS、IDELAYE3、ISERDESE3控制逻辑单独放在外面的一个状态机里管脚清晰、好维护。3.3 与IBUFDS、ISERDES的连接从上面的代码能看到一条完整的LVDS接收链路差分引脚进来先进IBUFDS转成单端再进IDELAYE3做延迟调节最后送ISERDESE3做串并转换。这里有个容易被忽略的点IDELAYE3和ISERDESE3之间的信号是单端的、已经经过延迟的数据流。如果你在中间插入了任何组合逻辑延迟链的精度可能被破坏因为普通逻辑的延迟是不受控的不同PVT条件下差异非常大。所以数据路径上IBUFDS-IDELAYE3-ISERDESE3之间必须直连中间不允许有任何LUT、寄存器或多余的缓冲。可能有人会问ISERDESE3前面要不要加BUFG不需要也最好不要。原因很简单ISERDESE3作为IO逻辑的一部分它本身就在IO bank附近直接吃IO区域的时钟资源不需要也不应该绕到全局时钟网络再回来。全局时钟网络适合分发到FPGA内部大量逻辑但用它来做IO高速数据的采样时钟延迟会大得多而且会引入额外的时钟skew。我还看到过有人习惯在IDELAYE3和ISERDESE3之间加一级寄存器美其名曰“同步”。这个做法在低速下没问题但对于高速LVDS接收等于在延迟链后面又插了一个不确定延迟的异步元件非常不推荐。4. 动态延迟从“固定值”到“眼图扫描”4.1 延迟值怎么扫静态配置一个延迟值叫做“盲调”通常的做法是先根据PCB走线长度和信号速率估算一个理论值再结合示波器和误码率测试结果反复修改。这套方法能用但效率低而且每条板子的差异都得单独调一遍。有了动态延迟能力之后更高效的做法是让FPGA自己扫描。具体思路是初始化时把所有通道的延迟置于一个较小值然后按固定步长逐步增大延迟值在每个延迟点上跑一小段收发测试或统计误码找出误码率最低的延迟区间最终把延迟锁定在区间中心。实现上这需要一个简单的状态机先设置整组延迟值、等待延迟链稳定、然后统计一个窗口内的误码数、更新延迟值继续下一轮。这个状态机不需要太复杂几十行RTL就能写完。但它带来的收益非常可观板卡上电后可以自动完成所有LVDS通道的延迟校准再也不用来回改代码、重新综合。我这边的系列后面还会专门讲如何设计这个自动校准状态机这一篇先把IDELAYE3本身的动态机制讲透。4.2 动态调整的时序要求动态调整IDELAYE3延迟值时有几个时序层面的坑这里提前说清楚。首先是LOAD信号和CNTVALUEIN的时序关系。CNTVALUEIN上的值要被正确加载必须保证在LOAD有效沿到来前就稳定下来否则会写入一个不确定值。也就是说你的控制逻辑必须先更新CNTVALUEIN等它稳定后再拉LOAD给一拍脉冲。顺序反了或者两个信号同时变化就会出现延迟值跳变到奇怪位置的诡异现象。其次是延迟链路触发条件。在调整过程中数据输出端会短暂出现异常数据。如果你在系统运行时动态调延迟必须设计好此时数据的处理方式。常用的办法是调整期间让数据链路暂停、丢弃接收数据等延迟稳定后才恢复。这个“调整窗口”的具体长度取决于参考时钟频率和延迟链的稳定时间通常在几微秒级别对于大量应用场景是完全可接受的。最后是EN_VTC的处理。EN_VTC使能后IDELAYE3会自动补偿电压和温度变化带来的延迟漂移。这个功能在环境温度变化大的场景比如室外设备、车载电子尤其有用。但要注意EN_VTC不是任何时候都建议打开的如果延迟值在你预期中需要频繁手动调整VTC和手动调整可能会冲突。我个人的经验是量产环境中打开EN_VTC调试阶段先关掉减少干扰变量。5. 常见问题与避坑指南5.1 例化报错排查在实际工程里IDELAYE3例化报错是很多新手第一个遇到的拦路虎。最常见的几个错误我列一下。第一个是端口连接错误。IDELAYE3的端口比较多尤其有ODATAIN、CASC_IN、CASC_RETURN这类不常用端口很多人例化时忘记连接或接地Vivado在综合阶段会报“signal is not connected”之类的错误。处理办法很简单用Vivado的Language Template生成例化模板先保证模板原样能综合过再往里面填自己的信号。第二个是参数配置越界。比如DELAY_VALUE给的数值超出了器件支持的范围或者REFCLK_FREQUENCY超出了手册范围。这类问题解决也不难先把参数都配成保守值综合过了之后再逐步往目标值靠。第三个是IO标准选择问题。当IDELAYE3连接的是IO输入路径时综合阶段会检查对应的引脚是否配置了合适的IO标准。如果引脚定义的是LVCMOS标准而你打算接收LVDS信号综合或实现阶段会报IO标准冲突。这时候要去XDC文件里把引脚标准改成LVDS同时确认BANK电压配置正确。5.2 采样点始终不对怎么办延迟值配了、代码也综合过了但实测采样点就是不对。这种情况我在项目里碰到过很多次原因各不相同。我通常按下面的顺序排查第一步用示波器测量FPGA引脚上实际的信号质量。先确认电平标准是否真的符合LVDS规范如果差分摆幅不足、共模电压不对后面怎么调延迟都是白搭。LVDS差分电平一般在350mV左右用示波器看单端波形是看不出名堂的一定要用差分探头或者看差分波形。第二步检查IBUFDS的DIFF_TERM参数。如果是板外已经有终端电阻了这里配置成FALSE如果是靠FPGA内部终端配置成TRUE。这个参数配错会导致信号反射严重、波形畸变采样点怎么调都找不到稳定位置。第三步用动态扫描的方式把延迟从最小扫到最大记录每个点的误码率。这样能画出一条“误码率-延迟值”的曲线曲线里最深的那段平坦区就是最佳延迟区间。如果扫描完发现整个曲线都没有误码为0的区域那基本可以断定信号质量本身有问题不是延迟链能解决的。调试的时候我建议把每个通道的当前延迟值通过调试接口读出来在Vivado的硬件管理器里实时观察。如果启动后每块板子的最优延迟值都不同别慌这是正常的因为PCB制造偏差和芯片个体差异本来就存在这正是动态延迟调整存在的意义。5.3 温度电压漂移与EN_VTC很多工程师在实验室调试时一切正常产品一到现场就出问题尤其是环境温度波动大的场景。原因大概率是温度变化导致IO延时发生了漂移。数字电路里的组合逻辑延迟本质上是MOS管开关速度决定的而MOS管开关速度又跟温度和电压强相关。温度升高时管子开关变慢延迟变大电压降低时同样延迟变大。这个漂移量看起来不大一两个tap的距离但对已经卡在时序边缘的设计来说足以造成偶发性的数据采样错误。EN_VTC就是用来对抗这个问题的。使能后IDELAYE3会实时监测电压温度变化并自动调整延迟链的tap数让总延迟保持稳定。这样即使环境温度从25度升到85度整条链路的有效延迟也能维持在设计值附近。不过EN_VTC不是一劳永逸的方案它要求在例化时预留一定的调节余量。如果延迟值已经顶到硬件的最大边界VTC补偿时根本没有空间再往上涨。所以设计时我一般会把初始延迟值设置在中间偏小的位置给自动补偿留足上下调节空间。另外如果你用动态扫描自动校准延迟扫描结束后应该把EN_VTC使能。这样自动校准选出来的初始延迟加上VTC的自动跟踪整个系统在宽温环境下才能真正稳得住。6. 写在最后的小经验这篇文章花了很大篇幅讲IDELAYE3但说句掏心窝的话可编程输入延迟只是手段不是目的。最终目的是让LVDS接收链路在各种各样的工艺偏差、温度变化、电压波动面前仍然能稳定地采到正确的数据。在实际项目中我越来越倾向于把延迟校准做成上电自动执行的一步初始化时对所有通道做一次全范围扫描几分钟之内完成全部通道的延迟锁定。这样不管是产线量产还是现场更换板卡都不需要人工介入每块板子都能自动适应自身的硬件差异。这块内容涉及自动校准状态机的设计细节我会在系列后面的文章里专门讲欢迎继续关注。最后分享一个调试时的小技巧不要一上来就用误码仪做最终验证先用FPGA内部的PRBS收发逻辑做初步测试成本低、迭代快。等到PRBS测试稳定通过后再接入实际业务数据跑整机验证。这个流程帮我省过大量时间。至于有同事问过的那个Platform Cable USB驱动在Windows上加载失败的问题多半是驱动签名和系统版本不匹配造成的重装对应版本的Vivado驱动即可属于环境问题不用过度纠结。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价