赞
踩
两个器件进行通讯时,至少都需要一个数据线来传输数据,并且还需要满足一定的时序才能保证数据准确的传输。像UART、SPI、IIC等传输频率并不高,布线的传输延时可忽略不计,只要满足相应的协议就可实现数据的传输,当然这种情况只限外部干扰较小的情况,如果要确保传输的准确性,还需要进行校验。但在高速传输时,在硬件上通过差分传输来降低外界的干扰信号,但数据线的长短会影响传输的时长。如通过clk和data两对差分线进行传输,由于clk的布线与dara的布线存在长短上的差异,主机传输到从机后clk和data的延时各不相同。如果我们希望在时钟上升沿上采集数据,但由于线的延时,可能在时钟上升沿时数据处于变化状态,这将会导致采集的数据错误。通过IDELAYE2原语可将某根信号线进行延时操作,以达到在时钟上升沿数据处于稳定的操作。
本文章是作者学习LVDS时的学习笔记,主要参考UG471和PG070。
IDELAYE2是Xilinx内部的输入信号延时资源,它主要是把输入信号延时一段时间。IDELAYE2可以一共有四个工作模式:固定延迟模式(FIXED), 可变延迟模式(VARIABLE), 可加载可变延迟模式(VAR_LOAD或VAR_LOAD_PIPE),VAR_LOAD与VAR_LOAD_PIPE模式相识,只是加载的位置不同,下文会进行阐述。
IDELAY2是一个可编程的31阶延迟原语,通过改变tap的值可以改变数据线的延时大小,其延时的分辨率与参考时钟频率f有关,延时的分辨率delay_resolution计算公式如下:
delay_resolution = 1/(32 * 2 * f)*1000000(ps)
其中f单位为Mhz。
当f=200Mhz时,delay_resolution=78ps(注:计算出来为78.125ps,但会取整,为78ps);
同样,当f=300Mhz时,delay_resolution=52ps。
延时的具体大小计算如下:
1.当tap=0时,我们要弄清一个误区,tap=0时并不是延时就是0,此时delay_time=600ps;
2.当tap!=0时,delay_time=600ps + tap * delay_resolution。
在该模式下数据延迟由属性IDELAY_VALUE设置,且延迟固定,不可更改。在该模式下,IDELAYCTRL原语必须例化。
在该模式下,延迟值可以在配置后通过CE和INC端口进行动态配置。同样,在该模式下,IDELAYCTRL原语也必须例化。该模式下的逻辑控制对应关系如下表所示。
该模式下功能与VARIABLE模式下类似,只不过可以通过CNTVALUEIN加载延迟节拍数。多了一种延迟加载方法。当LD端口有效时可以加载新的延迟CNTVALUE值到控制模块。该模式下逻辑功能关系如下表所示。
下图为可变模式下的延迟时序图。
参考前文可变延迟模式下的逻辑表,可见1时刻C=1,LD=1,CE=0,INC=0,则会加载IDELAY_VALUE的值到tap上,即此时tap0=IDELAY_VALUE;在时刻2时,C=1,LD=0,CE=1,INC=1,tap的值会自动累加1,即tap1=IDELAY_VALUE + 1;在时刻3时,C=1,LD=0,CE=0,INC=0,tap的值不变,即tap1=IDELAY_VALUE + 1;
参考前文可加载可变延迟模式下的逻辑表,可见1时刻C=1,LD=1,INC=0,CE=0,CNTVALUEIN=5’b00010,则会加载CNTVALUEIN的值到tap上,即tap=5‘b00010;在2时刻C=1,LD=0,INC=1,CE=1,CNTVALUEIN=5’b01010,则此时tap的值会自动加1,即tap=5‘b00010 + 1’b1 = 5‘b00011;在3时刻,C=1,LD=1,INC=0,CE=0,CNTVALUEIN=5’b01010,则会加载CNTVALUEIN的值到tap上,即tap=5‘b01010;
`timescale 1ns / 1ps
module idelay_test(
input clk_in_50,
input reset,
input[4:0] in_delay_tap_in_int,
input in_delay_ce,
input data_in_from_pins_int,
input in_delay_inc_dec,
input LD,
output delay_locked,
output[4:0] in_delay_tap_out_int,
output data_in_from_pins_delay
);
wire ref_clock_bufg;
wire ref_clock;
wire io_reset;
wire clk_200 ;
wire clk_100 ;
wire clk_50 ;
wire clk_25 ;
wire locked ;
assign ref_clock = clk_200;
assign io_reset = locked ? reset:1'b1;
assign clk_div_in = clk_50;
clk_wiz_0
clk_wiz_0_inst
(
.clk_200m (clk_200 ),
.clk_100m (clk_100 ),
.clk_50m (clk_50 ),
.clk_25m (clk_25 ),
.reset (reset ),
.locked (locked),
.clk_in1 (clk_in_50)
);
// (* IODELAY_GROUP = <iodelay_group_test> *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("FIXED"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
)
IDELAYE2_inst (
.CNTVALUEOUT(in_delay_tap_out_int), // 5-bit output: Counter value output
.DATAOUT(data_in_from_pins_delay), // 1-bit output: Delayed data output
.C(clk_div_in), // 1-bit input: Clock input
.CE(in_delay_ce), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(in_delay_tap_in_int), // 5-bit input: Counter value input
.DATAIN(1'b0), // 1-bit input: Internal delay data input
.IDATAIN(data_in_from_pins_int), // 1-bit input: Data input from the I/O
.INC(in_delay_inc_dec), // 1-bit input: Increment / Decrement tap delay input
.LD(LD), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(io_reset) // 1-bit input: Active-high reset tap-delay input
);
// (* IODELAY_GROUP = <iodelay_group_test> *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYCTRL IDELAYCTRL_inst (
.RDY(delay_locked), // 1-bit output: Ready output
.REFCLK(ref_clock_bufg), // 1-bit input: Reference clock input
.RST(io_reset) // 1-bit input: Active high reset input
);
BUFG
ref_clk_bufg (
.I (ref_clock),
.O (ref_clock_bufg));
endmodule
`timescale 1ns / 1ps
module idelay_test_tb( );
reg clk_in_50 ;
reg reset ;
reg LD ;
reg in_delay_ce ;
reg in_delay_inc_dec ;
wire delay_locked ;
reg[4:0] in_delay_tap_in_int ;
wire[4:0] in_delay_tap_out_int ;
reg data_in_from_pins_int ;
wire data_in_from_pins_delay ;
`define clk_period 20
`define clk_div_in_period 20
idelay_test
idelay_test_utt(
.clk_in_50 (clk_in_50 ),
.reset (reset ),
.in_delay_tap_in_int (in_delay_tap_in_int ),
.in_delay_ce (in_delay_ce ),
.data_in_from_pins_int (data_in_from_pins_int ),
.in_delay_inc_dec (in_delay_inc_dec ),
.LD (LD ),
.delay_locked (delay_locked ),
.in_delay_tap_out_int (in_delay_tap_out_int ),
.data_in_from_pins_delay (data_in_from_pins_delay )
);
initial begin clk_in_50 =0; end
always #(`clk_period/2) clk_in_50=~clk_in_50;
initial begin
// FIXED_task;
// VARIABLE_task;
VAR_LOAD_task;
$stop;
end
task init;
begin
reset =1;
in_delay_tap_in_int =0;
in_delay_ce =0;
data_in_from_pins_int =0;
in_delay_inc_dec =0;
LD =0;
#(`clk_div_in_period*10+1);
reset =0;
@(posedge idelay_test_utt.locked);
#(`clk_div_in_period*5);
end
endtask
task FIXED_task;
begin
init;
data_in_from_pins_int = 1;
#(`clk_div_in_period*10);
end
endtask
task VARIABLE_task;
begin
init;
repeat(3)begin
/*******tap自加1********/
in_delay_ce = 1;
in_delay_inc_dec = 1;
#(`clk_div_in_period*1);
in_delay_ce = 0;
in_delay_inc_dec = 0;
data_in_from_pins_int = ~data_in_from_pins_int;
/*********END************/
#(`clk_div_in_period*1000);
end
/**加载CNTVALUEIN到tap中*/
LD = 1;
#(`clk_div_in_period*1);
LD = 0;
data_in_from_pins_int = ~data_in_from_pins_int;
#(`clk_div_in_period*1000);
/*********END************/
repeat(3)begin
/*******tap自减1********/
in_delay_ce = 1;
in_delay_inc_dec = 0;
#(`clk_div_in_period*1);
in_delay_ce = 0;
in_delay_inc_dec = 0;
data_in_from_pins_int = ~data_in_from_pins_int;
/*********END************/
#(`clk_div_in_period*1000);
end
/**加载CNTVALUEIN到tap中*/
LD = 1;
#(`clk_div_in_period*1);
LD = 0;
data_in_from_pins_int = ~data_in_from_pins_int;
#(`clk_div_in_period*1000);
/*********END************/
end
endtask
task VAR_LOAD_task;
begin
init;
/*******CNTVALUEIN task********/
in_delay_tap_in_int = 10;
#(`clk_div_in_period*5);
LD = 1;
#(`clk_div_in_period*1);
LD = 0;
data_in_from_pins_int = ~data_in_from_pins_int;
#(`clk_div_in_period*1000);
/*********END************/
repeat(3)begin
/*******tap自加1********/
in_delay_ce = 1;
in_delay_inc_dec = 1;
#(`clk_div_in_period*1);
in_delay_ce = 0;
in_delay_inc_dec = 0;
data_in_from_pins_int = ~data_in_from_pins_int;
/*********END************/
#(`clk_div_in_period*1000);
end
/*******CNTVALUEIN task********/
in_delay_tap_in_int = 15;
#(`clk_div_in_period*5);
LD = 1;
#(`clk_div_in_period*1);
LD = 0;
data_in_from_pins_int = ~data_in_from_pins_int;
#(`clk_div_in_period*1000);
/*********END************/
end
endtask
endmodule
注:在进行仿真时需要将IDELAY_TYPE修改为对应的模式。
当IDELAY_TYPE = FIXED为FIXED模式,线的延时时间由IDELAY_VALUE来确定。
首先当IDELAY_VALUE = 0时,仿真结果如下:
可见,线延时了600ps。
当IDELAY_VALUE = 1时,仿真结果如下:
可见,线延时了(600 + 78)ps = 678ps。
当IDELAY_VALUE = 31时,仿真结果如下:
可见,线延时了(600 + 78*31)ps = 3018ps。
延时大小为(600 + 78*13)ps = 3018ps。
可见延时的大小按照上述执行。
延时大小为(600 + 78*15)ps = 1770ps。
可见延时的大小按照上述执行。
本文针对IDELAYE2原语进行详解,阐明了延时的最小分辨率与参考时钟有关,分辨率为delay_resolution = 1/(322f)*1000000(ps)。通过编写测试代码,对IDELAYE2的FIXED模式、VARIABLE模式及VAR_LOAD模式进行了仿真,结果与UG471一致。
工程文件
https://download.csdn.net/download/weixin_45372778/66985301
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。