概述
介绍
随着电子行业技术的发展,特别是在传输接口的发展上,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/
最后
以上就是开心皮带为你收集整理的FPGA并串转换的实现介绍方法一:Xilinx原语实现方法二:通过SelectIO IP核实现参考文献的全部内容,希望文章能够帮你解决FPGA并串转换的实现介绍方法一:Xilinx原语实现方法二:通过SelectIO IP核实现参考文献所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复