跨时钟域设计方法-握手协议、异步FIFO

一、握手协议

当由快时钟跨到慢时钟时,为了避免采不到信号这种情况,通常运用电平展宽、脉冲同步器、或者是握手处理。


图中所示,发送端时钟是clk1,接收端时钟是clk2,当发送端接收到外部传过的数据时,准备就绪时拉高t_req,向接收端发送该信号表示我准备好传输了你准备好接收了吗,该信号到达接收端后进行两级同步器,为什么两级同步,主要是如果是快转慢,你需要用这种方式来展宽信号电平,这里由于是慢转快,仅仅两级同步就是 为了减小亚稳态发生的概率,两级同步时在接收端的时钟clk2下发生的,两级同步后得到t_req_rr,在下一个clk2时钟沿来时发现t_req_rr为高,进行拉高ack,表示我接受到你的请求了,同时开始采集数据,此时的数据最稳定,当发送端接收到这个ack信号后,进行同步处理,同样是两级同步得到re_ack_rr信号,在clk1上升沿识别到该信号为1后,在下一个时钟沿,时拉低req,表示发送端不在向接收端请求发送;半握手结束;
接下来进行全握手的部分:
当拉低的req信号,再次经过clk2两级同步后得到req_rr为0时,下一个时钟沿拉低ack信号,表示以及完成接收任务,该信号经过clk1发送时钟的两级同步后的ack_rr为0,下一个时钟沿来的时候进行下一次数据的传输,如果检测到总线有数据要传输,下一个时钟拉高req,重复以上传输;

在这里插入图片描述

快时钟,转慢时钟时,如图所示:
当监测到总线上要传输数据时,传输器拉高req,req经过接收器的时钟des_clk的两级同步后得到des_req_syn2,在下一时钟上升沿拉高des_ack,且同时接收器开始采集数据,此时发送端通过将ack信号在发送端时钟下打两拍得到src_ack_sync2,后下一次时钟上升沿拉低req,同样马上接收端在就知道他拉低了req,经过两拍后再下一时钟沿拉低ack,ack信号在发送端时钟下经过两拍后再下一拍开始下一个数据的传输,同理如果有下一个数据则经过一拍拉高req请求传输。

二、代码

1.>top层:

module asynchronous_data(
input tclk,
input rclk,
input rstn,
input rrstn,
input [4:0] data_in,
output[4:0]data_out
);
 
 
wire req;
wire ack;
reg [4:0]tx_data;
 
tx tx_module(
.tclk(tclk),
.rstn(rstn),
.ack(rrstn),
.data_in(data_in),
.req(req),
.tx_data(tx_data)
);
 
rx rx_1(
.rclk(rclk),
.rrstn(rrstn),
.req(req),
.data_in(tx_data),
.ack(ack),
.rx_data(data_out)
);
 
endmodule


2.>t发送端:


module tx(
input tclk,
input rstn,
input ack,
input [4:0] data_in,
output req,
output reg[4:0]tx_data
);
 
 
wire ack_sync;
reg ack_sync1;
reg req_reg;
wire ack_syn_negedge;
always@(posedge tclk or negedge rstn)begin
	if(!rstn)begin
		tx_data<=0;
	end
	else if(ack_syn_negedge)begin
		tx_data<=data_in;
	end
end
 
reg_module reg_module1(
								.clk(tclk),
								.sig(ack),
								.rstn(rstn),
								.sig_reg(ack_sync)
							);
							
							
always@(posedge tclk or negedge rstn)begin
	if(!rstn)begin
		ack_sync1<=0;
	end
	else if(ack_syn_negedge)begin
		ack_sync1<=ack_sync;
	end
end
		
assign ack_syn_negedge=!ack_sync&ack_sync1;
 
 
always@(posedge tclk or negedge rstn)begin
	if(!rstn)begin
		req_reg<=0;
	end
	else if(ack_sync)begin
		req_reg<=0;
	end
	else begin
		req_reg<=1;
	end
end
	
assign req=	req_reg;
endmodule


3.接收端

module rx(
input rclk,
input rrstn,
input req,
input [4:0] data_in,
output ack,
output reg [4:0]rx_data
);
 
wire req_sync;
 
always@(posedge rclk or negedge rrstn)begin
	if(!rrstn)begin
		rx_data<=0;
	end
	else if(req_sync)begin
		rx_data<=data_in;
	end
end
 
reg_module reg_module1(
								.clk(rclk),
								.sig(req),
								.rstn(rrstn),
								.sig_reg(req_sync)
							);
		
assign ack =req_sync;
 
endmodule

4.调用两级同步

module reg_module(
input clk,
input rstn,
input sig,
output reg sig_reg
);
 
reg sig_reg0;
 
always@(posedge clk or negedge rstn)begin
	if(!rstn)begin
		sig_reg0<=0;
		sig_reg<=0;
	end
	else begin 
		sig_reg0<=sig;
		sig_reg<=sig_reg0;
	end
end
endmodule

总结

握手协议主要就是,我的信号传给你,要在你的时钟下进行两级同步后,参考我这个信号做出反映,反映后的信号传给我,我经过我的时钟下两级同步后,通过观测信号修改我刚刚的反映,这样,就不会传错了,但是由于每次信号交互都要两级同步,所以延迟较大,浪费不少资源,适合传输速度叫慢的进行传输。
引用:https://blog.csdn.net/yueqiu693/article/details/125073144

  • 10
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北极光sdu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值