当前位置:   article > 正文

多bit信号的跨时钟域处理_多bit跨时钟域

多bit跨时钟域

前言

常用的多bit信号的跨时钟域处理方法有两种:
①使用异步FIFO进行数据同步。
②采用握手方式进行数据同步。

使用FIFO进行的数据同步

当存在两个异步时钟域并且二者之间需要进行数据包传输时,双端口异步FIFO最为合适。

FIFO有两个端口,一个端口写入输入数据,另一个端口读出数据。两个端口工作在相互独立的时钟域内,通过各自的指针(地址)来读写数据。由于每个端口工作在相互独立的时钟域内,因此读写操作可以独立实现并且不会出现任何差错。当FIFO变满时,应停止写操作,直到FIFO中出现空闲空间。同样,当FIFO为空时,应停止读操作,直到有新的数据被写入FIFO中。
异步FIFO的具体代码可以参见我的另一篇文章:
异步FIFO代码

握手同步方式

FIFO可用于在不同的时钟域之间进行数据包的传输,但是在一些应用中,需要在不同时钟域之间进行少量数据的传输。FIFO占用的硬件资源较大,此时可以考虑使用握手同步机制。

以下是握手同步机制的工作步骤:
●用后缀_t表示数据发送端,用后缀_r表示数据接收端。发送端时钟用tclk表示,接收端时钟用rclk表示;
●当需要发送的数据准备好后,发送端将t_rdy信号置为有效;
●在t_rdy有效期间,t_data必须保持稳定;
●接收端在rclk时钟域内采用双同步器同步t_rdy控制信号,并把同步后的信号命名为t_rdy_rclk;
●接收端在发现t_rdy_rclk信号有效时,t_data已经安全地进入了rclk时钟域内,使用rclk对其进行采样,可以得到t_data_rclk。由于数据已经在rclk域进行了正确采样,所以此后在rclk域使用该数据是安全的;
●接收端将r_ack信号置为1;
●发送端通过双同步器在tclk时钟域内同步r_ack信号,同步后的信号命名为r_ack_tclk;
●以上所有步骤被称为“半握手”。这是因为发送端在输出下一个数据之前,不会等到r_ack_tclk被置为0;
●半握手机制工作速度快,但是使用半握手机制时需要谨慎,一旦使用不当,会导致操作错误;
●从低频时钟域向高频时钟域传输数据时,半握手机制较为适用,这是由于接收端可以更快地完成操作。然而,如果从高频时钟域向低频时钟域传输数据,则需要采用全握手机制;
●当r_ack_tclk为高电平时,发送端将t_rdy置为0;
●当t_rdy_rclk为低电平时,接收端将r_ack置为0;
●当发送端发现r_ack_tclk为低电平后,全握手过程结束,发送端可以发送新的数据;
●显然,全握手过程耗时较长,数据传输速率较慢。然而,全握手机制稳定可靠,可以在两个任意频率的时钟域内安全地进行数据传输。

下图所示为全握手机制工作波形图:
全握手机制工作波形
下面是一段采用全握手机制的同步桥代码,代码中采用的信号命名方式与以上讲述中略有不同,但整体思路与以上讲述的一致,可以直接例化此同步桥进行跨时钟域的数据同步:

module sync_bridge(
       input                  clk_t   ,
       input                  clk_r   ,
       input                  rst_n   ,
       input                  data_vld,   //表示发送端数据有效(已经准备好)
       input         [31:0]   data_t  ,
       output  reg   [31:0]   data_r
                  );
reg   req, req_syn1, req_syn2;
reg   ack, ack_syn1, ack_syn2;

always @(posedge clk_t, negedge rst_n) begin
  if(rst_n == 1'b0) begin
    req <= #1 1'b0;
  end
  else if(ack_syn2 == 1'b1) begin
    req <= #1 1'b0;
  end
  else if(ack_syn2 == 1'b0 && data_vld == 1'b1) begin
    req <= #1 1'b1;
  end
end

always @(posedge clk_t, negedge rst_n) begin
  if(rst_n == 1'b0) begin
    ack_syn1 <= #1 1'b0;
    ack_syn2 <= #1 1'b0;
  end
  else begin
    ack_syn1 <= #1 ack;
    ack_syn2 <= #1 ack_syn1;
  end
end

always @(posedge clk_r, negedge rst_n) begin
  if(rst_n == 1'b0) begin
    req_syn1 <= #1 1'b0;
    req_syn2 <= #1 1'b0;
  end
  else begin
    req_syn1 <= #1 req;
    req_syn2 <= #1 req_syn1;
  end
end

always @(posedge clk_r, negedge rst_n) begin
  if(rst_n == 1'b0) begin
    ack <= #1 1'b0;
  end
  else if(req_syn2 == 1'b1) begin
    ack <= #1 1'b1;
  end
  else if(req_syn2 == 1'b0) begin
    ack <= #1 1'b0;
  end
end

always @(posedge clk_r, negedge rst_n) begin
  if(rst_n == 1'b0) begin
    data_r <= #1 32'h0;
  end
  else if(req_syn2 == 1'b1) begin
    data_r <= #1 data_t;
  end
end

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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/387536
推荐阅读
相关标签
  

闽ICP备14008679号