Menu Close

高速通信分层设计—PRX100-D开发板实验(Xilinx)

之前的课程中,我们实现了高速通信分层设计–FII-PRA006 开发板(Altera)的实验。 这一节课,我们要将整个工程移植到Xilinx FPGA上。 这里,我们选用FII-PRX100-D 开发板。

实验目的:

  • 将Altera工程移植到Xilinx FPGA上
  • 实现之前的高速通信设计
  • 对比移植AlteraIP 到 Xilinx IP
  • 实现相关的管脚约束

工程环境:

Vivado 2018.2

FII-PRX100-D 开发板  (ARTIX 100T XILINX FPGA)

本实验在高速通信分层设计—PRA006开发板实验(Altera)的基础上做出修改而成的,通篇以修改后的源代码呈现给大家,在每个程序后面有对应的相关修改的解释。

1 顶层工程代码:

 

`timescale 1 ns / 1 ps
//`define SIM
module top
#(
    parameter IDLE = 10'b1010_1010_10
)
`ifdef SIM
    ();


    parameter       PERIOD = 20 ;  		//周期20

    reg             inclk ;	  				// 模拟板级提供的输入时钟

    initial begin
        inclk = 1'b0;
        #(PERIOD/2);
        forever
            #(PERIOD/2) inclk = ~inclk;
    end

    reg            pll_rst;  			//实体模块PLL的rst信号
    wire           tx_p;
    wire           tx_n;
    wire           rx_p;
    wire           rx_n;

    assign rx_p = tx_p;
    assign rx_n = tx_n;
        
    initial begin
        pll_rst=1'b1;
        #50 pll_rst=1'b0;
        
        #50000;
        $stop;
    end	
`else
    (
        input  inclk,

        output tx_p,
        output tx_n,
        
        input  rx_p,
        input  rx_n,
        
        output LED
    );
`endif

wire pll_locked;

wire reset = !pll_locked;

(* mark_debug = "true" *)wire tx_rdy;
(* mark_debug = "true" *)reg  [ 7: 0 ] tx_data;
(* mark_debug = "true" *)reg  tx_en;

(* mark_debug = "true" *)reg  tx_vld;
(* mark_debug = "true" *)wire tx_vld_ack;

(* mark_debug = "true" *)wire rx_data_vld;
(* mark_debug = "true" *)wire rx_data_rdy;
(* mark_debug = "true" *)wire ko;
(* mark_debug = "true" *)wire [ 7: 0 ] rx_data;

wire clk_100M;

localparam LEN = 16;
reg [ 7: 0 ] frame_len;
reg [ 2: 0 ] tx_st;

always@( posedge clk_100M or posedge reset )
    if ( reset )
    begin
        tx_vld <= 1'b0;
        tx_en <= 1'b0;
        frame_len <= 0;

        tx_data <= 0;
        tx_st <= 0;
    end
    else
    begin
        case ( tx_st )
            0:
            begin
                tx_vld <= 1'b0;
                tx_en <= 1'b0;
                tx_data <= 0;
                frame_len <= 0;
                tx_st <= 1;
            end
            1:
            begin
                tx_en <= 1'b0;
                tx_vld <= 1'b1;

                if ( frame_len == LEN )
                begin
                    tx_vld <= 1'b0;
                    tx_st <= 3;
                end
                else if ( tx_rdy )
                begin

                    tx_en <= 1'b1;
                    tx_st <= 2;
                end

            end
            2:
            begin
                tx_en <= 1'b0;
                frame_len <= frame_len + 1;
                tx_data <= tx_data + 1;
                tx_st <= 1;
            end
            3:
            begin
                frame_len <= 0;
                tx_vld <= 1'b0;
                tx_en <= 1'b0;

                if ( tx_vld_ack )
                    tx_st <= 1;
            end
            default:
                tx_st <= 0;
        endcase
    end

//=======================================================================================
(* mark_debug = "true" *)wire tx;
(* mark_debug = "true" *)wire rx;
IBUFDS #(
    .DIFF_TERM      ("TRUE"),   // Differential Termination
    .IBUF_LOW_PWR   ("TRUE"),   // Low power="TRUE", Highest performance="FALSE" 
    .IOSTANDARD     ("LVDS_25") // Specify the input I/O standard
) IBUFDS_rx_inst (
    .O  (rx),   // Buffer output
    .I  (rx_p), // Diff_p buffer input (connect directly to top-level port)
    .IB (rx_n)  // Diff_n buffer input (connect directly to top-level port)
);

    
OBUFDS #(
    .IOSTANDARD     ("LVDS_25"),// Specify the output I/O standard
    .SLEW           ("SLOW")    // Specify the output slew rate
) OBUFDS_tx_inst (
    .O  (tx_p), // Diff_p output (connect directly to top-level port)
    .OB (tx_n), // Diff_n output (connect directly to top-level port)
    .I  (tx)    // Buffer input
);    
    

hs_txrx
#(
    .IDLE (IDLE)
)
hs_txrx_inst
(
    .inclk      (inclk),
    .pll_rst    (pll_rst),

    .tx_rdy     (tx_rdy),
    .tx_vld     (tx_vld),
    .tx_data    (tx_data),
    .tx_en      (tx_en),
    .tx_vld_ack (tx_vld_ack),
    .tx         (tx),
    .rx         (rx),
    .rx_data_vld(rx_data_vld),
    .rx_data_rdy(rx_data_rdy),
    .ko         (ko),
    .rx_data    (rx_data),
    
    .clk_100M   (clk_100M),
    .pll_locked (pll_locked)
);

`ifndef SIM
    reg [31:0] led_cnt = 0;
    always @ (posedge clk_100M)
    led_cnt <= led_cnt + 1;

    assign LED = led_cnt[25];
