一、握手协议
当由快时钟跨到慢时钟时,为了避免采不到信号这种情况,通常运用电平展宽、脉冲同步器、或者是握手处理。
图中所示,发送端时钟是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请求传输。文章来源:https://www.toymoban.com/news/detail-656859.html
二、代码
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文章来源地址https://www.toymoban.com/news/detail-656859.html
到了这里,关于跨时钟域设计方法-握手协议、异步FIFO的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!