异步bus交互(二)— 握手协议(1)

跨时钟域处理 & 亚稳态处理

1.概述

常见的跨时钟域信号处理方法都有哪些呢?有如下的三种:

(1)两级DFF同步器
(2)握手协议
(3)异步FIFO

.
.

2.一个简单的握手信号

如果频率较高的时钟域A中的信号D1 要传到频率较低的时钟域B,但是D1只有一个时钟脉冲宽度(1T),clkb 就有几率采不到D1了,如图1。
异步bus交互(二)— 握手协议(1)
因此只有当D1 在很长一段时间内为1或0,确保一定可以被clkb采样到,才能用两级DFF同步器处理。

如果信号D1 只有1T或几个T的脉宽,又需要传到时钟频率较低甚至或快或慢不确定的时钟域B,这种情况该怎么如何处理呢?

握手协议(handshake)异步信号处理是一种常见的异步信号处理方法。

异步bus交互(二)— 握手协议(1)

使用握手信号“xreq”和“yack”,“系统x”将数据发送给“系统y”。下面是使用握手信号传输数据的例子。

  1. 发送器“系统x”将数据放在数据总线上并发出“xreq”(请求)信号,表示有效数据已经发到接收器“系统y”的数据总线上。
    
  2. 采用两级D触发器缓存,把“xreq”信号同步到接收器的时钟域“yclk”上,得到“yreq2”信号,当采样到yreq2有效后,将数据锁存到系统y的总线上,同时接收器发出“yack”信号(相应信号)。

3) 发送器接收到接收器发送来的“yack”信号,然后将“yack”信号同步到“xclk”时钟域上,同步的原理同上,采用两级的D触发器采样,采样时钟为“xclk”,得到同步后的“xack2”信号,xclk时钟采样到“xack2”有效后,发出下一个数据,同时让“xreq”有效一个时钟(xclk)。
异步bus交互(二)— 握手协议(1)
案例RTL代码

module  handshake_y(clky, rst_n_y, xdata, xreq, yack, ydata);

input         clky;

input         rst_n_y;

input[7:0]     xdata;

input         xreq;

output        yack;
output[7:0]   ydata;
reg[7:0]      ydata;
reg yack;
reg yreq1, yreq2;

always@(posedge clky or negedge rst_n_y)

begin

   if(!rst_n_y) yreq1 <= 1'b0;

   else       yreq1 <= xreq;

end

always@(posedge clky or negedge rst_n_y)

begin

   if(!rst_n_y) yreq2 <= 1'b0;

   else       yreq2 <= yreq1;

end

always@(posedge clky or negedge rst_n_y)

begin

   if(!rst_n_y)   ydata <= 8'h00;

   else if(yreq2) ydata <= xdata;

   else         ydata <= ydata;

end

always@(posedge clky or negedge rst_n_y)

begin

   if(!rst_n_y)
     yack <= 1'b0;

   else if(yreq2) 
      yack <= 1'b1;

   else yack <= 1'b0;

end

endmodule

//

module  handshake_x(clkx, yack, rst_n_x, xreq, xdata);

input         clkx;

input         yack;

input         rst_n_x;

output        xreq;

output  [7:0]    xdata;
reg xreq;
reg xack1,xack2;
reg  [7:0]  data;
reg  [7:0]    xdata;

always@(posedge clkx or negedge rst_n_x)

begin

   if(!rst_n_x) xack1 <= 1'b0;

   else        xack1 <= yack;

end

always@(posedge clkx or negedge rst_n_x)

begin

   if(!rst_n_x) xack2 <= 1'b0;

   else        xack2 <= xack1;

end

always@(posedge clkx or negedge rst_n_x)

begin

   if(!rst_n_x)   data <= 8'h00;

   else if(xack2) data <= data + 1;

   else           data <= data;

end

always@(posedge clkx or negedge rst_n_x)

begin

   if(!rst_n_x)   xdata <= 8'h00;

   else if(xack2) xdata <= data;

   else           xdata <= xdata;

end

always@(posedge clkx or negedge rst_n_x)

begin

   if(!rst_n_x)   xreq <= 1'b0;

   else if(xack2) xreq <= 1'b1;

   else           xreq <= 1'b0;

end

endmodule

测试代码

module tb;

reg clkx;

reg clky;

reg rst_n_x;

reg rst_n_y;
wire yack;
wire xreq;
wire  [7:0]    xdata;
wire  [7:0]    ydata;

initial

begin
//xdata = 8'h32;
clkx =1'b0;
clky =1'b0;
rst_n_x= 1'b0;
rst_n_y= 1'b0;
# 100;
//xdata = 8'h01;
rst_n_x= 1'b1;
rst_n_y= 1'b1;
# 100;
//xdata = 8'h01;
rst_n_x= 1'b0;
rst_n_y= 1'b1;
# 100;
//xdata = 8'h01;
rst_n_x= 1'b1;
rst_n_y= 1'b0;
end

always#5 clkx = ~clkx;

always#6 clky = ~clky;



handshake_x  x1(  // transmiter
.clkx(clkx),//in
.yack(yack),//in
.rst_n_x(rst_n_x),//in
.xreq(xreq),//out
.xdata(xdata)//out

);

handshake_y  y1( //receiver

.clky(clky),//in

.rst_n_y(rst_n_y),//in

.xdata(xdata),//in

.xreq(xreq),//in

.yack(yack),//out
.ydata(ydata)
);

endmodule

上一篇:串口发送模块与验证


下一篇:奇数分频