FPGAのIODELAYの可変遅延を動作させてみる(Xilinx7シリーズ )
はじめに
ARTY評価ボード(Artix7)を用いてFPGAのIOに実装されている遅延タップを動かしてみる。
IDELAYシンボルを使用すると、80ps単位で遅延をさせられるらしい。(リファレンスクロック:200MHZ)
使い道はあったりなかったりだと思うが、とりあえず動かしてみよう。
接続図
IDELAYシンボルを以下のようにつないでみる。
各遅延シンボルは固定遅延(800psぐらい)+80ps×32tapの遅延をするようである。
4つのシンボルをつなぐと一番下のOUT4は 0ns-10ns の遅延可変ができそうだ。
FPGAデザイン
IO_DELAYのソースをVerilogで作成した。
これ以外のFPGAソースは※1にGithubのリンクを記載。
// io_delay_module.v // author:manaka // date:20/07/19 // Description:First // History // module io_delay_module ( input rst ,input clk ,input rst_reg ,output rdy ,input di_01 ,output do_01 ,input ldcnt_01 ,input [4:0] dicnt_01 ,output [4:0] docnt_01 ,input di_02 ,output do_02 ,input ldcnt_02 ,input [4:0] dicnt_02 ,output [4:0] docnt_02 ,input di_03 ,output do_03 ,input ldcnt_03 ,input [4:0] dicnt_03 ,output [4:0] docnt_03 ,input di_04 ,output do_04 ,input ldcnt_04 ,input [4:0] dicnt_04 ,output [4:0] docnt_04 ); // IDELAYCTRL: IDELAY/ODELAY Tap Delay Value Control 7 Series // Xilinx HDL Libraries Guide, version 13.1 (* IODELAY_GROUP = "test_io_delay" *) // Specifies group name for associated IODELAYs and IDELAYCTRL IDELAYCTRL IDELAYCTRL_inst ( .RDY (rdy ), // 1-bit Ready output .REFCLK (clk ), // 1-bit Reference clock input .RST (rst ) // 1-bit Reset input ); // End of IDELAYCTRL_inst instantiation // IDELAYE2: Input Fixed or Variable Delay Element // 7 Series // Xilinx HDL Libraries Guide, version 2012.2 // IDELAYE2 output1 (* IODELAY_GROUP = "test_io_delay" *) // 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 (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). .SIGNAL_PATTERN ("DATA" ) // DATA, CLOCK input signal ) IDELAYE2_i01 ( .CNTVALUEOUT (docnt_01 ), // 5-bit output: Counter value output .DATAOUT (do_01 ), // 1-bit output: Delayed data output .C (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 (dicnt_01 ), // 5-bit input: Counter value input .DATAIN (di_01 ), // 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 (ldcnt_01 ), // 1-bit input: Load IDELAY_VALUE input .LDPIPEEN (1'b0 ), // 1-bit input: Enable PIPELINE register to load data input .REGRST (rst_reg ) // 1-bit input: Active-high reset tap-delay input ); // IDELAYE2 output2 (* IODELAY_GROUP = "test_io_delay" *) // 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 (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). .SIGNAL_PATTERN ("DATA" ) // DATA, CLOCK input signal ) IDELAYE2_i02 ( .CNTVALUEOUT (docnt_02 ), // 5-bit output: Counter value output .DATAOUT (do_02 ), // 1-bit output: Delayed data output .C (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 (dicnt_02 ), // 5-bit input: Counter value input .DATAIN (di_02 ), // 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 (ldcnt_02 ), // 1-bit input: Load IDELAY_VALUE input .LDPIPEEN (1'b0 ), // 1-bit input: Enable PIPELINE register to load data input .REGRST (rst_reg ) // 1-bit input: Active-high reset tap-delay input ); // IDELAYE2 output3 (* IODELAY_GROUP = "test_io_delay" *) // 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 (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). .SIGNAL_PATTERN ("DATA" ) // DATA, CLOCK input signal ) IDELAYE2_i03 ( .CNTVALUEOUT (docnt_03 ), // 5-bit output: Counter value output .DATAOUT (do_03 ), // 1-bit output: Delayed data output .C (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 (dicnt_03 ), // 5-bit input: Counter value input .DATAIN (di_03 ), // 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 (ldcnt_03 ), // 1-bit input: Load IDELAY_VALUE input .LDPIPEEN (1'b0 ), // 1-bit input: Enable PIPELINE register to load data input .REGRST (rst_reg ) // 1-bit input: Active-high reset tap-delay input ); // IDELAYE2 output4 (* IODELAY_GROUP = "test_io_delay" *) // 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 (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). .SIGNAL_PATTERN ("DATA" ) // DATA, CLOCK input signal ) IDELAYE2_i04 ( .CNTVALUEOUT (docnt_04 ), // 5-bit output: Counter value output .DATAOUT (do_04 ), // 1-bit output: Delayed data output .C (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 (dicnt_04 ), // 5-bit input: Counter value input .DATAIN (di_04 ), // 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 (ldcnt_04 ), // 1-bit input: Load IDELAY_VALUE input .LDPIPEEN (1'b0 ), // 1-bit input: Enable PIPELINE register to load data input .REGRST (rst_reg ) // 1-bit input: Active-high reset tap-delay input ); endmodule
CPUの制御
100msごとに1TAPずつ増やしていく処理を作成した。
/* * test application * ------------------------------------------------ * | UART TYPE BAUD RATE | * ------------------------------------------------ * uartns550 9600 * uartlite Configurable only in HW design * ps7_uart 115200 (configured by bootrom/bsp) */ #include <stdlib.h> #include <stdio.h> #include "xil_printf.h" #include "xparameters.h" #include "xil_cache.h" #include "xintc.h" #include "xgpio.h" #include "xiic.h" XGpio Gpio; /* The Instance of the GPIO Driver */ // include lib src #include "sleep.h" #include "platform.h" #define GPIOPS_BASE (0x40000000) #define LED_ADDR (0x40010000) #define IO_DELAY_01 (0x40020000) int main() { // variable u32 reg_u32_buf; // main process init_platform(); print("IO Delay Test Start\n\r"); while (1) { // init delay value XGpio_WriteReg(0x40020000, 0x00, 0x00000000);// initialize delay count XGpio_WriteReg(0x40020000, 0x00, 0x20202020);// load enable XGpio_WriteReg(0x40020000, 0x00, 0xDFDFDFDF);// load disable // loop delay 1 for (u8 i = 0; i <= 31; i++){ reg_u32_buf = 0x000000FF & i ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 1b at bit5 reg_u32_buf |= 0x00000020 ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 0b at bit5 reg_u32_buf &= 0xFFFFFFDF ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); usleep_MB(100000);//100ms }; // loop delay 2 for (u8 i = 0; i <= 31; i++){ reg_u32_buf = 0x0000FF00 & (i << 8) ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 1b at bit13 reg_u32_buf |= 0x00002000 ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 0b at bit13 reg_u32_buf &= 0xFFFFDFFF ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); usleep_MB(100000);//100ms }; // loop delay 3 for (u8 i = 0; i <= 31; i++){ reg_u32_buf = 0x00FF0000 & (i << 16) ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 1b at bit21 reg_u32_buf |= 0x00200000 ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 0b at bit21 reg_u32_buf &= 0xFFDFFFFF ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); usleep_MB(100000);//100ms }; // loop delay 4 for (u8 i = 0; i <= 31; i++){ reg_u32_buf = 0xFF000000 & (i << 24) ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 1b at bit29 reg_u32_buf |= 0x20000000 ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); // Set 0b at bit29 reg_u32_buf &= 0xDFFFFFFF ; XGpio_WriteReg(0x40020000, 0x00, reg_u32_buf); usleep_MB(100000);//100ms }; } }
チップスコープ評価
さすがに自宅にGサンプルができるオシロスコープはないので、チップスコープで見てみる。
可変遅延0の時。
OUT1,3はトリガと同じクロックでサンプルされている。OUT4は固定遅延分があり、次のクロックでサンプルされている。
可変遅延最大の時。(+128TAP 10ns遅延)
OUT4は3クロック後にサンプルされている。
10ns遅延していることの裏付けとなる。
可変遅延最大の時。(+69TAP 5nsぐらい遅延)
トリガ+2CLKなので5nsは遅延ているようである。
オシロ評価
しかし実際は80psごとに波形がきれいにシフトしていくはずである。
高機能なオシロを拝借してみてみると、きれいに80psステップで遅延が増加していく波形が確認できた。
最後に
実際どんな時にこのシンボルを使うのだろうか?
高速なDDRのバスの微調整などだろうか?
気になる。
注釈
githubのソース準備中