查看原文
其他

加油站| 单比特信号跨时钟域问题详解(大疆FPGA逻辑岗A卷)

相量子 达尔闻说 2021-01-17

达尔闻加油站,充分利用你的碎片时间涨知识。

加油站系列是此前达尔闻求职系列的延续,秋招季以来该系列已经分享了众多笔试题解析,覆盖华为硬件逻辑岗、大华硬件岗、海康威视等。今后,达尔闻将继续给大家带来最新鲜的笔试题目解析,通过这种方式查漏补缺,检测水平,补充完善你的知识库。

本期加油站解析题目来源大疆硬件逻辑岗,共1道编程题,涉及知识点包含:单比特信号跨时钟域的问题。

大疆FPGA逻辑岗的题目由20道单选题(每题2分)、10道多选(每题2分)、5道填空题(每题3分)、5道问答题(每题5分含编程),共40道题目100分,答题时间为90分钟。从题量来看还是可以接受的,但做题的时候可就没那么容易了,经历过整个秋招FPGA逻辑岗/数字IC岗的朋友说这是做过最难的一套笔试题,想想还是蛮有挑战性的。
今天解析的题目是上一期预留的大疆FPGA逻辑岗A卷的编程题。题目很有代表性,在多家公司的笔试题、面试题中均有出现过,今天就将这种类型的题目一网打尽。下面请看题目与解析:

1、Signal_a是clka(300M)时钟域的一个单时钟脉冲信号,如何将其同步到时钟域clkb(100M)中,并产生出Signal_b同步脉冲信号。请用Verilog代码描述,并画出对应的时序波形图说明图。(大疆FPGA逻辑岗A卷)

解析:该题目是很典型的单比特信号跨时钟域的问题,如果大家能够get到这点就说明你对FPGA知识了解还是挺多的。对于没有get到这个点的同学们也不要担心,我们讲从最基本的信号跨时钟域会引起亚稳态的现象讲起。单比特信号做跨时钟域主要有两种方式,第一种为电平同步方式,第二种为脉冲同步方式,这两种方法主要解决的问题是不同的,下面是详细的讲解。

一、电平同步,主要解决单比特信号从慢速时钟域同步到快速时钟域的问题

以串口接收数据作为例子,如下图所示。

首先是三个输入信号用绿色标注,时钟、复位和单比特串行输入的数据rx信号。一般在FPGA的设计中,会对单比特串行输入的数据rx信号进行打了两拍的操作(如果不做该处理会偶尔出现接收到的数据出现错误的现象),也就是让rx信号先经过两级寄存器。理论上,应该按照串口的时序找到rx的下降沿开始接收起始位的数据,为什么先将rx信号做打两拍处理呢?那就要先从跨时钟域会导致“亚稳态”的问题上说起。

示波器大家一定用过,当使用示波器把一个矩形脉冲的上升沿或下降沿放大后,会发现其上升沿和下降沿并不是瞬间被拉高或者拉低的,而是有一个倾斜变化的过程,这在运放中被称为“压摆率”。如果系统时钟刚好采集到上升沿的中间附近位置(按照概率来讲,如果数据传输量足够大或传输速度足够快时一定会产生这种情况),即数据传输过程中不满足触发器的建立时间Tsu(指触发器的时钟信号上升沿到来以前,数据稳定不变的最小时间)和保持时间Th(指触发器的时钟信号上升沿到来以后,数据稳定不变的最小时间),此时触发器输出端rx_reg1在有效时钟沿之后比较长的一段时间处于不确定状态,在这段时间里rx_reg1端在0和1之间处于振荡状态,而不是等于串口输入的稳定的rx值。

上图所示为产生亚稳态的波形示意图,rx信号经过FPGA中的第一级寄存器后输出的rx_reg1信号在时钟上升沿Tco时间后会有Tmet(决断时间)的振荡时段,当第一个寄存器发生亚稳态后,经过Tmet的振荡稳定后,第二级寄存器就能采集到一个稳定的值。但由于振荡时间Tmet是受到很多因素影响的,所以Tmet时间有长有短,如下图所示。

当Tmet1时间长到大于一个采样周期后,那第二级寄存器就会采集到亚稳态,但是从第二级寄存器输出的信号就是稳定的了。当然会人会问到第二级寄存器的Tmet2的持续时间会不会继续长到大于一个采样周期?这种情况虽然会存在,但是其概率是极小的,寄存器本身就有减小Tmet时间让数据快速稳定的作用。

