当使用FPGA进行ADC数据的处理时,由于目前一些ADC的工作频率已达到GHz,使得FPGA并不能直接处理这么高速的信号,这就需要对高速信号进行串并转换,实现数据的降速。
FPGA资源中,我们可以通过直接例化ISERDESE/OSERDESE资源来实现数据的串并转换和并串转换。
1、在vivado18.3 Language Templates中可以查找serdes资源的原语。
如上图所示,不同的FPGA系列,有不同的原语。这里使用的是Kintex UltraScale系列,所以我们选择ISERDESE3原语进行例化。
2、ISERDESE3模块的详细介绍参考Xilinx官方文档ug571。
3、本工程使用ISERDESE3进行1:4串并转换,传输的数据为data=32’b10010010101010001010100101011011。
4、serdes例化代码:
`timescale 1ns / 1ps
module serdes(
output wire [3:0] iserdes_q , // serdes的输出信号,并行数据
input wire clk , // 串行时钟,500M,DDR
input wire clkdiv , // 并行时钟,250M,SDR
input wire rst_n , // 复位信号,低有效
input wire iserdes_d // serdes的输入信号,串行数据
);
// ISERDESE3: Input SERial/DESerializer
// Kintex UltraScale
// Xilinx HDL Language Template, version 2018.3
ISERDESE3 #(
.DATA_WIDTH(4), // 1:4串并转换
.FIFO_ENABLE("FALSE"), // Enables the use of the FIFO
.FIFO_SYNC_MODE("FALSE"), // Always set to FALSE. TRUE is reserved for later use.
.IS_CLK_B_INVERTED(1'b1), // 设置为1时,会将CLK_B的输入信号进行反相,此时CLK_B和CLK应为同一驱动源
.IS_CLK_INVERTED(1'b0), // Optional inversion for CLK
.IS_RST_INVERTED(1'b1), // 设置为1时,会将RST的输入信号进行反相
.SIM_DEVICE("ULTRASCALE") // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,
// ULTRASCALE_PLUS_ES2)
)
ISERDESE3_inst (
.FIFO_EMPTY( ), // 1-bit output: FIFO empty flag
.INTERNAL_DIVCLK( ), // 1-bit output: Internally divided down clock used when FIFO is
// disabled (do not connect)
.Q(iserdes_q), // 4-bit registered output
.CLK(clk), // 1-bit input: High-speed clock
.CLKDIV(clkdiv), // 1-bit input: Divided Clock
.CLK_B(clk), // 1-bit input: Inversion of High-speed clock CLK
.D(iserdes_d), // 1-bit input: Serial Data Input
.FIFO_RD_CLK( ), // 1-bit input: FIFO read clock
.FIFO_RD_EN( ), // 1-bit input: Enables reading the FIFO when asserted
.RST(rst_n) // 1-bit input: Asynchronous Reset
);
endmodule
仿真激励文件代码
`timescale 1ns / 1ps
module serdes_tb(
);
reg clk ; // 串行时钟,500M,DDR
reg clkdiv ; // 并行时钟,250M,SDR
reg clk_data ; // 数据时钟,用于产生串行数据,使得clk的沿正好对准串行数据
reg rst_n ; // 复位信号,低有效
wire iserdes_d ; // serdes的输入信号,串行数据
wire [3:0] iserdes_q ; // serdes的输出信号,并行数据
reg [31:0] data ; // 预先设定的需要传输的数据
initial begin
clk = 1'b0 ;
clkdiv = 1'b0 ;
clk_data = 1'b0 ;
rst_n = 1'b0 ;
data = 32'b0 ;
#5 rst_n = 1'b1 ;
#199 data = 32'b10010010101010001010100101011011;
end
always #1 clk = ~clk ;
initial begin
#3 clkdiv = 1'b1;
forever begin
#2 clkdiv = ~clkdiv;
end
end
initial begin
#0.5 clk_data = 1'b1;
forever begin
#1 clk_data = ~clk_data;
end
end
assign iserdes_d = data[31];
always @(posedge clk_data or negedge clk_data) begin
data <= {data[30:0], 1'b0} ;
end
serdes serdes_inst(
.iserdes_q ( iserdes_q ),
.clk ( clk ),
.clkdiv ( clkdiv ),
.rst_n ( rst_n ),
.iserdes_d ( iserdes_d )
);
endmodule
仿真结果
值得注意的是,iserdese3输出的信号是先转换的数据在低位,后转换的数据在高位。如下图所示,由于没有注意这个问题,导致我一直以为仿真数据出错了。
5、如果需要进行串并1:8转换,只需要相应的修改DATA_WIDTH和输出数据的数据宽度即可。同理,oserdese3的使用相同,只不过是iserdese3的反过程,这里就不再赘述了。