在异步通信中数据位的提取至关重要,如果能够准确的把数据位提取出来,在后面的字同步,帧同步以及数据包同步都会迎刃而解。如果熟悉计算机异步串行口通信的原理,我们就知道要想准确的接受串行口的数据帧(基本数据帧如图1),首先要准确识别start位,这就对start位准确采样提出要求。关于UART的详细内容请参照本教材的相关章节。

图1 UART 基本数据帧
在对异步串行数据采样中,由于采用本地时钟,因此对接受的串行数据流是异步采样,对于异步采样及同步处理可以按照如下步骤进行。
- 首先要时钟同步化处理,消除亚稳态的影响,
- 提取串行数据流中的边沿脉冲(上升沿,下降沿,双边沿),
- 数据采样定位,
- 同步数据为输出。
在上几节内容中介绍了时钟同步化原理及处理办法,以及串行数据流边沿提取的方法,本节内容着重介绍数据采样定位以及数据位同步输出。
1.采样定位原理
采样定位的原理,如图2所示,利用本地时钟获取数据流的边沿后,通过延迟将对数据流(bit流)中的某个bit进行中心定位并采样。由于延迟的原因,因此采样对应的原数据也要对应的延迟。在高速串行通信中最理想的就是能做到对每个数据位(bit)进行相位矫正,但由于原始数据传输时不可能每个bit都含有时钟信息,因此在对没有边沿变化的数据位采样时,按照过采样时钟的倍数进行延迟。如图2中成功得到上升沿后,延迟3个时钟对RX_rrr进行采样,但相邻的下一个bit的采样(采样点2)就只能依赖本地时钟的计数器实现,如4倍过采样就需要延迟4个过采样时钟进行采样。

图2 4倍过采样时序图
图2中 RX为原始接收数据,RX_r,RX_rr,RX_rrr分别经过过采样时钟锁存的三个信号,双边沿脉冲为RX_r与RX_rr异或产生。采样点分布在RX_rrr上。图2中的时序图显示的各个信号之间的关系可以由如下Verilog代码实现。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
module recv_bit ( input rst, input clk_400M , //400Hz input rx, output reg rx_bit, output reg rx_bit_vld, output reg rx_r, //r---register output reg rx_rr, //rr--- rx_r registered output reg rx_dg //dg----double (dual) edge, 上升沿或下降沿 ); ////=========rx_r^rx_rr==1,dual edge wire rx_out; reg rx_rrr; reg [ 1: 0 ] sample_count = 0; always@( posedge clk_400M or posedge rst ) if ( rst ) begin rx_r <= 0; rx_rr <= 0; rx_rrr <= 0; rx_dg <= 0; end else begin rx_r <= rx_out; rx_rr <= rx_r; rx_rrr <= rx_rr; rx_dg <= rx_r ^ rx_rr; //dual edge end always@( posedge clk_400M or posedge rst ) if ( rst ) begin rx_bit_vld <= 0; rx_bit <= 0; sample_count <= 0; end else begin rx_bit_vld <= 0; if ( sample_count == 2 ) //0,1,2,3,0,1,2,3... begin rx_bit <= rx_rrr; // rx_bit_vld <= 1'b1; end if ( rx_dg ) // 2 3 0 0 sample_count <= 0; else sample_count <= sample_count + 1'b1; end IO_RX IO_RX_inst ( .rx_in ( rx ), .rx_out ( rx_out ) ); endmodule |
仿真程序:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
`timescale 10 ps / 1 ps module tb_recv_bit ( ); parameter PERIOD_ORG = 1000 ; parameter PERIOD_OVER = 250; reg org_clk = 0; reg over_sample_clk = 0; always # ( PERIOD_ORG / 2 ) org_clk = ~org_clk; always # ( PERIOD_OVER / 2 ) over_sample_clk = ~over_sample_clk; wire rx_bit; wire rx_bit_vld; wire rx_dg; reg rst; reg rx; initial begin rst = 1; rx = 0; #1000 rst = 0; #1000 rx = 0; #2000 rx = 1; #4000 rx = 0; #8000 rx = 1; #8000 rx = 0; #8000 rx = 1; #1000 rx = 0; #4000 rx = 1; #2000 $stop; end recv_bit recv_bit_inst ( .rst ( rst ), .clk_400M ( over_sample_clk ), .rx ( rx ), .rx_bit ( rx_bit ), .rx_bit_vld ( rx_bit_vld ), .rx_r (), .rx_rr (), .rx_dg ( rx_dg ) ); endmodule |
仿真波形:

图3
2. 采样相位校准
从图3的仿真波形可以看出,在采样点S1之前由于没有边沿矫正,采样完全按照本地过采样时钟进行,因此S1采样点距离rx_rrr的边沿比较近,而且这个距离是随机的,取决于本地时钟稳定的时刻,以及远程时钟与本地时钟频率的差异。S6是第二个边沿的校准采样点,由于收发时钟频率相同,因此经过S1校正后,后面都同步跟随,因此S6点实际上没有校准。以下情况会发生校准情况。
(1) 收发时钟频率不同
虽然目前无论晶振还是有源震荡器的精度都比较高(如 50ppm),但收发双方的时钟频率不可能完全相等,因此随着时间的累积,在捕获边沿后必然会发生调整。
(2)由于直流不平衡,PCB布线不等长等诸多因素眼图没有完全张开,使数据流中边沿的位置发生偏移,此时会出现采样点的调整。
不管是什么原因发生了边沿调整,都会将采样点调整到做合适的位置采样,而且采样点调整又是自动实现的,因此称为自适应位同步信号提取。
可以改变仿真程序测试采样点的调整过程,
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
`timescale 10 ps / 1 ps module tb_recv_bit ( ); parameter PERIOD_ORG = 1000 ; parameter PERIOD_OVER = 250; reg org_clk = 0; reg over_sample_clk = 0; always # ( PERIOD_ORG / 2 ) org_clk = ~org_clk; always # ( PERIOD_OVER / 2 ) over_sample_clk = ~over_sample_clk; wire rx_bit; wire rx_bit_vld; wire rx_dg; reg rst; reg rx; initial begin rst = 1; rx = 0; #1000 rst = 0; #1000 rx = 0; #2000 rx = 1; #3800 //缩短2ns, rx = 0; #8200 rx = 1; #8000 rx = 0; #8000 rx = 1; #1000 rx = 0; #4000 rx = 1; #2000 $stop; end recv_bit recv_bit_inst ( .rst ( rst ), .clk_400M ( over_sample_clk ), .rx ( rx ), .rx_bit ( rx_bit ), .rx_bit_vld ( rx_bit_vld ), .rx_r (), .rx_rr (), .rx_dg ( rx_dg ) ); endmodule |

图4
图4中可以看出有两处调整,一处是在初始化阶段rx输入都是0,一直没有边沿,因此在第一个边沿处发生调整,可以看到正常sample_count的计数都是0,1,2,3,0而在调整的地方变成0,1,2,0,因此直接影响下一次的采样间隔。
3. 位采样输出
由于使用过采样的方法,每个位的输出宽度是过采样时钟的过采样倍数。如4倍过采样的位输出宽度基本上为4个时钟周期, 同时伴随着的有rx_bit_vld信号指示采样时刻,该信号的宽度为一个时钟周期,如图4所示,实现代码如下,
rx_bit_vld<=0;
if(sample_count==2) //0,1,2,3,0,1,2,3…
begin
rx_bit<=rx_rrr; //
rx_bit_vld<=1’b1;
end
关于收发时钟频率差异的处理,将在介绍帧同步的文章中详细探讨。