ARTICLE DETAIL

资讯详情

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

LVDS高速ADC接口的Xilinx FPGA实现与调试实战

LVDS高速ADC接口的Xilinx FPGA实现与调试实战 做高速数据采集的朋友应该都清楚ADC和FPGA之间怎么把几百兆甚至上G的比特流稳定搬回来从来不是只靠原理图拉几根线就能完事。LVDS高速ADC接口在Xilinx FPGA上实现看起来是个标准题目实际落地时牵扯到差分电平理解、bank选型、引脚约束、数据捕获时序、训练对齐任何一个环节没想透出来的数据都是花屏、乱码、偶发跳变。这篇就按我实际做项目的顺序把从接口选型到最终跑起来的完整链路拆开讲也把那些容易踩的坑一并说清楚给正在搞高速采集、软件无线电或者示波器数字端的工程师做个参考。1. 从ADC到FPGA先搞清楚LVDS接口到底在传什么1.1 LVDS不是“差分而已”它是一套完整电平协议很多新手会把LVDS理解成“两根线反着传”这个理解不算错但落地的时候会吃亏。LVDS全称Low Voltage Differential Signaling核心是电流驱动发射端用一个约3.5mA的恒流源经过接收端100欧姆终端电阻形成约350mV的差分摆幅。这个摆幅比单端CMOS信号的0到1.8V甚至0到3.3V小得多所以功耗低、电磁辐射小配合差分走线抗共模干扰能力极强特别适合高速低摆幅场景。这个“恒流源加外部或者内部100欧姆匹配”的本质决定了选型的很多约束。比如接收端如果没接终端电阻电流源没有回流路径信号就会出现反射和振铃数据根本收不稳。再比如LVDS的共模电压大约是1.2V差分摆幅在1.035V到1.365V之间这个范围如果和FPGA bank的VCCIO供电选得不匹配输入引脚可能根本识别不了电平更别说什么时序收敛了。顺便提一个容易混淆的差分标准——HCSL很多人问它和LVDS的区别。HCSL主要用于PCIe时钟、Ethernet参考时钟这类场合它的电流源是15mA左右通过50欧姆到地的终端产生约0.7V到0.9V的摆幅强调的是低抖动时钟分配而不是数据传输。ADC接口里一般不会用HCSL因为ADC输出的重点是稳定的数据沿和足够的建立保持时间LVDS的架构和数据手册约定配合得更紧密。选型时认准LVDS就够了别被HCSL、LVPECL、CML这些名字带走。1.2 并行LVDS和串行LVDS两条路线怎么选高速ADC的接口大体分两种形态。第一种是并行LVDSADC把每个采样点的多个bit并行输出一条DDR时钟伴随这些数据一起送到FPGA常见于250MSPS到500MSPS级别、位数12bit到16bit的ADC比如ADI的AD9653、TI的ADS42JB69这类。并行LVDS的数据线数量多比如16bit、DDR模式下只需要8对数据线加1对时钟但布线资源和引脚压力都不小好处是协议简单只要把数据和时钟的相位关系搞好基本就能收数据。第二种是串行LVDS也就是JESD204B/C这类协议ADC把多bit数据串行化之后通过高速serdes通道发出来FPGA侧需要GTX/transceiver或者专用的JESD204 IP核来做解串。串行方案的线少、通道扩展灵活能支持几GSPS的采样率但协议复杂需要处理多通道对齐、确定性延迟、SYSREF同步、误码监测一堆事情调试周期明显更长。我做这个项目用的是并行LVDS方案ADS42JB69250MSPS的采样率16bit分辨率输出格式配置成双通道DDR模式每通道8对LVDS数据线加1对DDR时钟。当时选它的原因很朴素需求是双通道同步采集并行LVDS的确定性延迟天然比JESD204好处理FPGA侧逻辑也简单不需要依赖复杂IP。如果你的项目采样率在500MSPS以下、对确定性延迟有要求、团队FPGA逻辑积累又不是特别深厚并行LVDS是很务实的选择。2. Xilinx FPGA接收LVDS的硬件基础Bank选型决定成败2.1 HP Bank和HR BankLVDS标准不是哪都能随便接Xilinx 7系列以及Ultrascale系列的IO分为HPHigh Performance和HRHigh Range两类bank。HP bank的VCCIO固定1.8V适合接DDR、LVDS这类高速接口信号完整性好HR bank的VCCIO可以到2.5V或者3.3V适配老式单端电平但是高速差分性能明显弱一些。关键点来了LVDS标准在HP bank下对应IO standard是LVDS或者LVDS_25而在HR bank下通常只能用LVDS_25。这是什么意思呢如果你的ADC输出的是1.8V共模的LVDS电平接在HP bank上可以直接用LVDS标准内部终端电阻DIFF_TERM也可以直接打开但如果板子那边把ADC的LVDS接到了HR bank而且VCCIO设成了3.3V那你必须用LVDS_25标准并且由于HR bank内部端接不支持LVDS_25的DIFF_TERM外部通常得在靠近FPGA引脚的地方自己加100欧姆差分终端电阻否则反射会非常难看。我当时犯过一个错原理图上把ADC的LVDS差分对接到了HR bank想着FPGA支持差分就能收结果读进来的数据在高速下全是毛刺。后来查UG471才明白HR bank的LVDS_25虽然能用但是内部没有匹配终端高速信号没有源端和终端的良好匹配波形质量根本保证不了。最后是靠改PCB换bank才解决的。所以画原理图前一定要先打开所选FPGA封装的bank电气规范表确认ADC的LVDS电平到底是1.8V还是2.5V再决定放哪个bank区。2.2 IBUFDS_DIFF_OUT与内部端接原语怎么选在Xilinx FPGA里LVDS差分引脚不能像普通单端信号那样直接用IBUF必须例化差分缓冲原语。最常用的是IBUFDS和IBUFDS_DIFF_OUT。单端版IBUFDS只输出一个信号适合差分时钟输入DIFF_OUT版本会同时输出o和ob两个互补信号适合需要同时采样差分对两边的应用。在做ADC数据接收时我给每个bit的LVDS输入都用了IBUFDS_DIFF_OUT这样如果后续需要在逻辑里做差分信号交叉验证或者要调整极性手里多一个原始反相信号会方便很多。标准IP设置IBUFDS_DIFF_OUT有一个DIFF_TERM属性设置为TRUE时FPGA会在片内直接跨接100欧姆终端电阻。如果是HP bank配LVDS标准这个属性可以直接打开不用在板子上再放电阻如果是HR bank配LVDS_25DIFF_TERM无效必须在PCB上靠近FPGA引脚处放100欧姆差分电阻。有一个容易忽略的小细节如果ADC输出自身已经内部端接或者经过了驱动芯片做了缓冲FPGA侧再开DIFF_TERM就相当于两个100欧姆并联等效阻抗变成50欧姆反而破坏匹配。所以需要确认ADC和FPGA之间有没有串阻、有没有驱动buffer再决定DIFF_TERM开不开。2.3 引脚约束里的差分对语法P管锁一个就行Xilinx工具的引脚约束里差分信号用“LVDS_25”这样的标准名并且在XDC里只需要锁定差分对的正端P负端N会自动跟着对应。如果你用“LVDS”标准一般锁P端N端会自动绑定到相邻引脚。这个自动关联不代表可以随便放实际上P和N必须落在同一对合法的差分引脚上否则会产生DRC错误或者信号绕很远时序完全跑不起来。实际项目中我还习惯给每个差分对补充一个等长约束用set_max_delay -datapath_only。因为LVDS差分对内是电流环回流P和N两条线的长度差会直接影响共模转差模的噪声通常要求芯片内部到芯片内部的差分对内等长控制在5mil以内对间等长控制在50mil以内。FPGA引脚到ADC引脚之间的PCB走线等长一般由硬件工程师负责但FPGA内部从PAD到IO逻辑的延迟差我们没办法直接控制这时用pin delay或者等长约束把关键信号间的skew收紧再加上后续的set_input_delay数据稳定度会明显好很多。3. 数据捕获的核心DDR时钟与ISERDESE2的配合3.1 数据和时钟是中心对齐还是边沿对齐决定捕获方式并行LVDS ADC的DDR时钟与数据的相位关系有两种可能中心对齐Center-Aligned或者边沿对齐Edge-Aligned。中心对齐指的是数据变化在时钟上升沿和下降沿的中间FPGA用时钟的两个沿直接采样就能得到稳定的数据边沿对齐则是指数据在时钟沿附近变化这时直接采会有建立保持冲突需要通过约束或者延迟单元把时钟相位往数据眼中间移。ADS42JB69这款ADC输出的是DDR时钟默认是数据与时钟中心对齐。这是最舒服的情况ISERDESE2在DDR模式下用CLK的上下沿直接捕获即可不需要额外的相位调整。如果ADC寄存器配置把输出时钟改成边沿对齐那么FPGA侧通常要例化ODELAY或者IDELAY对着时钟线做可调延迟把采样点移到数据眼中心。这个调整最好别拍脑袋定实际做法是在FPGA里例化IDELAYE2把时钟线延迟步进从0到31扫一遍统计每个档位的误码率选中间那段无误码的档位作为工作点。这个方法听起来土但实测非常有效尤其在不同温漂和批次ADC之间一致性一般的时候。3.2 ISERDESE2的关键参数和例化方式ISERDESE2是Xilinx专门用来做高速串并转换的模块在并行LVDS接收场景里主要做DDR双沿采样然后把数据送到内部逻辑时钟域。我以前刚接触ISERDESE2时总把它当成复杂IP其实关键参数就那几个ISERDESE2 #( .DATA_RATE (DDR), .DATA_WIDTH (8), .INTERFACE_TYPE (NETWORKING), .DYN_CLK_INV_EN (FALSE), .DYN_CLKDIV_INV_EN (FALSE), .NUM_CE (1), .OFB_USED (FALSE), .IOBDELAY (NONE), .SERDES_MODE (MASTER) ) iserdes_data_inst ( .CLK (adc_clk_p_i), .CLKB (adc_clk_n_i), .CLKDIV (clk_div), .D (adc_data_bit), .CE1 (1b1), .CE2 (1b1), .RST (rst_n), .Q1 (data_q[0]), .Q2 (data_q[1]), .Q3 (data_q[2]), .Q4 (data_q[3]), .Q5 (data_q[4]), .Q6 (data_q[5]), .Q7 (data_q[6]), .Q8 (data_q[7]) );要注意的点有几个。CLK和CLKB必须接差分时钟信号CLKDIV接分频后的逻辑时钟CLK和CLKDIV必须相位对齐否则数据采进来之后跨时钟域容易产生错误的拼接顺序。DATA_WIDTH设置为8时CLK的频率必须是CLKDIV的4倍DDR双沿采样相当于bit rate是CLKDIV的8倍。如果你的ADC数据位宽超过8bit比如16bit通道拆成了两路DDR一般一组ISERDESE2处理8bit再用两组拼起来。SERDES_MODE如果是8bit以上要记得配成MASTER加SLAVE的形式单独一个MASTER只支持到8bit。3.3 MSB位置不对问题就出在“对齐”很多人在用ISERDESE2收ADC数据时会遇到一个很头疼的现象采回来的数据数值看起来有规律但整体不对比如数值跳变幅度不对或者和预期值对不上。这通常不是采样时序的问题而是bit拼接顺序和ADC输出引脚映射不一致。举个例子ADC输出16bit数据在DDR模式下每一对LVDS线会在时钟上升沿输出一个bit下降沿输出相邻的另一个bit。如果ISERDESE2的Q1到Q8顺序和ADC实际输出位的bit序没对齐低字节和高字节就会错位数据自然就是乱七八糟的。解决方法是利用ADC手册里的输出时序图和位映射表先确定哪条LVDS线对应最高有效位MSB然后用training pattern验证。快速验证技巧给ADC配置一个固定输出pattern比如输出0xA5A5然后在FPGA里抓ISERDESE2的并行输出。如果看到的是0x5A5A说明8bit组内高低位反了如果看到的是0xA5A5但位置偏了说明数据组之间错位。这时候在逻辑里做bit反转、byte重组或者调整ISERDESE2的Q端映射问题很快就能定位。这个环节最忌讳直接改时钟相位因为问题根本不在相位而在映射。4. 时序约束与实现收敛把理论延迟落成可跑的XDC4.1 先创建虚拟时钟再算输入延迟LVDS ADC接口的时序约束核心是让工具知道ADC数据相对于FPGA接收时钟的建立时间和保持时间这样布线工具才能保证ISERDESE2采样点的正确性。首先要为ADC的采样时钟创建一个虚拟时钟create_clock -name adc_clk -period 8.000因为真正的采样时钟来自ADC芯片FPGA内部没有这个时钟源只有数据线上的DDR时钟。以250MSPS、DDR模式为例单bit的数据速率是250Mbps时钟周期4nsDDR一个沿周期2ns。如果ADC输出时钟与数据中心对齐那么数据在上下沿各有一个稳定的采样窗口窗口中心是时钟沿后的1ns左右。这时set_input_delay的设置逻辑是数据相对于adc_clk时钟的上升沿和下降沿分别约束。create_clock -name adc_clk -period 4.000 [get_ports adc_clk_p] set_input_delay -clock adc_clk -max 0.8 [get_ports {adc_data[*]}] set_input_delay -clock adc_clk -min -0.2 [get_ports {adc_data[*]}]注意这里0.8ns和-0.2ns不是拍脑袋定的而是结合ADC的tSU、tHD参数和PCB走线延迟算出来的。如果ADC手册规定数据在时钟沿前1ns有效、后1ns内有效那么max输入延迟大约就是1ns减一点PCB偏斜min延迟是-1ns加一点PCB偏斜。算出来的窗口只要落在ISERDESE2的捕获窗口内时序报告就不会报红。多通道ADC尤其要注意每个字节通道的输入延迟可能有微小差异最好分组约束别偷懒写一个大集合否则一旦某条路径持续靠近边界跑起来就是偶发误码。4.2 别忽略建立时间和保持时间窗口两个都要看做时序收敛的时候很多人只盯setup觉得hold时间不够是低级错误实际LVDS高速接口的hold违例非常隐蔽。hold违例的表现不是跑不起来而是跑起来偶发数据跳变温度一变或者电压稍微波动就出问题。这在高速ADC接口尤其多见因为FPGA内部从PAD到ISERDESE2的路径延迟不确定性大hold窗口本身又很窄。遇到hold违例常规手段是查看综合报告里对应路径的延迟然后通过IOB属性或者调整IDELAY把数据路径延迟加一点。具体操作是给数据引脚加IDELAYE2原语让数据相对时钟延后1/4个bit周期左右这往往能把采样点从数据眼边缘挪到中心位置。实际项目中我用过IDELAY_VALUE 8左右对应78ps * 8约624ps对250Mbps的DDR数据来说刚好让采样点挪进眼图中心。这个值不能脱离具体PCB和ADC bestimmen最好的方式还是做滑动扫描实验找到误码率最低的一段工作点然后留出余量。4.3 和PCB联动等长不是“一样长”就完事FPGA和PCB的互动在LVDS接口上特别明显。很多硬件工程师做等长的时候只保证PIN封装处到连接器/ADC的走线等长却忽略了FPGA引脚到IO逻辑内部的延迟是不同的。这个延迟虽然不高几十皮秒级别但在几百Mbps或Gbps速率下就不可忽略了。Xilinx的XDC里可以用set_pin_delay给引脚加不同的内部延迟补偿让PCB等长加内部延迟后的总skew控制在1/4 bit周期内。另外串阻的选择也影响信号质量。LVDS差分对通常建议在靠近发送端串22欧姆或者33欧姆电阻用于压低振铃和过冲靠近接收端则放100欧姆差分终端同时还可以加100nF到1uF的AC耦合电容隔直之后方便ADC和FPGA共模电压不完全匹配时也能正常工作。FPGA侧DIFF_TERM如果开了外部终端就需要去掉或者做成可选焊接。这块最好是画板前就和硬件工程师对齐不然板子回来了只能靠飞线临时处理非常被动。5. 调试实录从波形花到稳定采数的全过程5.1 先在低速下验证寄存器配置再拉高采样率拿到新板子头一件事不是把采样率调到最高然后各种抓波形那是给自己挖坑。我的习惯是先把ADC配置成低速模式或者降低采样时钟比如用10MHz的时钟替代250MHz确认FPGA侧能稳定采到递增斜坡或者固定pattern。这个过程能快速区分问题域如果低速下数据就是错的那基本是引脚约束、bank供电、串阻匹配的问题如果低速下数据正确拉到高速才出错那才是时序、眼图、终端匹配的问题。高速拉起来后我一般用ILAIntegrated Logic Analyzer抓ISERDESE2输出的并行数据观察是否稳定。如果数据在较大范围内跳变优先查参考时钟质量和ADC的供电纹波如果数据偶尔跳一个bit检查对应LVDS差分对的等长和DIFF_TERM如果数据整体表现为稳定的低位翻转那大概率是训练pattern没过需要调整对齐状态机。5.2 用Training Pattern做自动对齐比手工调可靠并行LVDS接口的数据对齐不能指望每次上电都是对的。不同批次ADC、不同温度、不同电源电压下ADC输出数据相对时钟的相位会有漂移必须做一个上电自动校准逻辑。做法是让ADC在初始化阶段输出一组已知的training pattern比如0x1FF和0x200交替或者伪随机序列FPGA侧检测ISERDESE2并行输出的pattern是否匹配。我实现过一个简单的对齐状态机先把所有通道的ISERDESE2输出统一到同一拍然后用一个bit偏移寄存器控制每个通道的数据拼装顺序不断尝试把输入pattern和期望pattern比对一旦匹配成功就锁定偏移值。如果所有偏移尝试都失败再调用IDELAYE2扫描延迟档位相当于做了一次硬件的自动“眼图扫描”。这个逻辑写起来不复杂大概200行Verilog但能省下大量手工调试时间尤其在多通道ADC系统里每个通道都要对齐的话手工调根本不现实。顺带说一个热词项目里的相关点——如果做的是FPGA基于LVDS接口的多通道数据采集系统可以进一步扩展去做TDC时间数字转换或者直方图分析。那时候每个通道的偏斜修正就不只是bit对齐了还需要对采样点之间的时间差做精细标定这个标定数据存进BRAM运行时实时补偿思路和训练对齐是一脉相承的。5.3 常见故障对照表遇到现象直接查我在调试中遇到过好几个典型问题整理了对照表方便参考故障现象可能原因排查方向低速下数据全错引脚约束、bank电压、P/N接反查XDC、查原理图、查LVDS差分对极性低速正常高速数据花终端匹配不足、等长不满足确认DIFF_TERM/外部终端、对间等长单个bit偶发跳变数据与时钟相位靠近边缘加IDELAY、扫描延迟档位上电后每次采到的MSB位置不同缺少自动训练对齐增加Training Pattern自动校准两片ADC数据成组错位多通道对齐状态未完成按字节通道分组约束、独立对齐温度变化后偶发误码hold余量不足加IDELAY并保留至少1/4bit余量数据看起来对但幅度不对位拼接顺序错用固定pattern验证并重组Q端映射5.4 调接口的几条手记最后说几个个人经验。第一LVDS差分对极性检查不能只靠万用表最好做一次“故意反接”的验证比如把某个bit的P和N在约束里互换一下看数据是否变成按位取反以此确认工具里的映射和PCB实际连接一致。第二采样时钟的质量决定数据质量的底线ADC的采样时钟如果抖动大后面FPGA侧做再多训练对齐都白搭这个环节不能省。第三上电时序不能忽略有些ADC要求数据输出使能和时钟稳定之间有一定延迟如果FPGA侧复位释放得太早训练对齐就会在ADC输出尚未稳定时跑飞表现为第一次上电大概率失败、复位几次后正常。6. 从并行LVDS到更高阶应用的思路如果后面项目要上JESD204B并行LVDS这套训练对齐、眼图扫描、延迟约束的思路依然能复用只是把ISERDESE2换成了GTX/GTH的RX把自定义training pattern换成了K码或者comma检测。你会发现本质还是“恢复时钟、找到数据的相位、对齐通道、锁定状态”这四步只是硬件模块不同、协议更复杂而已。我个人的体会是把LVDS高速ADC接口吃透最大的收获不是记住了几个原语和约束命令而是建立了一套排查高速数据链路问题的思路先分电平标准对不对再看时钟和数据相位关系然后做对齐和训练最后用约束保证各个环境条件下的收敛。这套思路在任何高速接口项目里都通用无论是DDR显存、PCIe还是SerDes底层逻辑都是相通的。实际操作中还有一个建议调试并行LVDS接口时不要一开始就在代码里加太多复杂的纠错和重传机制先用最简逻辑把原始数据流稳定抓出来确认数据链路本身是干净的再往上加功能。数据链路干净了这个系统就稳定了一大半剩下的只是业务逻辑的正确性。等跑通之后再去做自动训练、误码统计、直方图分析这些更高阶的功能你的调试工具的积累也会越来越厚。
返回列表