
搞过FPGA项目的人应该都有这种体会点屏、接ADC、连摄像头传感器的时候LVDS几乎是无处不在的接口。手里拿着一个LVDS屏或者一颗LVDS输出的ADC芯片手册上写着“兼容LVDS/LVCMOS”可真到了Vivado里面配IO的时候才发现事情没那么简单——信号老是没波形、采样不稳定、跑到一半丢数据甚至有时候直接把芯片搞烫了。这些坑我基本都踩过一遍这篇就想把基于Xilinx SelectIO IP核做LVDS差分信号接入的整套思路和配置细节梳理清楚。内容围绕Vivado平台下的SelectIO IP核展开从差分信号原理、IP核内部机制、参数选择到时序约束、PCB联动调板全流程走一遍。适合正在调试LVDS接口的FPGA工程师也适合刚入门想搞明白“为什么这么配”的初学者。1. 先搞清楚LVDS为什么大家都在用它1.1 差分信号的基本逻辑LVDS全称Low-Voltage Differential Signaling低压差分信号。所谓差分就是单路信号不用一根线而是用两根线传输一根走正逻辑一根走负逻辑接收端看的是两根线之间的电压差。换句话说它不关心“这根线对地是多少伏”只看P和N之间差了多少。这个设计带来的好处非常直接。单端信号最怕地弹和共模干扰因为地的电位在整个板子上并不完全一致发送端的地和接收端的地之间可能有几十毫伏甚至几百毫伏的压差单端信号一过来可能就把逻辑电平搞错了。而差分信号不依赖绝对地电位只要两根线受到的共模干扰差不多差值就不会有大的变化天然具备抗干扰能力。另外LVDS的电压摆幅特别小典型值只有350mV左右比LVCMOS的3.3V或者1.8V摆幅小了一个数量级。小摆幅意味着翻转时间短功耗低而且可以支持非常高的速率。像7系列FPGA的HP BankLVDS可以跑到1.25Gbps以上这个速率对于MIPI屏、高速ADC、相机接口来说完全够用。1.2 LVDS电气标准的关键参数做LVDS配置的时候有三个电气参数必须刻在脑子里共模电压、差分摆幅、终端匹配。共模电压典型值是1.2V一般范围在0.3V到2.4V之间。这是接收端判断差分信号有效范围的地基如果发送端共模不对即使差分幅值正确接收端也可能识别不了。差分摆幅典型值是350mV也就是P和N之间的电压差会在-350mV到350mV之间跳变。接收端的判决门限一般在±100mV左右只要差分幅值在这个范围以上就能正常接收。终端匹配是另一个容易忽略的点。LVDS要求在接收端加100Ω的跨接电阻这个电阻的作用是吸收发送端的电流把差分电流转换成电压同时做阻抗匹配减少反射。Xilinx FPGA的HP Bank内部其实已经集成了可编程的差分终端电阻叫DIFF_TERM在约束文件里可以直接打开。如果你的板子在外部又加了一颗100Ω电阻两者就会并联变成50Ω信号幅度直接折半辨认不出来。这是新手很容易踩的坑。1.3 单端转差分的常见误区很多从MCU转过来做FPGA的人刚开始不太适应“一根信号变成两根线”的思维。MIPI、LVDS、RS485、CAN这些其实都是差分传输原理上是通的。比如RS485就是差分信号在工业总线上的应用典型共模范围能做到-7V到12V搭配双绞线来抵抗长距离传输的共模干扰。LVDS虽然电压低、速率高、距离短但抗干扰逻辑和RS485是一样的——传“差”不传“对地”。所以当你看到“FPGA的LVDS接收”这个问题时本质上是在问我怎样把一对差分线上的微小压差安全、无误码地恢复成FPGA内部能处理的单端逻辑0和1。搞清楚这一点后面所有的配置都是在为这个目标服务。2. SelectIO IP核到底解决什么问题2.1 为什么不用IOBUF自己拼很多刚接触LVDS的人第一反应是LVDS不就是两根线一根正一根负吗我直接把引脚配置成差分模式输入进来不就行了理论上确实如此但实际工程里没有这么简单。Xilinx FPGA的IOBI/O Block里面物理上提供了差分输入缓冲器IBUFDS和差分输出缓冲器OBUFDS。IBUFDS的用法很简单例化一个原语把I和IB分别接到P端和N端O端输出单端信号就可以。但问题是LVDS接收不仅仅是把两根线转成一根线还需要考虑差分终端电阻的使能、内部延迟的调整、DDR模式下数据的双沿采样、串并转换、位对齐等一堆事情。如果你只是低速信号比如一个1MHz的差分时钟或者复位信号用原语确实够了。但如果是高速数据比如7:1的LVDS接口、DDR模式的MIPI DSI那一堆IO资源、ISERDES、IDELAY的配置就非常繁琐而且每换一个bank或者速率都要重新调一遍。SelectIO IP核把这些东西封装成了一个GUI界面勾选参数就能生成内部自动把IBUFDS、IDELAY、ISERDES/OSERDES全部连好省掉大量重复工作。2.2 SelectIO IP核的能力边界SelectIO IP核不是万能的它处理的是FPGA的普通IO资源也就是HP Bank和HR Bank上的引脚不是GTP/GTX那种高速串行收发器。换句话说几Gbps以上的SerDes信号不归它管那是GT Transceiver的领域。LVDS在7系列和Ultrascale系列的普通IO上单端速率一般能到1.25Gbps到1.6Gbps做并行LVDS、7:1模式的显示接口、ADC/DAC数据接口足够用了。IP核内部支持的功能主要包括差分缓冲器配置、输入串并转换ISERDES、输出并串转换OSERDES、输入延迟IDELAY控制、DDR采样模式、数据位宽转换、Bit Slip等。这些对应着LVDS应用中几乎所有的常见场景。比如你接一颗LVDS输出的ADC数据线可能只有4对但对齐时钟Frame Clock有1对数据是DDR模式输出的那就需要ISERDES做双沿采样再根据Frame Clock做通道对齐。这些在SelectIO IP核里都有对应的选项完全可以通过配置实现不用手工管理底层原语。2.3 什么时候该用IP核什么时候用原语我的经验是控制类信号、低速时钟、简单电平转换用原语数据总线、DDR采样、串并转换、需要动态延迟调整的场合用IP核。原语的好处是透明、可控、不占额外逻辑。比如你只是把一颗外置芯片的LOCK信号接进FPGA这信号是LVDS电平直接IBUFDS DIFF_TERM打开就够了用IP核反而杀鸡用牛刀。而数据类信号比如MIPI DSI的4通道数据每通道是DDR模式、10位深度的RGB数据如果你不用IP核手工配ISERDESE2的四个级联输出、IDELAYE2的延迟TAP、BITSLIP的时序控制工作量非常大而且很容易搞错。IP核帮你把这几层封装好了配置一个参数就能实现。另外从可移植性角度讲IP核生成的接口在不同器件之间切换时Vivado会帮你自动适配原语如果手写的话不同系列之间字符名都可能不一样移植成本高。当然代价就是IP核生成的代码可读性差网表层级多综合时间稍微长一点但这个开销在真实项目中完全可以接受。3. Vivado下配置SelectIO IP核的完整实操3.1 创建IP核与接口类型选择打开Vivado左侧IP Catalog搜索“SelectIO”能看到两个主要的IP一个叫“SelectIO Interface Wizard”另一个是“SelectIO IP”。名字看起来差不多但能力和配置方式有很大区别。SelectIO IP是一个比较基础的版本支持简单的单端和差分IO配置适合简单的信号接入。SelectIO Interface Wizard是进阶版本支持Native接口、7:1接口、DDR3/4接口等多种协议模板功能更全。对于LVDS数据处理场景一般推荐直接用SelectIO Interface Wizard。创建时需要选择接口类型。这里有几个关键选项Native模式完全通用数据线、时钟线、控制线都可以自定义最灵活。7:1模式专门为LVDS显示接口设计的比如VGA或特定LCD屏的7:1 LVDS格式IP核会自动生成deserializer逻辑。DDR3/4模式面向内存接口LVDS项目一般用不到。实际项目里做LVDS屏或者LVDS ADC选Native模式就行。选完它会出现一系列子页面告诉你输入数据宽度、时钟类型、有无Bitslip等这些根据实际接口手册填写即可。3.2 关键参数逐项讲解第一页选择单端IO还是差分IO。选Differential后又有几个分支Differential Input输入差分、Differential Output输出差分、Differential Bidirection双向差分。输入和输出分别对应的数据方向不同但都要指定P和N引脚。这里要注意有的接口手册上把正负端标成P/N有的标成/-本质一样对应FPGA引脚时别搞反。第二页是数据宽度和采样方式。数据宽度指单对差分线上每个时钟周期恢复出多少位数据。如果ADC数据手册上写“每个lane上DDR采样一个时钟周期输出7位”那数据宽度就填7。采样方式一定要看接口是SDR还是DDRSDR是单沿采样每个时钟周期只有1位DDR是双沿采样每个时钟周期有2位。LVDS高速接口绝大多数是DDR模式因为这样可以在同样的时钟频率下获得两倍带宽。第三页是时钟选项。输入接口一般有两种时钟一种是独立的外部时钟比如ADC采样时钟和data线一起进来这类选“Use separate clock pin”另一种是数据线自带嵌入式时钟比如某些MIPI接口不传单独时钟靠数据翻转恢复但在普通LVDS应用中比较少通常还是带独立对齐时钟的。第四页是IO Delay配置。这里可以选是否使用IDELAY什么时候用当你跑高速LVDS时数据线和时钟线之间存在skew需要用IDELAY把数据延后若干个TAP让采样点对准数据眼图的中央。一般推荐选“Fixed”延迟在调试阶段先把延迟值设为0跑通后再手工调整。最后是Bitslip选项。Bitslip是在多个lane并行传输时做字对齐用的当多个通道的数据在FPGA内部并行化后因为布线长度差异或链路延迟差异可能每个lane的字节边界不在同一个位置需要一个可编程的移位操作来对齐。选“Enable Bitslip”后IP核会输一个Bitslip信号你只要在逻辑中检测到对齐失败时拉一下它数据就会移位一个比特直到对齐为止。3.3 生成后的顶层例化与连接IP核配置完成后Generate Output Products然后在你的设计里例化。例化模板可以通过右键IP核选择“Open IP Example Design”获得也可以在Sources面板里查看它生成的例化代码。我习惯先把例化代码复制到自己的顶层模块里然后逐一对照信号名连接。常见信号包括// 输入方向示例 // 差分时钟输入 lvds_clk_p_i // 正端时钟 lvds_clk_n_i // 负端时钟 // 差分数据输入 lvds_data_p_i[3:0] lvds_data_n_i[3:0] // IP核输出 clk_out // 恢复出的采样时钟 data_out // 解串后的并行数据总线 bitslip // 对齐控制连接完毕后如果你勾选了添加ILAIntegrated Logic Analyzer集成逻辑分析仪Vivado会自动把你的data_out和clk_out连到调试核上方便直接抓波形看数据是否正常。3.4 时钟与复位处理IP核生成的时钟输出一定要接入BUFG或者BUFIO。数据恢复时钟上接普通的全局时钟网络BUFG即可因为解串后的数据已经不是特别高速了。如果是专用的高速时钟网络Xilinx还提供BUFIO但BUFIO只能接在同一个时钟区域的IO上布局布线会受限多数LVDS应用不太需要较真到这个程度。复位方面有个比较隐蔽的点SelectIO IP核有的版本生成后复位信号需要你确保在时钟稳定后拉高再拉低完成IP核内部的复位序列。如果省掉这个过程可能出现数据的第一拍不对但后面都正常的情况。所以建议在外部加一个简单的上电延时复位reg [7:0] reset_cnt 0; always (posedge clk_out) begin if (reset_cnt 8hFF) reset_cnt reset_cnt 1; end assign ip_core_reset (reset_cnt 8h10);当reset_cnt计数到一定值之后再释放复位保证IP核内部的所有级联寄存器先被清过一遍再开始接收数据。4. 时序约束与PCB联动容易翻车的地方4.1 管脚约束PACKAGE_PIN与IOStandard配置好IP核之后有一件事IP核帮不了你管脚约束。在XDC文件中你需要手写以下约束set_property PACKAGE_PIN AK26 [get_ports {lvds_data_p[0]}] set_property PACKAGE_PIN AK25 [get_ports {lvds_data_n[0]}] set_property IOSTANDARD LVDS [get_ports {lvds_data_p[0]}] set_property IOSTANDARD LVDS [get_ports {lvds_data_n[0]}] set_property DIFF_TERM TRUE [get_ports {lvds_data_p[0]}]这里有三个重点一是P和N的引脚必须成对出现在同一个差分对引脚上。Xilinx器件的管脚定义里每一对差分引脚是有固定对应关系的你不能随便拿两个普通IO硬配成差分。在Vivado的Device视图里能看到哪些引脚是同一个差分对它们的命名一般是像M21/N21这样相邻的引脚对。二是IOSTANDARD必须设成LVDS。如果你把P设成LVDS但N忘了设综合会报错。建议用通配符批量约束set_property IOSTANDARD LVDS [get_ports lvds_data_p*] set_property IOSTANDARD LVDS [get_ports lvds_data_n*]三是DIFF_TERM。如果外部没有端接电阻就必须设成TRUE让FPGA内部电阻做终端匹配。如果外部板上已经有一颗100Ω电阻就不再设TRUE否则并联后阻抗减半信号幅度不足。4.2 input delay与output delay设置思路时序约束这块是LVDS项目能跑稳的关键。不要指望不给约束就能干干净净的时序收敛尤其是跑几百Mbps以上的LVDS流。输入约束的思路是告诉工具数据到达的时间范围让工具去判断采样是否满足建立保持时间。需要用到两个约束# 输入延迟最大值与最小值 set_input_delay -clock [get_clocks lvds_clk] -max 2.5 [get_ports {lvds_data_p[*]}] set_input_delay -clock [get_clocks lvds_clk] -min 0.5 [get_ports {lvds_data_p[*]}]这里的数据来自接口手册或实际布线估算。手册上通常会给Tco和PCB走线延迟一般总延迟等于发送端时钟到数据输出延迟加上PCB走线延迟。没有手册的话先用0到周期的一半做保守估计跑起来之后根据实测眼图去修正。输出约束类似用set_output_delay告诉工具下游芯片的建立保持需求set_output_delay -clock [get_clocks lvds_clk] -max 3.0 [get_ports {lvds_data_p[*]}] set_output_delay -clock [get_clocks lvds_clk] -min 1.0 [get_ports {lvds_data_p[*]}]如果约束不通过优先考虑的不是加缓冲、加逻辑而是调整IDELAY值、改变采样边沿、检查PCB走线等长情况。很多工程师在一开始把IDELAY设成某个好看的固定值之后就不再调实际这是不对的每个设计的工作条件电压、温度会让最佳延迟点发生偏移所以更合理的方式是先跑一段时间用眼图扫描选中值。4.3 从PCB看LVDS布线等长、阻抗、回流这条虽然偏向硬件但FPGA工程师也必须懂因为很多LVDS调不通的根因在板子不在逻辑。第一是等长。差分对内两根线必须等长误差控制在5mil以内。不等长会导致P和N到达接收端的时刻不同直接造成差分信号失真。对间等长可以根据时钟频率放宽但最好也控制在50mil以内保证并行数据的skew不会太大。在Vivado里可以通过report_timing_summary里看到的引脚延迟差来反向验证PCB是否等长。第二是阻抗。LVDS差分阻抗标准是100Ω差分阻抗也就是说建立模型时要确保差分线阻抗在100Ω左右。如果板厂做成了85Ω或者120Ω信号反射就大眼图质量差误码率上升。这个最好在投板前就跟板厂确认好阻抗叠层。第三是回流路径。靠近LVDS走线的地层必须完整不能有分割。数据手册上经常画着“参考平面”的阴影区域就是这个意思。如果地平面被TCP走线劈开回流路径绕行共模噪声就会飙起来。这也是很多工程师Debug时忽略的一个点。5. 调试实录常见问题与排查技巧5.1 差分极性反了这个问题非常常见也很隐蔽。信号接入后示波器看到P和N波形是“相反”的你以为这就是差分但实际上定义反了。P和N接反的后果是时钟上看到的波形是反相数据上恢复出来的每一位都是反的。排查方法很简单用示波器看差分波形正常LVDS的P端在逻辑1时是1.2V175mV的电压N端是1.2V-175mV。如果P比N低那就是反了。FPGA端解决方式不用改PCB只需在约束里把P和N的物理引脚互换即可改动成本为0。但如果你在IP核配置里已经指定了P/N端口名换物理引脚要小心必须保持成对关系例如原先是M21/N21现在改成N21/M21其实还是同一个差分对。5.2 电平不匹配导致烧芯片/不工作LVDS接口虽然电压不高但不同器件之间的接口电平可能存在差异。比如有些LCD屏的LVDS接口工作在2.5V甚至3.3V的共模电压下而FPGA的HP Bank只支持1.2V~1.8V的VCCO。直接把两者接在一起轻则不工作重则烧内部ESD结构。实际项目中一定要先查芯片手册的“LVDS Input Common Mode Range”一栏。如果不在FPGA能支持的范围内就需要加外部电平转换芯片或者把信号接到HR Bank上——HR Bank的LVDS支持范围更宽一点但速率上限会降低。另一个建议是上电时先不要急着把数据线全接上先只接时钟线和一根地线用示波器看共模电压是否正常再逐步接入数据线。5.3 数据乱序与bit slip并行数据出现乱序是最让人头大的问题。现象是数据看起来“有波形”“有变化”但和预期的数值完全对不上比如显示的时候图像断层、颜色错乱。先排查每根lane本身的bit顺序对不对有些ADC手册上数据位序标记是MSB first有些是LSB first。如果IP核配置的位序和手册相反则每一拍的数据都会反转。这个直接在IP核配置里调整“Data bit order”就行。如果确认位序没错那就检查lane和lane之间是否有偏移。多lane场景下每个lane的传输延迟不可能完全一致复位之后每个lane恢复出的数据字边界可能不在同一个位置。这时候就需要Bitslip。在逻辑中检测每个lane的对齐标记比如帧头的特殊数据模式如果不满足就对这个lane拉高Bitslip一个时钟周期。这个过程要在同步状态机里操作不能所有lane同时滑要逐个对齐等所有lane都满足后再锁存。5.4 仪表与波形判断技巧调试LVDS时最常用的工具是示波器和Vivado自带的ILA。但很多人用示波器看差分波形的习惯不对。测LVDS波形时一定要用差分探头或者把两个通道分别接P和N用通道A减通道B的数学功能来显示差分波形。直接看P和N的单端波形是无法判断信号质量的——你看到的是共模分量和差模分量的叠加。波形判断的关键参数是眼图睁开眼睛的大小、上升沿是否平滑、过冲是否过大、差分幅值是否在250mV~450mV范围。ILA的判断技巧是不要一上来就看全部数据先看几个关键信号位的电平比如最低位在连续帧里是否按预期翻转。常见操作是写一个简单的计数器用LVDS恢复出的数据去跑如果计数器正常工作说明数据通路基本没问题。再用一个已知的测试图像或伪随机序列喂进去输出和预期比对就能快速定位是通道对齐问题还是数据映射问题。6. 一条龙注意事项从原理图到跑通的经验合集最后把这些年遇到过的教训集中列一下每一条都是真实项目中踩出来的。第一原理图阶段就要确认FPGA的Bank电压。LVDS在HP Bank上通常要求VCCO1.8VHR Bank上VCCO可以是2.5V或3.3V。如果你的原理图把LVDS信号接到了VCCO3.3V的HP Bank上那和LVDS的电平根本不匹配基本没得救。选Bank之前先翻手册确认所选Bank支持LVDS标准。第二差分信号的约束不要“裸奔”。有人的XDC里只写了PACKAGE_PIN和IOSTANDARD还有CLOCK_DEDICATED_ROUTE没有写DIFF_TERM。结果是综合不报错但上板后信号质量差。养成好习惯所有LVDS端口都显式写一遍DIFF_TERM。第三时钟线的时序约束一定要优先保证。很多人调LVDS数据调不通最后发现是时钟管脚没进专门的时钟pin而是走通用IO绕了很远。用report_clock_networks看时钟路径如果走了非专用路径最好调整管脚选择或加约束。第四上板调试顺序有讲究先时钟、再复位、后数据。上电后用示波器确认时钟引脚有波形且频率正确然后再看复位释放后IP核输出是否正常最后才看数据。不要一上电就抓波形那样抓到的问题很难定位。我自己的习惯是新项目接入LVDS接口第一版设计里一定会把IP核设为最“裸”的配置——不做Bitslip不做延迟补偿先把数据恢复出来看着正常再说。跑通之后再加IDELAY扫描、加Bitslip对齐逻辑一步一步把设计加固。这种增量式的调试方式比一上来就把所有高级功能全打开遇到问题不知道是哪个环节出错效率要高得多。做LVDS这类差分接口本质上就是个“细节堆叠”的工程电气标准懂一点IP配置懂一点时序约束懂一点PCB走线懂一点调试手段懂一点所有环节都到位了这个项目才算真正做透。希望这篇文章能把你在Vivado平台上配置LVDS差分信号的这条路趟平一点。