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)決定