SERDES是英文SERializer(串行器)/DESerializer(解串器)的简称。它是一种主流的时分多路复用(TDM)、点对点(P2P)的串行通信技术。即在发送端多路低速并行信号被转换成高速串行信号,经过传输媒体(光缆或铜线),最后在接收端高速串行信号重新转换成低速并行信号。这种点对点的串行通信技术充分利用传输媒体的信道容量,减少所需的传输信道和器件引脚数目,提升信号的传输速度,从而大大降低通信成本。xilinx 7系列通过原语调用serdes接口,就可以实现串并(并串)转化的应用。
平台:AT7 Xilinx USB3.0+LVDS+FPGA开发板
语言:SystemVerilog
功能:20M时钟产生8位的数据经serdes串化,由一对LVDS输出,再由另一对LVDS接收,经serdes解串恢复8bit的数据。
这里,在特权的LVDS测试例程上简化,只用调用原语serdes验证数据的传输(说实话,特权同学的例程代码,确实有点凌乱,前后看了两天。可能是对这些其中用到的原语不熟吧)
`timescale 1ns / 1ps
module srdes_test(
//外部输入时钟和复位接口
input logic sys_clk_i,
input logic ext_rst_n, //复位信号,低电平有效
//LED指示灯接口
output logic [7:0] led, //用于测试的LED指示灯
//LVDS发送接口
output logic [1:0] lvds_txdb_p,
output logic [1:0] lvds_txdb_n, //数据
// output logic lvds_txclk_p,
// output logic lvds_txclk_n, //时钟
//LVDS接收接口
input logic [1:0] lvds_rxdb_p,
input logic [1:0] lvds_rxdb_n //数据
// input logic lvds_rxclk_p,
// input logic lvds_rxclk_n //时钟
);
//led 输出
assign led = 8'hFF;
wire tx_1 = '0;
OBUFDS io_lvds_out(
.O( lvds_txdb_p[1] ),
.OB( lvds_txdb_n[1] ),
.I( tx_1 ) );
localparam DATA_CHECK = 8'hD0; //8'b1101_0000
/***************************************************************
* 1,时钟
***************************************************************/
wire sys_rst;
wire clk_20M_OUT,clk_160M_OUT,clk_200M_OUT;
clk_pll20M instance_name
(
// Clock out ports
.clk_20M_OUT(clk_20M_OUT), // output clk_20M_OUT
.clk_160M_OUT(clk_160M_OUT), // output clk_160M_OUT
.clk_200M_OUT(clk_200M_OUT), // output clk_200M_OUT
// Status and control signals
.reset( !ext_rst_n ), // input reset
.locked( !sys_rst ), // output locked
// Clock in ports
.clk_50M_IN( sys_clk_i )); // input clk_50M_IN
/***************************************************************
* 2,发送
***************************************************************/
//数据产生
logic [7:0] data_out;
data_gen_module #(
.DATA_WIDTH(8)
)Udata_gen (
.clk( clk_20M_OUT ),
.en( !sys_rst ),
.dout( data_out )
);
logic check;
wire [7:0] data_tx = check ? DATA_CHECK:data_out;
wire tx_data_out;
OSERDESE2 #(
.DATA_WIDTH (8), // SERDES word width
.TRISTATE_WIDTH (1),
.DATA_RATE_OQ ("SDR"), // , DDR
.DATA_RATE_TQ ("SDR"), // , DDR
.SERDES_MODE ("MASTER")) // , MASTER, SLAVE
oserdes_m (
.OQ (tx_data_out),
.OCE ( 1'b1 ),
.CLK ( clk_160M_OUT ),
.RST ( sys_rst ),
.CLKDIV ( clk_20M_OUT ),
.D8 (data_tx[7]),
.D7 (data_tx[6]),
.D6 (data_tx[5]),
.D5 (data_tx[4]),
.D4 (data_tx[3]),
.D3 (data_tx[2]),
.D2 (data_tx[1]),
.D1 (data_tx[0]),
.TQ (),
.T1 (1'b0),
.T2 (1'b0),
.T3 (1'b0),
.T4 (1'b0),
.TCE (1'b1),
.TBYTEIN (1'b0),
.TBYTEOUT (),
.OFB (),
.TFB (),
.SHIFTOUT1 (),
.SHIFTOUT2 (),
.SHIFTIN1 (1'b0),
.SHIFTIN2 (1'b0)) ;
OBUFDS io_data_out(
.O( lvds_txdb_p[0] ),
.OB( lvds_txdb_n[0] ),
.I( tx_data_out ) );
/***************************************************************
* 3,接收
***************************************************************/
wire delay_ready;
IDELAYCTRL icontrol (
// Instantiate input delay control block
.REFCLK ( clk_200M_OUT ),
.RST ( sys_rst ),
.RDY (delay_ready) );
wire bslip;
wire [7:0] bslip_din;
lvds_bitslip#(
.PATTERN_A(8'hD0)
)Ubitslip(
.clk_d( clk_20M_OUT ), // lvds 数据时钟20M
.rst_n( 1'b1 ),
.din( bslip_din),
.bitslip( bslip )
);
wire data_in;
IBUFDS #(
.DIFF_TERM("TRUE"), // Differential Termination
.IBUF_LOW_PWR("FALSE"), // Low power="TRUE", Highest performance="FALSE"
.IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFDS_inst (
.O( data_in ), // Buffer output
.I( lvds_rxdb_p[0] ), // Diff_p buffer input (connect directly to top-level port)
.IB( lvds_rxdb_n[0] ) // Diff_n buffer input (connect directly to top-level port)
);
wire data_ind;
logic [4:0] delay2_val;
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // 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, 290.0-310.0).
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
)
idelay_d(
.CNTVALUEOUT( ), // 5-bit output: Counter value output
.DATAOUT( data_ind ), // 1-bit output: Delayed data output
.C( clk_20M_OUT ), // 1-bit input: Clock input
.CE( 1'b0 ), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL( ), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN( delay2_val ), // 5-bit input: Counter value input
.DATAIN( 1'b0 ), // 1-bit input: Internal delay data input
.IDATAIN( data_in), // 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
);
logic [7:0] data_rx;
ISERDESE2 #(
.DATA_WIDTH (8),
.DATA_RATE ("SDR"),
// .SERDES_MODE ("MASTER"),
.IOBDELAY ("IFD"),
.INTERFACE_TYPE ("NETWORKING"))
iserdes_rx (
.O ( ), // 1-bit output: Combinatorial output
// Q1 - Q8: 1-bit (each) output: Registered data outputs
.Q1(data_rx[7]),
.Q2(data_rx[6]),
.Q3(data_rx[5]),
.Q4(data_rx[4]),
.Q5(data_rx[3]),
.Q6(data_rx[2]),
.Q7(data_rx[1]),
.Q8(data_rx[0]),
// SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
.SHIFTOUT1( ),
.SHIFTOUT2( ),
.BITSLIP(bslip),
// CE1, CE2: 1-bit (each) input: Data register clock enable inputs
.CE1( 1'b1 ),
.CE2( 1'b1 ),
.CLKDIVP( 1'b0 ), // 1-bit input: TBD
// Clocks: 1-bit (each) input: ISERDESE2 clock input ports
.CLK( clk_160M_OUT ), // 1-bit input: High-speed clock
.CLKB(~clk_160M_OUT), // 1-bit input: High-speed secondary clock
.CLKDIV( clk_20M_OUT ), // 1-bit input: Divided clock
.OCLK( 1'b0 ), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
// Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
.DYNCLKDIVSEL( 1'b0 ), // 1-bit input: Dynamic CLKDIV inversion
.DYNCLKSEL( 1'b0 ), // 1-bit input: Dynamic CLK/CLKB inversion
// Input Data: 1-bit (each) input: ISERDESE2 data input ports
.D( 1'b0 ), // 1-bit input: Data input
.DDLY( data_ind ), // 1-bit input: Serial data from IDELAYE2
.OCLKB( 1'b0 ), // 1-bit input: High speed negative edge output clock
.RST( 1'b0 ), // 1-bit input: Active high asynchronous reset
// SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
.SHIFTIN1( 1'b0 ),
.SHIFTIN2( 1'b0 )
);
assign bslip_din = data_rx;
/***************************************************************
* 4,监测
***************************************************************/
vio_1 Uvio_1 (
.clk( clk_20M_OUT ), // input wire clk
.probe_out0( {delay2_val} ) // output wire [9 : 0] probe_out0
);
ila_0 Uila_0 (
.clk(clk_160M_OUT), // input wire clk
.probe0( data_tx ), // input wire [15:0] probe0
.probe1( data_rx ), // input wire [15:0] probe1
.probe2(bslip) // input wire [1:0] probe2
);
vio_0 Uvio_0 (
.clk( clk_20M_OUT ), // input wire clk
.probe_in0( check ), // input wire [0 : 0] probe_in0
.probe_out0( check ) // output wire [0 : 0] probe_out0
);
endmodule