今天给大侠带来 Xilinx ISE14.7 LVDS 应用,话不多说,上货。
最近项目需要用到差分信号传输,于是看了一下 FPGA 上差分信号的使用。Xilinx FPGA 中,主要通过原语实现差分信号的收发:OBUFDS(差分输出 BUF),IBUFDS(差分输入 BUF)。
注意在分配引脚时,只需要分配 SIGNAL_P 的引脚,SIGNAL_N 会自动连接到相应差分对引脚上;若没有使用差分信号原语,则在引脚电平上没有 LVDS 的选项(IO Planning PlanAhead)。
测试代码:
module lvds_test( sys_clk,
sys_rst,
signal_in_p,
signal_in_n,
signal_out_p,
signal_out_n,
led_signal
);
input sys_clk,sys_rst;
input signal_in_p,signal_in_n;
output signal_out_p,signal_out_n;
output led_signal;
wire signal_out_temp;
reg[31:0] clk_cnt;
always @ (posedge sys_clk) begin
if(!sys_rst) clk_cnt <= 32'd0;
else begin
if(clk_cnt == 32'd10_000_000) clk_cnt <= 32'd0;
else clk_cnt <= clk_cnt+1'b1;
end
end
assign signal_out=(clk_cnt >= 32'd5_000_000) ? 1 : 0;
OBUFDS signal_out_diff( .O(signal_out_p),
.OB(signal_out_n),
.I(signal_out)
);
IBUFDS signal_in_diff( .O(led_signal),
.I(signal_in_p),
.IB(signal_in_n)
);
endmodule
约束文件:
NET "signal_out_p" IOSTANDARD = LVDS_33;
NET "signal_out_p" LOC = U16;
NET "sys_clk" IOSTANDARD = LVCMOS33;
NET "sys_rst" IOSTANDARD = LVCMOS33;
NET "led_signal" LOC = D18;
NET "led_signal" IOSTANDARD = LVCMOS33;
#Created by Constraints Editor (xc6slx45t-csg324-3) - 2016/06/06
NET "sys_clk" TNM_NET = "sys_clk";
TIMESPEC TS_sys_clk = PERIOD "sys_clk" 50 MHz HIGH 50 %;
NET "signal_in_p" LOC = T12;
NET "signal_in_n" LOC = V12;
NET "sys_clk" LOC = G8;
NET "sys_rst" LOC = U3;
# PlanAhead Generated IO constraints
NET "signal_in_p" IOSTANDARD = LVDS_33;
约束文件 IO Planning PlanAhead 产生,原语的使用可参考:E:\Xilinx\ISE\14.7\ISE_DS\ISE\doc\usenglish\isehelp\spartan6 里面提供了所用器件的原语。
同时,Xilinx 器件内部信号内部还提供了 100 欧姆电阻匹配,可参考 Spartan-6 FPGA SelectIO Resources(UG381)
补充:
若要实现高速通信的场合,可以利用 FPGA 内部自带的 SelectIO 资源,利用 ISERDESE2、 OSERDESE2,实现串-并,并-串的转换,理论速度可达到 750Mbs,
参考资料:Spartan-6 FPGA Data Sheet: DC and Switching Characteristics(UG162)
通信框图:
因为串行转成并行的时候,输出的数据无法判断哪个 Bit 是高位,哪个 bit 是低位,因此,对于 ISERDESE2 可以利用 bitslip 信号来重新对齐串行数据以获得正确的字节数据;代码实现时,也需要先进行数据对齐,才能进行数据的正常接收。
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
module lvds_test(
input clk_50m,//全局时钟
input rstn, //复位
input clk_in_from_pin_p, //lvds时钟输出P
input clk_in_from_pin_n, //lvds时钟输入N
input data_in_from_pin_p, //lvds输入数据P
input data_in_from_pin_n, //lvds输入数据N
output clk_out_to_pin_p, //lvds时钟输出P
output clk_out_to_pin_n, //lvds时钟输出N
output data_out_to_pin_p, //lvds输出数据P
output data_out_to_pin_n //lvds输出数据N
);
wire clk_div_out_1; //低速时钟1,串行发送时钟的8分频
wire clk_div_out_2; //低速时钟2,串行接收时钟的8分频
wire [7:0] datain; //LVDS输入的8位并行数据
//产生LVDS发送的测试数据,0~FF
reg [7:0] dataout;
always @(posedge clk_div_out_1) begin
if (~rstn)
dataout <= 0;
else if (dataout == 8'hff)
dataout <= 0;
else
dataout <= dataout + 1'b1;
end
//产生BITSLIP信号,用于修改串转并的Bit的起始位置
wire [7:0] data_delay;
reg BITSLIP=1'b0;
reg slip_check;
reg equal=1'b0;
assign data_delay=datain;
always @(posedge clk_div_out_2)
begin
if (~rstn)
slip_check <= 1'b0;
else if(data_delay==8'h80) //当串转并的输入的数据为0x80的时候,检测开始
slip_check <= 1'b1;
else
slip_check <= 1'b0;
end
always @(posedge clk_div_out_2)
begin
if (~rstn) begin
BITSLIP <= 1'b0;
equal<=1'b0;
end
else if((slip_check==1'b1) && (equal==1'b0))
if (data_delay ==8'h81) begin //如果检测到数据0x80后面的下一个时钟的数据为0x81时
BITSLIP <= 1'b0; //BITSLIP不为高
equal<=1'b1; //数据正确信号为高
end
else begin
BITSLIP <= 1'b1; //BITSLIP产生一个高脉冲,改变串转并的数据排列
equal<=1'b0; //数据正确信号为低
end
else begin
BITSLIP <= 1'b0;
equal<=equal;
end
end
//并转串,8位数据dataout转换成串行数据,并通过lvds差分信号输出
p_to_s p_to_s_inst
(
// From the device out to the system
.DATA_OUT_FROM_DEVICE(dataout), //Input pins
.DATA_OUT_TO_PINS_P(data_out_to_pin_p), //Output pins
.DATA_OUT_TO_PINS_N(data_out_to_pin_n), //Output pins
.CLK_TO_PINS_P(clk_out_to_pin_p), //Output pins
.CLK_TO_PINS_N(clk_out_to_pin_n), //Output pins
.CLK_IN(clk_50m), // Single ended clock from IOB
.CLK_DIV_OUT(clk_div_out_1), // Slow clock output
.IO_RESET(~rstn) //system reset
);
//串转并,LVDS差分信号转换成单端信号再通过串转并,转换为8位数据datain
s_to_p s_to_p_inst
(
// From the system into the device
.DATA_IN_FROM_PINS_P(data_in_from_pin_p), //Input pins
.DATA_IN_FROM_PINS_N(data_in_from_pin_n), //Input pins
.DATA_IN_TO_DEVICE(datain), //Output pins
.BITSLIP(BITSLIP), //Input pin
.CLK_IN_P(clk_in_from_pin_p), // Differential clock from IOB
.CLK_IN_N(clk_in_from_pin_n), // Differential clock from IOB
.CLK_DIV_OUT(clk_div_out_2), // Slow clock output
.IO_RESET(~rstn) //system reset
);
endmodule
其中,clk_div_out_1 和 clk_div_out_2 是 8 分频得到的(ISERDESE2、 OSERDESE2 核实现),OSERDESE2 输出的 LVDS 差分时钟可作为 ISERDESE2 的接收时钟。
END
作者:yang_jun1219
来源:FPGA技术江湖
相关文章推荐
- 基于 FPGA 的低成本、低延时成像系统
- Xilinx Zynq 系列 FPGA 实现神经网络中相关资源评估
- 使用 FPGA 搭建逻辑分析仪-USB 2.0 篇
- FPGA Signal tap 逻辑分析仪使用教程
- 最实用的 Modelsim 使用教程
更多 FPGA 干货请关注 FPGA 的逻辑技术专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。