xilinx IBUFDS 使用和仿真
接收代码:
以下代码的功能为:接收16位的LVDS差分信号接收:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library ieee;
use ieee.std_logic_1164.all;
Library UNISIM;
use UNISIM.vcomponents.all;
entity LVDS_RX_TEST is
port (
k7_rclkp : in std_logic;
k7_rclkn : in std_logic;
lvds_rx_dp : in std_logic_vector(15 downto 0);
lvds_rx_dn : in std_logic_vector(15 downto 0);
adc_clk : out std_logic;
adc_dat : out std_logic_vector(31 downto 0)
);
end LVDS_RX_TEST;
architecture rtl of LVDS_RX_TEST is
signal k7_rclk : std_logic;
signal lvds_rx_dat : std_logic_vector(15 downto 0);
signal adc_dat_i : std_logic_vector(31 downto 0);
signal adc_dat_r : std_logic_vector(31 downto 0);
signal k7_rclk_bufds : std_logic;
begin
adc_clk <= k7_rclk;
process (k7_rclk)
begin
if (k7_rclk'event and k7_rclk = '1') then
adc_dat_r <= adc_dat_i;
adc_dat <= adc_dat_r;
end if;
end process;
K7_RCLK_IBUFDS_INST : IBUFDS
generic map (
DIFF_TERM => TRUE, -- Differential Termination
IBUF_LOW_PWR => FALSE, -- Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
IOSTANDARD => "LVDS_25")
port map (
O => k7_rclk_bufds, -- Buffer output
I => k7_rclkp, -- Diff_p buffer input (connect directly to top-level port)
IB => k7_rclkn -- Diff_n buffer input (connect directly to top-level port)
);
K7_RCLK_BUFG_INST : BUFG
port map (
O => k7_rclk, -- 1-bit output: Clock output
I => k7_rclk_bufds -- 1-bit input: Clock input
);
lvds_rx_gen:
for i in 0 to 15 generate
begin
IBUFDS_inst : IBUFDS
generic map (
DIFF_TERM => TRUE, -- Differential Termination
IBUF_LOW_PWR => FALSE, -- Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
IOSTANDARD => "LVDS_25")
port map (
O =>lvds_rx_dat(i), -- Buffer output
I => lvds_rx_dp(i), -- Diff_p buffer input (connect directly to top-level port)
IB => lvds_rx_dn(i) -- Diff_n buffer input (connect directly to top-level port)
);
IDDR_inst : IDDR
generic map (
DDR_CLK_EDGE=> "SAME_EDGE_PIPELINED", --"OPPOSITE_EDGE", "SAME_EDGE"
-- or "SAME_EDGE_PIPELINED"
INIT_Q1 => '0', -- Initial value of Q1: '0' or '1'
INIT_Q2 => '0', -- Initial value of Q2: '0' or '1'
SRTYPE => "SYNC") -- Set/Reset type: "SYNC" or "ASYNC"
port map (
Q1 => adc_dat_i(i), -- 1-bit output for positive edge of clock
Q2 => adc_dat_i(16+i), -- 1-bit output for negative edge of clock
C => k7_rclk, -- 1-bit clock input
CE => '1', -- 1-bit clock enable input
D => lvds_rx_dat(i), -- 1-bit DDR data input
R => '0', -- 1-bit reset
S => '0' -- 1-bit set
);
end generate;
end rtl;
原始仿真代码:
一开始的仿真代码如下:
module TB;
// Inputs
reg k7_rclkp;
reg k7_rclkn;
reg [15:0] lvds_rx_dp;
reg [15:0] lvds_rx_dn;
// Outputs
wire adc_clk;
wire [31:0] adc_dat;
LVDS_RX_TEST uut (
.k7_rclkp(k7_rclkp),
.k7_rclkn(k7_rclkn),
.lvds_rx_dp(lvds_rx_dp),
.lvds_rx_dn(lvds_rx_dn),
.adc_clk(adc_clk),
.adc_dat(adc_dat)
);
initial begin
k7_rclkp = 1;
k7_rclkn = 0;
lvds_rx_dp = 0;
lvds_rx_dn = 0;
// Wait 100 ns for global reset to finish
#100;
end
always #100 k7_rclkp=~k7_rclkp;
always #100 k7_rclkn=~k7_rclkn;
always #100 lvds_rx_dp =lvds_rx_dp +2'b11;
always #100 lvds_rx_dn = lvds_rx_dn +2'b10;
endmodule
仿真结果有误:
从图中可以看出lvds_rx_dat一直为高阻态,接收到的信号均为错误信号!!
原因分析:
分析发现是IBUFDS原语的输出有问题!具体原因是自己对LVDS和IBUFDS的理解不到位,导致写出always #10000 lvds_rx_dp =lvds_rx_dp +2'b11;
always #10000 lvds_rx_dn = lvds_rx_dn +2'b10;这样错误的测试语句。
事实上LVDS是差分信号,即lvds_rx_dp与lvds_rx_dn的每bit均是相反信号;IBUFDS原语的真值表如下:(其中“-*”表示输出维持上一次的输出值,保持不变)
IBUFDS原语用于将差分输入信号转化成标准单端信号,且可加入可选延迟。在IBUFDS原语中,输入信号为I、IB,一个为主,一个为从,二者相位相反。
修改后的仿真代码:
module TB;
// Inputs
reg k7_rclkp;
reg k7_rclkn;
reg [15:0] lvds_rx_dp;
reg [15:0] lvds_rx_dn;
// Outputs
wire adc_clk;
wire [31:0] adc_dat;
// Instantiate the Unit Under Test (UUT)
LVDS_RX_TEST uut (
.k7_rclkp(k7_rclkp),
.k7_rclkn(k7_rclkn),
.lvds_rx_dp(lvds_rx_dp),
.lvds_rx_dn(lvds_rx_dn),
.adc_clk(adc_clk),
.adc_dat(adc_dat)
);
initial begin
// Initialize Inputs
k7_rclkp = 1;
k7_rclkn = 0;
lvds_rx_dp = 0;
lvds_rx_dn = 0;
#100;
end
always #100 k7_rclkp=~k7_rclkp;
always #100 k7_rclkn=~k7_rclkn;
always #100 lvds_rx_dp =lvds_rx_dp +2'b11;
always #100 lvds_rx_dn = ~lvds_rx_dp;
endmodule
修改后的仿真波形:
总结:
xilinx IBUFDS接收时先接时钟高电平的数据,但将其置于输出信号的低位!(高低位由语句:
Q1 => adc_dat_i(i), -- 1-bit output for positive edge of clock
Q2 => adc_dat_i(16+i), -- 1-bit output for negative edge of clock)决定