原创 “单比特信号同步”

2009-5-24 11:35 2363 12 12 分类: 工程师职场

1. 概述


信号同步的目的是防止新时钟域中第一级触发器


的亚稳态信号对下一级逻辑造成影响。


简单的同步器由两个触发器串联而成,中间没有其它组合电路。


这种设计可以保证后面的触发器获得前一个触发器输出时


前一个触发器已退出了亚稳态,并且输出已稳定。


2.信号同步的要求


为了使同步工作能正常进行


从某个时钟域传来的信号应先通过原时钟域上的一个触发器


然后不经过两个时钟域间的任何组合逻辑


直接进入同步器的第一个触发器中。


这一要求非常重要,


因为同步器的第一级触发器对组合逻辑所产生的毛刺非常敏感。


如果一个足够长的毛刺正好满足建立-保持时间的要求


则同步器的第一级触发器会将其放行,


给新时钟域的后续逻辑送出一个虚假的信号。


3.同步造成的延时


一个经同步后的信号在两个时钟延以后就成为新时钟域中的有效信号。


信号的延迟是新时钟域中的一到两个时钟周期。


一种粗略的估算方法是同步器电路在新时钟域中造成两个时钟周期的延迟,


设计者需要考虑同步延迟对跨时钟域的信号时序造成的影响。


4.三种常用的同步器


同步器由许多种设计方法,


因为同一种同步器不能满足所有应用的需求。


同步器的类型基本上有三种:电平、边沿检测和脉冲。


虽然还存在其它类型的同步器,


但这三种类型的同步器可以解决设计者遇到的多数应用问题。


A. 电平(level signal)同步器


在电平同步器中,


跨时钟域的信号在新时钟域中要保持高电平或低电平两个时钟周期以上。


同步之后的信号是电平的形式,


而该电平所维持的时钟周期个数是其在跨时钟域期间被上升沿检测到的次数。


这种同步器是所有同步器电路的核心。


下面是用Verilog描述的电平同步器


module synzer_ls(
                 data_out,
                 clk1,
                 clk2,
                 data_in
                 ); //level signal synchronizer


  output     data_out;  // signal that after synchronized
  input      clk1;      // old clk signal
  input      clk2;      // new clk signal
  input      data_in;   // signal that before synchronized


  reg        a;         // DFF in the old clk domain
  reg        b;         // the first DFF in the new clk domain
  reg        c;         // the second DFF in the new clk domain


  always @(posedge clk1) //a
    a<=data_in;
 
  always @(posedge clk2) //b
    b<=a;


  always @(posedge clk2) //c
    c<=b;
 
  assign data_out=c;


endmodule


B. 边沿检测(edge detecting)同步器


边沿检测同步器在电平同步器的输出端增加了一个触发器。


新增触发器的输出经反相后和电平同步器的输出进行与操作。


这一电路会检测同步器输入的上升沿,


产生一个与时钟周期等宽、高电平有效的脉冲。


如果将与门的两个输入端交换使用,


就可以构成一个检测输入信号下降沿的同步器。


将与门改为非门可以构建一个产生低电平有效脉冲的电路。


当一个脉冲进入更快的时钟域中时,


边沿检测同步器可以工作的很好。


这一电路会产生一个脉冲,用来指示输入信号上升或下降沿。


这种同步器有一个限制,


即输入脉冲的宽度必须大于同步时钟周期与第一个同步触发器所需保持时间之和。


最保险的脉冲宽度是同步器时钟周期的两倍。


如果输入是一个单时钟宽度脉冲进入一个较慢的时钟域,


则这种同步器没有作用,


在这种情况下就要采用脉冲同步器。


下面是用Verilog描述的边沿(上升沿)检测同步器


module synzer_ed(
                 data_out,
                 clk1,
                 clk2,
                 data_in
                 ); // edge detecting synchronizer


  output     data_out;  // signal that after synchronized
  input      clk1;      // old clk signal
  input      clk2;      // new clk signal
  input      data_in;   // signal that before synchronized


  reg        a;         // DFF in the old clk domain
  reg        b;         // the first DFF in the new clk domain
  reg        c;         // the second DFF in the new clk domain
  reg        d;         // the third DFF in the new clk domain


  always @(posedge clk1) //a
    a<=data_in;
 
  always @(posedge clk2) //b
    b<=a;


  always @(posedge clk2) //c
    c<=b;
 
  always @(posedge clk2) //d
    d<=c;


  assign data_out=c&&(~d);


endmodule


C. 脉冲(Pulse)同步器


脉冲同步器的输入信号是一个单时钟宽度脉冲,


它触发原时钟域中的一个翻转电路。


每当翻转电路接收到一个脉冲时,它就会在高低电平间进行转换,


然后通过电平同步器到达异或门的一个输入端,


而另一个信号经过一个时钟周期的延迟进入异或门的另一端,


翻转电路每转换一次状态,


这个同步器的输出端就产生一个单时钟宽度的脉冲。


脉冲同步器的基本功能是从某个时钟域取出一个单时钟宽度脉冲,


然后在新时钟域中建立另一个单时钟宽度的脉冲。


脉冲同步器也有一个限制,


及输入脉冲之间的最小间隔必须等于两个同步器时钟周期。


如果输入脉冲相互过近,


则新时钟域中的输出脉冲也紧密相邻,


结果是输出脉冲宽度比一个时钟周期宽。


当输入脉冲时钟周期大于两个同步器时钟周期时,这个问题更加严重。


这种情况下,如果输入脉冲相邻太近,则同步器就不能检测到每个脉冲。


下面是用Verilog描述的脉冲同步器


module synzer_pl(
                 data_out,
                 clk1,
                 clk2,
                 data_in,
                 rst_n
                );  // pulse synchronizer
            
 output     data_out; // signal that after synchronized
 input      clk1;     // old clk signal
 input      clk2;     // new clk signal
 input      data_in;  // signal that before synchronized
 input      rst_n;    // signal indicating reset
 
 reg        a;        // DFF in the old clk domain
 reg        b;        // the first DFF in the new clk domain
 reg        c;        // the second DFF in the new clk domain
 reg        d;        // the third DFF in the new clk domain
 
 wire       q;
 wire       q1;
 wire       di;
 
 assign di=data_in?q1:q;
 assign q=a;
 assign q1=~a;
 assign data_out=(c==d)?0:1;
 
 always @(posedge clk1) //a
 begin
   if(!rst_n)
     a<=1'b0;
   else
     a<=di;
 end
 
 always @(posedge clk2) //b
    b<=a;


  always @(posedge clk2) //c
    c<=b;
 
  always @(posedge clk2) //d
    d<=c;
   
endmodule

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
12
关闭 站长推荐上一条 /3 下一条