[参考文献]
[1] https://blog.csdn.net/yijingjijng/article/details/48024059
前言
CDR全称为Clock and Data Recovery,即时钟数据恢复。顾名思义,CDR就是接收端根据接收到的数据信号恢复出时钟,以便于接收端对数据信号进行恢复和处理。
那为什么需要CDR呢?CDR一般应用于串行数据的恢复,那为什么不像SPI一样多传输一条数据线呢?我们知道SPI的最大传输速度也就几Mbps,这对图像等实时传输是不可能的。而如果速度传输加快,信道对传输信号的影响变大,会导致时钟和数据信号产生不同程度的影响,导致误码。因此后面演变出了SerDes这类高速传输方式,其采用LVDS差分信号进行数据传输,同时省去了时钟线,接收端再根据接收到的差分数据信号进行CDR处理,恢复出时钟和数据。
本文是基于FPGA全数字电路实现的,重在实现的逻辑,没有物理层的优化,也就意味着无法对太高速的数据进行恢复,仅供参考。
一、CDR原理
目前基于FPGA的全数字CDR设计基本上都是采取了过采样的方式实现,具体可以使用同频多相时钟采样和数据延迟链采样两种方式实现。核心都是采用Nxf的高速时钟,对信号进行N倍的过采样,通过对采样后数据进行判断分析,得到数据跳变沿的位置,再用最佳的采样点进行恢复数据。但是对于A7系列FPGA来说,PLL最大只能生成600MHz左右的时钟,因此对于高速信号直接使用Nxf的高频时钟采样是很困难的。
本文采用同频多相时钟采样的方式实现CDR,利用PLL产生0°和90°相位差的采样时钟,两时钟利用双沿采样,如此起到了4倍上采样的效果。最后通过一个判决器对四个采样点进行判决,得到信号跳变沿的位置,再选取最佳的采样点恢复出数据。
如下图所示,数据信号发生跳变时存在四种情况,跳变沿前后两个采样点采样得到的值不一样,如此便能通过四个采样数值得到跳变沿所在的位置,再选取合适的采样点进行数据的恢复,比如说情况1,信号的上升沿在第一个和第二个采样点之间,可选择相对稳定的第三个采样点作为数据恢复点,以此类推。
二、CDR实现电路
代码实现
module CDR(
input clk_0,
input clk_90,
input rst_n,
input ser_in,
output ser_clk,
output ser_out,
output [3:0] debug
);
reg data00,data01,data02,data03;
reg data10,data11,data12,data13;
reg data20,data21,data22,data23;
reg data30,data31,data32,data33;
reg data04,data14,data24,data34;
wire cdr_en ;
reg [3:0] pos_neg;
assign debug = {data34,data24,data14,data04};
assign ser_out = (pos_neg[0])?data23:
(pos_neg[1])?data33:
(pos_neg[2])?data03:
(pos_neg[3])?data13:0 ;
assign ser_clk = (pos_neg[0])?~clk_0 :
(pos_neg[1])?~clk_90:
(pos_neg[2])? clk_0 :
(pos_neg[3])? clk_90:0 ;
//Determine which position is the edge
always @(posedge clk_0 or negedge rst_n)begin
if(!rst_n) pos_neg <= 4'd0;
else if(!cdr_en)begin
pos_neg[0] <= !data04 & data14 & data24 & data34; //the edge of data is in the first position
pos_neg[1] <= !data04 & !data14 & data24 & data34; //
pos_neg[2] <= !data04 & !data14 & !data24 & data34; //
pos_neg[3] <= data04 & data14 & data24 & data34; //
end
else
pos_neg <= pos_neg;
end
assign cdr_en = (|pos_neg)?1'b1:1'b0;
always @(posedge clk_0 or negedge rst_n)begin
if(!rst_n)begin
data04 <= 1'b0;
data14 <= 1'b0;
data24 <= 1'b0;
data34 <= 1'b0;
end
else begin
data04 <= data03;
data14 <= data13;
data24 <= data23;
data34 <= data33;
end
end
always @(posedge clk_0 or negedge rst_n)begin
if(!rst_n) begin
data00 <= 1'b0; data01 <= 1'b0;
data02 <= 1'b0; data03 <= 1'b0;
end
else begin
data00 <= ser_in; data01 <= data00;
data02 <= data01; data03 <= data02;
end
end
always @(posedge clk_90 or negedge rst_n)begin
if(!rst_n) begin
data10 <= 1'b0; data11 <= 1'b0;
data12 <= 1'b0; data13 <= 1'b0;
end
else begin
data10 <= ser_in; data11 <= data10;
data12 <= data11; data13 <= data12;
end
end
always @(negedge clk_0 or negedge rst_n)begin
if(!rst_n) begin
data20 <= 1'b0; data21 <= 1'b0;
data22 <= 1'b0; data23 <= 1'b0;
end
else begin
data20 <= ser_in; data21 <= data20;
data22 <= data21; data23 <= data22;
end
end
always @(negedge clk_90 or negedge rst_n)begin
if(!rst_n) begin
data30 <= 1'b0; data31 <= 1'b0;
data32 <= 1'b0; data33 <= 1'b0;
end
else begin
data30 <= ser_in; data31 <= data30;
data32 <= data31; data33 <= data32;
end
end
endmodule
测试文件
module tb_cdr( );
reg clk;
reg rst_n;
reg ser_in;
wire ser_out;
wire clk_90;
wire ser_clk;
initial begin
clk = 0;ser_in = 0; rst_n = 1;
#100 rst_n = 0;
#10 rst_n = 1;
#1000
#11
repeat(100)begin
#10 ser_in = $random%2;
end
end
always #5 clk = ~clk;
assign #2.5 clk_90 = clk;
CDR CDR(
.clk_0 (clk ),
.clk_90 (clk_90 ),
.rst_n (rst_n ),
.ser_in (ser_in ),
.ser_clk (ser_clk),
.ser_out (ser_out)
);
endmodule
三、仿真波形
文章来源:https://www.toymoban.com/news/detail-767549.html
总结
本文基于FPGA全数字实现了CDR,实现结果有所局限,CDR的频率不能太高且不能自适应更正识别数据信号的相位,主要目的是实现时钟恢复的功能,仅供参考。后续将该CDR模块会应用于低速的serdes实现。文章来源地址https://www.toymoban.com/news/detail-767549.html
到了这里,关于基于FPGA的CDR时钟恢复设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!