よくわからないFPGAのこととか

よくわからないFPGAとか回路とか数学とかについて

FPGAのIODELAYの可変遅延を動作させてみる(Xilinx7シリーズ )


はじめに

ARTY評価ボード(Artix7)を用いてFPGAのIOに実装されている遅延タップを動かしてみる。

f:id:manaka1122:20200722231759j:plain
io_delay概要

IDELAYシンボルを使用すると、80ps単位で遅延をさせられるらしい。(リファレンスクロック:200MHZ)
使い道はあったりなかったりだと思うが、とりあえず動かしてみよう。


接続図

IDELAYシンボルを以下のようにつないでみる。
各遅延シンボルは固定遅延(800psぐらい)+80ps×32tapの遅延をするようである。
4つのシンボルをつなぐと一番下のOUT4は 0ns-10ns の遅延可変ができそうだ。

f:id:manaka1122:20200722231827j:plain
io_delay接続図


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は固定遅延分があり、次のクロックでサンプルされている。

f:id:manaka1122:20200722232137j:plain
IO DELAY 実機波形 可変遅延無し(+0ns)

可変遅延最大の時。(+128TAP 10ns遅延)
OUT4は3クロック後にサンプルされている。
10ns遅延していることの裏付けとなる。

f:id:manaka1122:20200722232001j:plain
IO DELAY 実機波形 可変遅延最大(+10ns)

可変遅延最大の時。(+69TAP 5nsぐらい遅延)
トリガ+2CLKなので5nsは遅延ているようである。

f:id:manaka1122:20200722232046j:plain
IO DELAY 実機波形 可変遅延半分(+5ns)


オシロ評価

しかし実際は80psごとに波形がきれいにシフトしていくはずである。
高機能なオシロを拝借してみてみると、きれいに80psステップで遅延が増加していく波形が確認できた。


最後に

実際どんな時にこのシンボルを使うのだろうか?
高速なDDRのバスの微調整などだろうか?
気になる。


注釈

githubのソース準備中