1. 从单端到差分:为什么LVDS是高速传输的首选?
如果你玩过ZYNQ7020,或者任何一款FPGA,想把一个高速时钟或者数据信号从芯片里送出去,你可能会直接把它连到某个输出引脚上。但当你跑到几百兆赫兹甚至更高频率时,问题就来了:单端信号对外部噪声太敏感了,信号质量下降得厉害,传输距离也上不去。这时候,就该LVDS登场了。
LVDS,全称低压差分信号,它不是什么新玩意儿,但在高速、抗干扰、低功耗的场合,几乎是“标配”。它的工作原理特别巧妙:不是用一个引脚对地输出一个电压,而是用一对引脚,输出两个极性相反、幅度相等的信号。接收端不关心这对信号具体是几伏,只关心它们之间的电压差。外界的共模噪声会同时作用在这两根线上,但差值几乎不变,这就天然具备了强大的抗干扰能力。实测下来,用LVDS传数据,比单端信号稳太多了。
在ZYNQ7020这类7系列FPGA里,硬件上已经为LVDS这类差分信号做好了准备。芯片的I/O Bank里,相邻的物理引脚可以被配置成一个差分对(比如P和N)。但是,你写Verilog代码时,如果直接把一个内部信号assign给两个输出端口,工具可不会自动帮你生成差分驱动电路。这就需要我们手动调用Xilinx提供的“原语”——你可以把它理解为FPGA底层最基础的硬件模块。对于输出LVDS,这个原语就是OBUFDS;对于接收LVDS,则是IBUFDS。我刚开始搞这块的时候,以为只要约束文件里指定了LVDS标准就行,结果综合出来根本不对,信号出不去,踩了个大坑。后来才明白,必须得在代码里显式地例化这些原语,工具才会调用对应的硬件资源。
2. 实战第一步:用OBUFDS原语输出LVDS信号
好了,理论说完,我们直接上代码。假设你FPGA内部有一个50MHz的时钟信号clk_i,你想把它以LVDS的形式发送出去,正负端分别接到顶层端口dout_p和dout_n上。
你会怎么写?我猜你可能第一反应是:
assign dout_p = clk_i;
assign dout_n = ~clk_i;
千万别这么干! 我试过,这么写综合工具要么报错,要么综合出来的根本不是真正的差分输出,性能极差,而且你后面想加IO约束都困难。
正确的做法是调用OBUFDS原语。下面是一个最基础的例化模板:
OBUFDS #(
.IOSTANDARD("LVDS_25"), // 指定输出IO标准为LVDS_25
.SLEW("SLOW") // 指定输出压摆率为慢速
) dout_OBUFDS_inst (
.O (dout_p), // 差分正端输出,连接至顶层端口
.OB (dout_n), // 差分负端输出,连接至顶层端口
.I (clk_i) // 内部单端信号输入
);
这段代码是什么意思呢?我来拆解一下:
OBUFDS:这就是我们要用的输出差分缓冲器原语。#( ... ):这是Verilog的参数例化语法,用来配置原语的属性。.IOSTANDARD("LVDS_25"):这是最关键的参数之一。它告诉FPGA,这对引脚要用LVDS_25电平标准。这里的“25”代表典型的输出共模电压是2.5V。这个参数必须和你的硬件设计(Bank电压)以及约束文件保持一致。.SLEW("SLOW"):压摆率控制。设为“SLOW”可以减小信号边沿的陡峭程度,从而降低电磁干扰(EMI),但会限制


370

被折叠的 条评论
为什么被折叠?