由于在上位机中波特率和rx是同步关系,而rx信号和FPGA的系统时钟sys_clk是异步的关系,我们此时要做的是将慢速时钟域系统中的数据rx同步到快速时钟域系统中,所使用的方法叫电平同步法,俗称“打两拍法”。所以rx信号进入FPGA后会首先经过一级寄存器,出现亚稳态现象,导致rx_reg1信号的状态不确定是0还是1,就会使受其影响的将其他信号做出不同的判断,有的判断到“0”有的判断到“1”,有的也进入了亚稳态,产生连锁反应,导致逻辑混乱。为了避免这种情况,数据进来后首先进行打一拍的处理,打一拍后产生rx_reg1信号。 rx_reg1可能还存在低概率的亚稳态问题,为了进一步降低出现亚稳态的概率,我们将从rx_reg1信号再打一拍后产生rx_reg2信号,使之能够较大概率保证 rx_reg2信号是0或者1中的一种确定情况,这样rx_reg2所影响的后级信号就都是相对稳定的了,就不会对后级电路造成过大影响。

打两拍后虽然能让数据稳定到0或者1,但是究竟是0还是1却是随机的,与输入没有必然的关系。 

注:单比特信号从慢速时钟域同步到快速时钟域需要使用打两拍的方式消除亚稳态,第一级寄存器产生亚稳态并经过自身后可以稳定输出的概率为70%~80%左右,第二级寄存器可以稳定输出的概率为99%左右,再后面改善就不明显了,所以数据进来后一般选择打两拍即可。

亚稳态振荡时间Tmet关系到后级寄存器的采集稳定问题,Tmet影响因素包括:器件的生产工艺、温度、环境以及寄存器采集到亚稳态里稳定态的时刻等。甚至某些特定条件,如干扰、辐射等都会造成Tmet增长。

二、脉冲同步,主要解决单比特信号从快速时钟域同步到慢速时钟域的问题

对于亚稳态的问题同样也会在将单比特信号从快速时钟域同步到慢速时钟域时出现,本期要解析的笔试题就是这种情况,但我们却不能仅仅用“打两拍法”,这是为什么呢?如下图所示,慢速时钟域的时钟clkb根本就采集不到快速时钟域clka下的Signal_a脉冲信号,会漏掉数据,所以我们需要先解决这个问题,再做单比特数据的跨时钟域工作。

就要想办法转换思路,如果能够让同步于快速时钟域clka下的脉冲信号Signal_a变长到可以让慢速时钟域clkb检测到这个问题,就可以完美解决了。所以先将快速时钟域clka下的脉冲信号Signal_a,在快速时钟域clka的作用下,变为沿信号,产生一个名为src_state的中间变量来作为脉冲信号Signal_a变成的沿信号。如下图所示,每当快速时钟域clka检测到Signal_a脉冲信号为高时,让src_state信号取反,使得Signal_a的第一个脉冲变为src_state信号的上升沿,Signal_a的第二个脉变为src_state信号的下降沿,后面如果Signal_a信号还有脉冲依然是变为src_state信号的上升沿和下降沿。

巧妙的利用将“脉冲信号”转化为“沿信号”的思想就可以使慢速时钟域的时钟clkb检测到同步于快速时钟域clka且将脉冲信号Signal_a转化为沿信号的src_state,相当于是把同步于快速时钟域clka的脉冲信号Signal_a进行了展宽处理,这样我们就把快速时钟域clka的脉冲信号Signal_a通过src_state信号“沿”的形式在慢速时钟域clkb中得到了保留。如下图所示,src_state信号是同步与快速时钟域clka的信号,state_dly1信号是同步于慢速时钟域clkb的信号。

现在只是将快速时钟域clka的脉冲信号Signal_a以src_state信号沿的形式保留住了,还没有做同步处理。如下图所示,此时我们再对src_state信号做打两拍的处理就可以将src_state信号同步到慢速时钟域clkb中了。其中,state_dly1信号是src_state信号在慢速时钟域clkb下打的第一拍,state_dly2信号是src_state信号在慢速时钟域clkb下打第二拍,state_dly2就是同步于慢速时钟域clkb的稳定信号。

