在高速信号采集的过程中,经常会因为电路设计或者其他原因,原本设计好对应的data_clk与data经过线路传输之后在接收端时序上不能很好的对应,这可能会造成采样数据的错位。
如果用了各种物理电路上的办法都没法解决后,可以尝试使用Idelay(针对Xilinx,Altera应该也有相应的原语)。
Xilinx每个系列可能Idelay的名字会有一些差异,但差异不大,在K7系列下,Idelay的原语叫做Idelay2。
Idelay2原语示例:
(* IODELAY_GROUP = "RX_FRAME" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("DATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(INIT_VALUE), // 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(cnt_value), // 5-bit output: Counter value output
.DATAOUT(rx_frame_dly), // 1-bit output: Delayed data output
.C(sys_clk), // 1-bit input: Clock input
.CE(1'b0), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(tap_value), // 5-bit input: Counter value input
.DATAIN(rx_frame), // 1-bit input: Internal delay data input
.IDATAIN(1'b0), // 1-bit input: Data input from the I/O
.INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
.LD(1'b1), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
);
针对其中经常用到的变量,功能如下:
DELAY_SRC常量,这个常量可以选DATAIN或IDATAIN,区别在于IDATAIN的数据输入要求经过BUF产生,常用于BUF的输出信号,Input端口信号;DATAIN只要求FPGA内部逻辑产生的信号就可以。
IDELAY_TYPE,设置IDELAY2的模式;FIXED代表延时值固定,一般用在确定好参数后使用,VARIBLE,VAR_LOAD,VAR_LOAD_PIPE都是动态改变延时值,VARIBLE可以自动增大减小,后两个是根据CINVALUEIN端口动态改变延时值,一般选用VAR_LOAD。
IDELAY_VALUE,是初始化的值,在FIXED模式下,就是固定的延时值
REFCLK_FREQUENCY,指的Idelay的参考时钟的频率,一般选用200M,这个后面会具体讲。
SIGNAL_PATTERN,这个有DATA和CLOCK两个选项,影响Vivado对信号时序分析的路径。
端口中,
CNTVALUEIN是设置延时值,用于手动调试;
CNTVALUEOUT输出当前延时值,便于调试观测;
C是数据时钟,但CE不是时钟使能,而是延时值tap自动增加减少使能,所以我选择拉低;
CINVCTRL,INC,LDPIPEEIN,REGRST不怎么用,全拉低;
在上面的DELAY_SRC选择了哪一个,就在对应的数据端口连接数据,另一个数据端口拉低,比如DELAY_SRC设定为"DATAIN",选择DATAIN端口输入数据,IDATAIN端口拉低;
因为需要手动调节延时值,所以LD拉高,只有LD拉高才能动态载入CNTVALUEIN的延时值
前面说到参考时钟,Idelay之所以延时,CINVALUEIN对应的延时值多少就跟这个地方有关系了,参考时钟不是随便设的,这跟另一个原语IDELAYCTRL有关:
(* IODELAY_GROUP = "RX_FRAME" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
IDELAYCTRL IDELAYCTRL_inst (
.RDY(idelay_rdy), // 1-bit output: Ready output
.REFCLK(ref_clk), // 1-bit input: Reference clock input
.RST(rst) // 1-bit input: Active high reset input
);
这个原语端口很少,连接对应200M的参考时钟,复位信号,输出一个ready信号;
看起来这个原语并没有什么有用的输出;但其实它的作用是给Idelay2提供了延时的依据;之所以可以精确延时并不是说我们在REFCLK_FREQUENCY填一个200就可以了,而是这个IDELAYCTRL 的作用,通过(* IODELAY_GROUP = "RX_FRAME" *)将IDELAYCTRL 和Idelay2连接起来,"RX_FRAME"类似于组名,可以随意改,同一组的组名要一样。
200MHz 对应1个时钟周期5ns,Idelay将其分为64tap,每个tap延时值大概是78ps,Idelay可调的最大tap为31,也就是延时值控制在0-31tap;
同样,为了减小相同参考时钟下Idelay2与IDELAYCTRL 的FPGA内部走线延时,必须使用IODELAY_GROUP将它们绑定在一起,使用方法参考上面的做法。
注意,IDELAYCTRL 的REFCLK输入时钟一定要经过BUFG输出再接入。
效果:
没加Idelay
没有加Idelay,并串转换中找不到帧头
加入Idelay
加了Idelay,找到帧头
总结:
使用方法都在上面,对于多bit信号可以使用generate for 生成块。
调试这个的时候遇到过一个问题,C端口没有连接到正常的时钟,连接到一个根本没有定义的信号,Vivado做好事不留名的直接帮我拉低到地,导致我在VAR_LOAD模式下一直无法正常改变延时值,CNTVALUEOUT与CINVALUEIN不正确,最后打开Schematic看RTL图才找到问题。
这一系列都是Xilinx中SelectIO的内容,包括I/ODDR,I/OBUFDS,下一篇就会讲到ISERDES,并串转换的一种用法,Idelay经常与ISERDES一同出现,解决高速串行通信上的问题。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !