FPGA并串转换的实现

介绍

随着电子行业技术的发展,特别是在传输接口的发展上,IEEE1284被 USB 接口取代,PATA被 SATA 取代,PCI被 PCI-Express 所取代,无一不证明了传统并行接口的速度已经达到一个瓶颈了,取而代之的是速度更快的串行接口,于是原本用于光纤通信的SerDes 技术成为了为高速串行接口的主流。串行接口主要应用了差分信号传输技术,具有功耗低、抗干扰强,速度快的特点,理论上串行接口的最高传输速率可达到10Gbps 以上。因此,串并/并串转换在FPGA设计中具有重要意义。

方法一:Xilinx原语实现

Xlinx的原语OSERDESE2是一种专用的并-串转换器,每个OSERDESE2模块都包括一个专用串行化程序用于数据和3状态控制。数据和3状态序列化程序都可以工作在SDR和DDR模式。数据串行化的位宽可以达到8:1(如果使用原语模块级联,则可以到10:1和14:1)。3状态序列化最高可达14:1,有一个专用的DDR3模式可用于支持高速内存应用程序。
下图便是OSERDESE2的框图
在这里插入图片描述
其各个端口的含义如下表所示
在这里插入图片描述
在本博客的实验中,我们不关心三态控制模块,因此,用到的信号为CLK,CLKDIV,分别作为串行输出和并行输入的时钟,D1-D8为并行的数据输入端口,OQ为串行的数据输出端口,RST为复位信号。
例化时一些可配置的属性如下所示:
在这里插入图片描述
当DATA_RATE_OQ属性为DDR时,串行数据在每个时钟周期(串行数据的时钟,即快时钟)的跳变沿都会更新,当值为SDR时,仅在上升沿更新,在不同的属性配置下,原语支持的并行数据位宽也不同,如下图所示:
在这里插入图片描述
DATA_WIDTH为并串转换时并行数据的位宽。在不同的DATA_RATE_OQ和DATA_WIDTH下,串行数据输出的延迟也略有不同,如下表所示:
在这里插入图片描述
例如在进行8位并行数据转串行时,其时序应如下图所示
在这里插入图片描述
可以看到,并行数据被慢时钟的上升沿寄存后,经过4个快时钟周期,第一个串行数据开始输出,与表中的延迟一致。
下面是8位并行转串行的代码:
设计文件:

//------------------------------------------------------------------------
//--OSERDESE2测试模块
//------------------------------------------------------------------------
 
//------------<模块及端口声明>--------------------------------------------
module serializer(
    input			clk_ser		,			//串行输出时钟,50M*4=200M
    input			clk_per		,			//并行输入时钟,50M
    input			rst_n		,			//复位信号,低电平有效
    input	[7:0]  	par_data	,			//并行输入数据
		
    output  	    ser_data        		//串行输出数据
);
 
//------------<例化原语>---------------------------------------------------
OSERDESE2 #(
  .DATA_RATE_OQ		("DDR")		,   		// DDR, SDR
  .DATA_RATE_TQ		("SDR")		,   		// DDR, BUF, SDR
  .DATA_WIDTH		(8)			,   		// Parallel data width (2-8,10,14)
  .INIT_OQ			(1'b0)		,   		// Initial value of OQ output (1'b0,1'b1)
  .INIT_TQ			(1'b0)		,   		// Initial value of TQ output (1'b0,1'b1)
  .SERDES_MODE		("MASTER")	, 			// MASTER, SLAVE
  .SRVAL_OQ			(1'b0)		,			// OQ output value when SR is used (1'b0,1'b1)
  .SRVAL_TQ			(1'b0)		,			// TQ output value when SR is used (1'b0,1'b1)
  .TBYTE_CTL		("FALSE")	,			// Enable tristate byte operation (FALSE, TRUE)
  .TBYTE_SRC		("FALSE")	,			// Tristate byte source (FALSE, TRUE)
  .TRISTATE_WIDTH	(1)      				// 3-state converter width (1,4)
)
OSERDESE2_inst (
  .OFB				()					,	// 1-bit output: Feedback path for data
  .OQ				(ser_data)			,	// 1-bit output: Data path output
  .SHIFTOUT1		()					,
  .SHIFTOUT2		()					,
  .TBYTEOUT			()					,   // 1-bit output: Byte group tristate
  .TFB				()					,	// 1-bit output: 3-state control
  .TQ				()					,	// 1-bit output: 3-state control
  .CLK				(clk_ser)			,	// 1-bit input: High speed clock
  .CLKDIV			(clk_per)			,	// 1-bit input: Divided clock
  .D1				(par_data[0])		,
  .D2				(par_data[1])		,
  .D3				(par_data[2])		,
  .D4				(par_data[3])		,
  .D5				(par_data[4])		,
  .D6				(par_data[5])		,
  .D7				(par_data[6])		,
  .D8				(par_data[7])		,
  .OCE				(1'b1)				,	// 1-bit input: Output data clock enable
  .RST				(~rst_n)			,	// 1-bit input: Reset
  .SHIFTIN1			()					,
  .SHIFTIN2			()					,
  .T1				(1'b0)				,
  .T2				(1'b0)				,
  .T3				(1'b0)				,
  .T4				(1'b0)				,
  .TBYTEIN			(1'b0)				,	// 1-bit input: Byte group tristate
  .TCE				(1'b0)              	// 1-bit input: 3-state clock enable
);
 
endmodule

测试文件

//------------------------------------------------
//--OSERDESE2原语仿真
//------------------------------------------------
 
`timescale 1ns / 1ps			//时间单位/精度
 
//------------<模块及端口声明>----------------------------------------
module tb_serializer();
 
reg			clk_per		;
reg			clk_ser		;
reg			rst_n		;
reg	[7:0]	par_data	;
wire		ser_data	;
 
//------------<设置初始测试条件>----------------------------------------
initial begin
    clk_per <= 1'b0;
    clk_ser <=  1'b1;
    rst_n <= 1'b0;
	par_data <= 8'd0;
    #180
    rst_n <= 1'b1;
end
//------------<设置时钟>----------------------------------------------
always #10	clk_per = ~clk_per;
always #2.5	clk_ser = ~clk_ser;
 
always #20	par_data <= $random % 256;		//每20ns随机生成一个8位数据用于并行输入
 
//------------<例化被测试模块>---------------------------------------- 
serializer	serializer_inst(
    .clk_per	(clk_per)	,
    .clk_ser	(clk_ser)	,
    .rst_n		(rst_n)		,
    .par_data	(par_data)	,
    .ser_data	(ser_data)
);
 
endmodule

仿真波形如下图所示
在这里插入图片描述
进阶:OSERDESE2原语还支持例化两次原语级联,以便实现10位、14位位宽的串行化转换。下图是10位位宽的级联框图,其中一个设置位MASTER,另一个设置为SLAVE,通过SHIFTIN与SHIFTOUT连接。
在这里插入图片描述
在进行级联时,一个原语为Master,另一个为Slave,并且最终的串行数据由Master输出,Master和Slave之间通过SHIFTIN和SHIFTOUT连接,数据的高位输入至Slave,并且是从D3而不是D1开始。
相应的代码如下
设计文件:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// Website      : 
// Module Name  : par2ser.v
// Create Time  : 2020-02-23 14:20:43
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************


module par2ser(
    input                   clk_1x          ,
    input                   clk_5x          ,
    input                   rst_n           ,
    input           [ 9:0]  par_data        ,

    output  wire            ser_data_p      ,
    output  wire            ser_data_n  
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
wire                        shiftout1       ;
wire                        shiftout2       ;
wire                        ser_data        ;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/

OBUFDS #(
    .IOSTANDARD                 ("DEFAULT"              ), // Specify the output I/O standard
    .SLEW                       ("SLOW"                 )           // Specify the output slew rate
) OBUFDS_inst (
    .O                          (ser_data_p             ),     // Diff_p output (connect directly to top-level port)
    .OB                         (ser_data_n             ),   // Diff_n output (connect directly to top-level port)
    .I                          (ser_data               )      // Buffer input
   );

 OSERDESE2 #(
    .DATA_RATE_OQ               ("DDR"                  ),   // DDR, SDR
    .DATA_RATE_TQ               ("DDR"                  ),   // DDR, BUF, SDR
    .DATA_WIDTH                 (10                     ),         // Parallel data width (2-8,10,14)
    .INIT_OQ                    (1'b0                   ),         // Initial value of OQ output (1'b0,1'b1)
    .INIT_TQ                    (1'b0                   ),         // Initial value of TQ output (1'b0,1'b1)
    .SERDES_MODE                ("MASTER"               ), // MASTER, SLAVE
    .SRVAL_OQ                   (1'b0                   ),        // OQ output value when SR is used (1'b0,1'b1)
    .SRVAL_TQ                   (1'b0                   ),        // TQ output value when SR is used (1'b0,1'b1)
    .TBYTE_CTL                  ("FALSE"                ),    // Enable tristate byte operation (FALSE, TRUE)
    .TBYTE_SRC                  ("FALSE"                ),    // Tristate byte source (FALSE, TRUE)
    .TRISTATE_WIDTH             (1                      )      // 3-state converter width (1,4)
   ) OSERDESE2_inst_master (
      .OFB                      (                       ),             // 1-bit output: Feedback path for data
      .OQ                       (ser_data               ),               // 1-bit output: Data path output
      // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
      .SHIFTOUT1                (                       ),
      .SHIFTOUT2                (                       ),
      .TBYTEOUT                 (                       ),   // 1-bit output: Byte group tristate
      .TFB                      (                       ),             // 1-bit output: 3-state control
      .TQ                       (                       ),               // 1-bit output: 3-state control
      .CLK                      (clk_5x                 ),             // 1-bit input: High speed clock
      .CLKDIV                   (clk_1x                 ),       // 1-bit input: Divided clock
      // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
      .D1                       (par_data[0]            ),
      .D2                       (par_data[1]            ),
      .D3                       (par_data[2]            ),
      .D4                       (par_data[3]            ),
      .D5                       (par_data[4]            ),
      .D6                       (par_data[5]            ),
      .D7                       (par_data[6]            ),
      .D8                       (par_data[7]            ),
      .OCE                      (1'b1                   ),             // 1-bit input: Output data clock enable
      .RST                      (~rst_n                 ),             // 1-bit input: Reset
      // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
      .SHIFTIN1                 (shiftout1              ),
      .SHIFTIN2                 (shiftout2              ),
      // T1 - T4: 1-bit (each) input: Parallel 3-state inputs
      .T1                       (1'b0                   ),
      .T2                       (1'b0                   ),
      .T3                       (1'b0                   ),
      .T4                       (1'b0                   ),
      .TBYTEIN                  (1'b0                   ),     // 1-bit input: Byte group tristate
      .TCE                      (1'b0                   )              // 1-bit input: 3-state clock enable
   );

   // End of OSERDESE2_inst instantiation
 OSERDESE2 #(
    .DATA_RATE_OQ               ("DDR"                  ),   // DDR, SDR
    .DATA_RATE_TQ               ("DDR"                  ),   // DDR, BUF, SDR
    .DATA_WIDTH                 (10                     ),         // Parallel data width (2-8,10,14)
    .INIT_OQ                    (1'b0                   ),         // Initial value of OQ output (1'b0,1'b1)
    .INIT_TQ                    (1'b0                   ),         // Initial value of TQ output (1'b0,1'b1)
    .SERDES_MODE                ("SLAVE"               ), // MASTER, SLAVE
    .SRVAL_OQ                   (1'b0                   ),        // OQ output value when SR is used (1'b0,1'b1)
    .SRVAL_TQ                   (1'b0                   ),        // TQ output value when SR is used (1'b0,1'b1)
    .TBYTE_CTL                  ("FALSE"                ),    // Enable tristate byte operation (FALSE, TRUE)
    .TBYTE_SRC                  ("FALSE"                ),    // Tristate byte source (FALSE, TRUE)
    .TRISTATE_WIDTH             (1                      )      // 3-state converter width (1,4)
   ) OSERDESE2_inst_slave (
      .OFB                      (                       ),             // 1-bit output: Feedback path for data
      .OQ                       (                       ),               // 1-bit output: Data path output
      // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
      .SHIFTOUT1                (shiftout1              ),
      .SHIFTOUT2                (shiftout2              ),
      .TBYTEOUT                 (                       ),   // 1-bit output: Byte group tristate
      .TFB                      (                       ),             // 1-bit output: 3-state control
      .TQ                       (                       ),               // 1-bit output: 3-state control
      .CLK                      (clk_5x                 ),             // 1-bit input: High speed clock
      .CLKDIV                   (clk_1x                 ),       // 1-bit input: Divided clock
      // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
      .D1                       (                       ),
      .D2                       (                       ),
      .D3                       (par_data[8]            ),
      .D4                       (par_data[9]            ),
      .D5                       (                       ),
      .D6                       (                       ),
      .D7                       (                       ),
      .D8                       (                       ),
      .OCE                      (1'b1                   ),             // 1-bit input: Output data clock enable
      .RST                      (~rst_n                 ),             // 1-bit input: Reset
      // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
      .SHIFTIN1                 (                       ),
      .SHIFTIN2                 (                       ),
      // T1 - T4: 1-bit (each) input: Parallel 3-state inputs
      .T1                       (1'b0                   ),
      .T2                       (1'b0                   ),
      .T3                       (1'b0                   ),
      .T4                       (1'b0                   ),
      .TBYTEIN                  (1'b0                   ),     // 1-bit input: Byte group tristate
      .TCE                      (1'b0                   )              // 1-bit input: 3-state clock enable
   );                    




endmodule


测试文件:

`timescale 1ns / 1ps
`define     CLOCK        20
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/02/23 14:23:39
// Design Name: 
// Module Name: tb_par2ser
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_par2ser10_1;
reg                        clk_1x          ;
reg                        clk_5x          ;
reg                        rst_n           ;
reg                [ 9:0]  par_data        ;
wire                       ser_data_p      ;
wire                       ser_data_n      ;

initial begin
    clk_1x          =       1'b0;
    clk_5x          =       1'b0;
    rst_n           <=      1'b0;
    #(10*`CLOCK)
    rst_n           <=      1'b1;
end
always #(`CLOCK/2)      clk_1x          =           ~clk_1x;
always #(`CLOCK/8)      clk_5x          =           ~clk_5x;

always @(posedge clk_1x or negedge rst_n)
    if(rst_n == 1'b0)
        par_data            <=          10'b11_1111_1111;
    else 
        par_data            <=          $random % 1024; 



par2ser par2ser_inst(
    .clk_1x                 (clk_1x                 ),
    .clk_5x                 (clk_5x                 ),
    .rst_n                  (rst_n                  ),
    .par_data               (par_data               ),

    .ser_data_p             (ser_data_p             ),
    .ser_data_n             (ser_data_n             )
);
endmodule


仿真波形如下图所示
在这里插入图片描述
奇怪的是,这里的输出延迟为4个clk,和表中给出的5clk不一致!

方法二:通过SelectIO IP核实现

点击IP Catalog,输入SelectIO,进行如下配置
第一个界面:
在这里插入图片描述
第二个界面:
在这里插入图片描述
其余保持默认。
代码:

`timescale 1ns / 1ps
`define     CLOCK        20
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/02/23 15:39:03
// Design Name: 
// Module Name: tb_select_io
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_select_io;
reg                        clk_1x          ;
reg                        clk_5x          ;
reg                        rst_n           ;
reg                [ 9:0]  par_data        ;
wire                       ser_data_p      ;
wire                       ser_data_n      ;
initial begin
    clk_1x          =       1'b0;
    clk_5x          =       1'b0;
    rst_n           <=      1'b0;
    #(10*`CLOCK)
    rst_n           <=      1'b1;
end
always #(`CLOCK/2)      clk_1x          =           ~clk_1x;
always #(`CLOCK/8)      clk_5x          =           ~clk_5x;
always @(posedge clk_1x or negedge rst_n)
    if(rst_n == 1'b0)
        par_data            <=          0;
    else 
        par_data            <=          $random % 1024; 

selectio_wiz_0 selectio_wiz_0_inst
 (
   .data_out_from_device            (par_data                       ), // input [9:0] data_out_from_device
   .data_out_to_pins_p              (ser_data_p                     ), // output [0:0] data_out_to_pins_p
   .data_out_to_pins_n              (ser_data_n                     ), // output [0:0] data_out_to_pins_n
   .clk_in                          (clk_5x                         ), // input clk_in                            
   .clk_div_in                      (clk_1x                         ), // input clk_div_in                        
   .io_reset                        (~rst_n                         ) // input io_reset
); 

endmodule


仿真波形如下
在这里插入图片描述

参考文献

https://blog.csdn.net/wuzhikaidetb/article/details/119767367
https://www.freesion.com/article/3737576142/

  • 6
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA硅农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值