`endif
endmodule

Vivado工程的顶层代码中对外端口与Quartus工程中的对外端口设计不同。 Xilinx FPGA 使用IBUFDS,OBUFDS 原语实现单端信号rx,tx 到差分信号的转换,所以在端口上的定义为tx_p, tx_n;  rx_p, rx_n。单端信号到差分信号的转换也可以使用Xilinx SelectIO IP 核实现。 本文使用IBUFDS,OBUFDS 原语。

在仿真程序中, 不再使用tx_rx 信号连接 发送和接收端口, 而是使用 assign rx_p = tx_p;   assign rx_n = tx_n; 来实现。

2 修改hs_txrx.v代码:

/*
pll1 pll1_inst
(
    .areset     ( pll_rst ),    //1'b0;
    .inclk0     ( inclk ),
    .c0         ( clk_100M ),
    .c1         ( clk_400M ),
    .locked     ( pll_locked )

);
*/

pll1 pll1_inst
(
    // Clock out ports
    .clk_out1   (clk_100M),     // output clk_out1
    .clk_out2   (clk_400M),     // output clk_out2
    // Status and control signals
    .reset      (pll_rst),      // input reset
    .locked     (pll_locked),   // output locked
    // Clock in ports
    .clk_in1    (inclk)         // input clk_in1
);

将Altera PLL替换为Xilinx clock IP。

Xilinx clock IP 例化如下:

图1

图2

3 修改tx_pmd.v代码:

module tx_PMD
(
    input tx_in,
    output tx_out
);

assign tx_out = tx_in;
/*
IO_TX IO_TX_INST
(
    .tx_in  ( tx_in ),
    .tx_out ( tx_out )
);
*/
endmodule

 

在Quartus 工程中, 使用IO_TX IP 核, 当移植到Xilinx FPGA 时, 这里将不再使用IP核, 而是在top.v 文件中使用 OBUFDS 来实现.

4 修改recv_bit_pmd.v代码:

assign rx_out = rx;
/*    
IO_RX IO_RX_inst
(
    .rx_in  ( rx ),
    .rx_out ( rx_out )
);
*/

同样, 注释Quartus 工程中的IO_RX IP , 而是在top.v 文件中使用 IBUFDS 原语实现。

5 对比移植altera IP 到 Xilinx IP:

Quartus 工程 , 使用PLL IP核, IO_TX和IO_RX  IP核 。 其中PLL 输入50M 时钟, 输出 100M, 400M 时钟。

Vivado 工程: 使用PLL IP核,IBUFDS 和 OBUFDS 原语。 其中PLL 也是输入50M 时钟, 输出为100M,400M 时钟,Xilinx需要使用xBUFDS (x 表示 I 或者 O)原语实现单端信号到差分信号的转换。

6 实现相关的管脚约束:

#==================================================
#clk
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports inclk]
create_clock -period 20.000 -name OSC_CLK -waveform {0.000 10.000} [get_ports inclk]

set_property -dict {PACKAGE_PIN R7 IOSTANDARD LVCMOS33} [get_ports pll_rst]

set_property -dict {PACKAGE_PIN N23 IOSTANDARD LVCMOS33} [get_ports LED]


set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVDS_25 } [get_ports tx_p]
set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVDS_25 } [get_ports tx_n]
set_property -dict {PACKAGE_PIN K7 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_p]
set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_n]



 

Xilinx文档中相关阻抗匹配部分如下所示:

图3

set_property -dict {PACKAGE_PIN K7 IOSTANDARD LVDS_25    DIFF_TERM 1} [get_ports rx_p]

在管脚约束文件中定义管脚为lvds_25 标准, 同时使用DIFF_TERM 1或者DIFF_TERM TRUE,表示使用内部差分电阻。

注:在使用Artix 系列FPGA 使用LVDS差分功能时, 需要管脚连接的bank 电压 <=  2.5v  。 目前,我们使用tx_p, tx_n, rx_p, rx_n 都是连接在bank35中。 所以需要将bank35 的电压设置为 <= 2.5v ,否则FPGA 不会工作,因此这里选择bank35电压为1.8V。如图4所示:

图4

 

7 .  FII-PRX100-D高速通信回环实验设置

  •     原理图部分如图5,图6所示:

图5

图6

  • 开发板硬件连线如图7所示:

图7

8 使用ILA (mark_debug)调试高速通信信号:

图8

 

图9

示波器波形:

图10

其中 紫色信号连接tx_p,  黄色信号连接 tx_n。 白色信号为 tx_p – tx_n  得到相关的差分信号。

由于通信工程当中的逻辑验证部分在之前的文章中已经介绍过,这里只演示了在线的硬件调试部分内容。

关于详细的实验内容,请参见对应的视频。

 

vivado 2018.2 工程代码:

[content_control]

high_speed_xilinx.zip

[/content_control]

Posted in FPGA, FPGA 教材教案, Verilog, 教材与教案, 文章

发表回复

相关链接