到此为止,还有最后一部需要做的那就是将变为state_dly2信号的“沿”再转化为脉冲信号。这就需要引入了另一个新的知识——边沿检测。边沿检测主要作用是能够准确的识别出信号的上升沿或下降沿,也就是希望当上升沿或下降沿来临时,能够产生一个唯一标识上升沿或下降沿的脉冲信号来告诉上升沿或下降沿来了,然后再根据这个脉冲信号启动下一级操作。如下图所示,对同一信号打一拍后在①位置处检测到上升沿,拉高一个时钟的脉冲;在②位置处检测到下降沿,拉高一个时钟的脉冲。要满足这种特殊的要求,我们该如何编写代码呢?

上升沿检测核心代码在①处检测到data为高电平,data_reg为低电平,即表示有上升沿产生。

方法一:与逻辑实现
//-----------------------------------------------
always@(posedge sys_clk ornegedge sys_rst_n)
    if(sys_rst_n ==1'b0)
       podge <=1'b0;
    else   if((data)&&(~data_reg))   //核心逻辑
       podge <=1'b1;
    else  
       podge <=1'b0;

//-----------------------------------------------

方法二:或逻辑实现
//-----------------------------------------------
always@(posedge sys_clk ornegedge sys_rst_n)
    if(sys_rst_n ==1'b0)
       podge <=1'b0;
    else   if((~data)||(data_reg))   //核心逻辑
       podge <=1'b0;
    else  
       podge <=1'b1;
//-----------------------------------------------
下降沿检测核心代码:在②处检测到data为低电平,data_reg为高电平,即表示有下降沿产生,和上升沿的情况刚好相反。

方法一:与逻辑实现

//-----------------------------------------------
always@(posedge sys_clk ornegedge sys_rst_n)
    if(sys_rst_n ==1'b0)
       nedge <=1'b0;
    else   if((~data)&&(data_reg))   //核心逻辑
       nedge <=1'b1;
    else  
       nedge <=1'b0;   
//-----------------------------------------------

注:上面的例子是用时序逻辑实现的,和上图所示波形完全一致。希望大家能够记住边沿检测的核心逻辑以方便使用,当看到类似的代码也可以反推出检测的是上升沿还是下降沿。其核心逻辑也可以结合三目运算符用组合逻辑assign来实现,会使podge和nedge检测到上升沿和下降沿的脉冲均会提前一拍。

在今天解析的题目中需要同时检测上升沿和下降沿才能够还原脉冲信号,可以将上面上升沿的任一核心代码中的核心逻辑和下降沿的任一核心代码中的核心逻辑相组合来实现,当然还有个更好的办法那就是用“异或(^)”逻辑。

由前面的分析知道src_dtate信号在慢速时钟域clkb的采样下得到的state_dly1信号可能是不稳定的,而state_dly2信号是稳定的,不能直接用state_dly1和state_dly2来产生沿标志信号,因为state_dly1的不稳定性可能会导致产生的下降沿标志信号也不稳定,所以需要将state_dly2信号再打一拍,产生dst_state信号,用state_dly2信号和dst_state信号产生上升沿和下降沿标志信号还原脉冲,这就是为什么看到一共打了三拍的原因。还原后的波形如下所示,看到Signal_b信号的波形我们就知道要用assign语句来实现。此时就成功的实现了将快速时钟域clka的脉冲信号Signal_a同步到慢速时钟域clkb的脉冲信号Signal_b。如果大家做过百兆以太网的设计,就会用到这种方法来同步脉冲信号。

波形和分析都如此详细了,那我们的代码还是问题吗,当然要一气呵成,RTL代码如下所示:

//------------------------------------------------
01module fast_to_slow(
02     input  wire   clka       ,   //sourceclock
03      input  wire   src_rst_n   , //sourceclock reset (0:reset)
04      input  wire   Signal_a   ,   //sourceclock pulse in
05      input  wire   clkb       ,   //destinationclock
06      input  wire   dst_rst_n  ,   //destinationclock reset (0:reset)
07    
08      outputwire   Signal_b       //destinationpulse out
09);
10 
11reg     src_state   ;
12reg     state_dly1  ;
13reg     state_dly2  ;
14reg     dst_state   ;
15 
16//将脉冲信号转化为沿信号
17always@(posedge clka ornegedge src_rst_n)
18     if(src_rst_n ==1'b0)
19         src_state<=1'b0;
20     elseif(Signal_a ==1'b1)
21         src_state<=~src_state;
22 
23  //将展宽的脉冲打三拍
24always@(posedge clkb ornegedge dst_rst_n)
25     if(dst_rst_n ==1'b0)begin
26        state_dly1 <=1'b0;
27         state_dly2 <=1'b0;
28         dst_state  <=1'b0;
29     end              
30     elsebegin    
31         state_dly1 <= src_state;
32         state_dly2 <= state_dly1;
33         dst_state  <= state_dly2;
34     end
35 
36//上升沿和下降沿同时检测
37assign Signal_b = dst_state ^ state_dly2;
38
39endmodule
//-----------------------------------------------

根据上面RTL代码综合出的RTL视图如下所示。

如下图所示,是我们通过ModelSim仿真来验证得到的结果,和分析得到的波形是完全一致的。

为了后面大家仿真方便我们也将仿真代码贴出来供大家参考,Testbench代码如下所示:

//-----------------------------------------------
01module tb_fast_to_slow();
02
03reg     clka;
04reg     src_rst_n;
05reg     Signal_a;
06reg     clkb;
07reg     dst_rst_n;
08    
09wire    Signal_b;
10
11//初始化系统时钟、复位
12initialbegin
13 clka        =1'b1;
14 src_rst_n <=1'b0;
15 Signal_a  <=1'b0;
16 clkb       =1'b1;
17 dst_rst_n <=1'b0;
18 #3.334
19  //复位释放
20 src_rst_n <=1'b1;
21 dst_rst_n <=1'b1;
22 #33.34;
23  //第一个脉冲
24 Signal_a  <=1'b1;
25 #3.334;     
26 Signal_a  <=1'b0;
27 #66.68;    
28  //第二个脉冲
29 Signal_a  <=1'b1;
30 #3.334;     
31 Signal_a  <=1'b0;
32end
33
34//clka:模拟快速时钟域的时钟,每1.667ns电平翻转一次,频率近似为300MHz
35always  #1.667 clka =~clka;
36
37//clkb:模拟慢速时钟域的时钟,每5ns电平翻转一次,频率为100MHz
38always  #5 clkb =~clkb;
39
40//----------------fast_to_slow_isnt-----------
41 fast_to_slow  fast_to_slow_isnt(
42 .clka      (clka      ),  //input    clka      
43 .src_rst_n(src_rst_n),  //input   src_rst_n 
44 .Signal_a  (Signal_a),  //input   Signal_a     
45 .clkb      (clkb      ),  //input    clkb      
46 .dst_rst_n(dst_rst_n),  //input   dst_rst_n 
47                                            
48 .Signal_b (Signal_b  )   //output  Signal_b     
49);
50      
51endmodule
//-----------------------------------------------
其实在使用的这种脉冲同步法来解决单比特信号从快速时钟域同步到慢速时钟域的问题是有一定缺陷的,比如输入脉冲的间隔至少是两个同步器时钟周期(大家可以分析下原因),需要用握手信号的方法来进一步改进,有兴趣的可以再网上查找相关资料,但本题用脉冲同步法来解决是完全可以的,这也是出题人的本意。
还有同学会问道:本期讲解的是单比特信号的跨时钟域处理,那在遇到多比特数据跨时钟域处理时该怎么办呢?多比特数据跨时钟域也有属于它自己的独特方法,由于篇幅有限这里不再详细讲解,后面遇到相关的题目再详细展开。

下期预告

下一期,将对另一道大疆FPGA逻辑岗A卷的问答题进行解析,大家可以提前看一下题目,尝试着做一做,敬请期待。
用moore型状态机实现序列“1101”从右到左的不重叠检测。(注:典型的状态机设计分为moore与mealy两大类,其中mealy状态机的输出不仅与当前状态值有关,而且与当前输入有关;moore状态机的输出仅与当前状态值有关,而与此时的输入无关)(大疆FPGA逻辑岗A卷)1)请画出状态转移图,图中状态用S0, S1, S2, ...标识2)针对这个具体设计如何衡量验证的完备性?
END

目前,我们正在通过大疆硬件岗和FPGA逻辑岗的题目,为大家带来笔试题的解析,以及知识的补充。如果有想要解析的题目,可以发给达尔闻安排。同时,欢迎加入达尔闻求职技术交流群,进群方式:添加妮姐微信(459888529),并备注求职,即可邀请进群

达尔闻求职“加油站”系列:

磁珠的用法、PCB布线3W规则

达尔闻 求职“笔试经”系列:

华为硬件逻辑岗(FPGA)

紫光展锐数字IC岗(编程题)


达尔闻 求职“面试经”系列
从无人机爱好者到获得DJI大疆Offer
offer拿到手软,最后选华为!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存