跨时钟传输

一、单比特CDC传输
1.1 慢到快
快时钟域相比慢时钟域采样速度更快,也就是说从慢时钟域来到快时钟域的信号一定可以被采集到。既然快时钟一定可以采集到慢时钟分发的数据,那么考虑的问题就只剩下如何保证采样到的信号质量!最常用的同步方法是双级触发器缓存法,俗称延迟打拍法。信号从一个时钟域进入另一个时钟域之前,将该信号用两级触发器连续缓存两次,可有效降低因为时序不满足而导致的亚稳态问题。
具体如下图所示:来自慢时钟clk1的信号在clk2被多次采样(信号在clk1持续一个时钟周期,在clk2持续三个时钟周期),如果只需要在clk2持续一个时钟周期,可以采用边沿检测即可得到signal4;

1.2 快到慢
慢时钟域相比快时钟域采样速度更慢,也就是说从快时钟域来到慢时钟域的信号极有可能被漏采。一般要求在接收时钟域中采样信号要保持三个时钟边沿的时间(也就是1.5倍的采样时钟周期)才会避免出现漏采。也就是快到慢跨时钟域的核心是如何延长信号长度!
对于电平信号而言(一般电平信号持续时间足够长),信号长度可以得到保证,所以正常采用两级同步器采样即可。
对于脉冲信号而言(一般脉冲信号持续时间很短),长度难以得到保证,需要对信号进行延长。目前,常用延长方法有两种:
-
一是开环(无反馈)延长,在知道两个时钟频率比的情况下,可以采用“快时钟域脉宽扩展+慢时钟域延迟打拍”的方法进行同步。
-
二是闭环(有反馈)延长,信号延长的恢复位置由反馈信号决定,此方法实质是通过相互握手的方式对窄脉冲信号进行脉宽扩展,这也是我们常说的“握手协议”。
然而,除了“握手协议”以外其他两种方法都是有缺陷、有限制的,具体如下图所示:


可以看到无论是电平还是脉冲信号使用起来都是有限制的,因为它们采用的都是无反馈的开环设计(详细可查看博文跨时钟传输——单比特)。采用闭环的反馈设计可以避免这些问题,具体流程如下:

- 快时钟域对脉冲信号进行检测,检测为高电平时输出高电平信号req。
- 慢时钟域对快时钟域的信号req进行延迟打拍采样。因为此时的脉冲信号被快时钟域保持拉高状态,延迟打拍肯定会采集到该信号。
- 慢时钟域确认采样得到高电平信号req_r2后,拉高反馈信号ack再反馈给快时钟域。
- 快时钟域对反馈信号ack进行延迟打拍采样得到ack_r0。如果检测到反馈信号为高电平,证明慢时钟域已经接收到有效的高电平信号,信号恢复原来状态。


1.3 单比特“握手协议”verilog代码
verilog代码
//单比特快到慢“握手协议”
module cdc_sbit_handshake(
input aclk, //快时钟
input arst_n, //快时钟域复位信号
input signal_a,//快时钟域信号
input bclk, //慢时钟
input brst_n, //慢时钟域复位信号
output signal_b//慢时钟域输出信号
);
//慢时钟域信号展宽直至反馈信号回来再恢复
reg req;//寄存慢时钟域展宽信号
reg ack_r0;//反馈信号
always@(posedge aclk or negedge arst_n) begin
if(!arst_n) begin
req <= 1'b0;
end
else if(signal_a) begin
req <= 1'b1; //信号展宽
end
else if(ack_r0) begin
req <= 1'b0; //反馈信号到来时恢复
end
end
//展宽信号跨时钟同步至慢时钟域
reg req_r0;
reg req_r1;
reg req_r2;
always@(posedge bclk or negedge brst_n) begin
if(!brst_n)begin
{
req_r2,req_r1,req_r0} <= 3'b0;
end
else begin
{
req_r2,req_r1,req_r0} <= {
req_r1,req_r0,req};
end
end
//生成反馈信号并同步至快时钟域
reg ack;
always@(posedge aclk or negedge arst_n) begin
if(!arst_n) begin
{
ack_r0,ack} <= 2'b0;
end
else begin
{
ack_r0,ack} <= {
ack,req_r1};
end
end
//信号上升沿检测,让输出持续一个慢时钟周期
assign signal_b = ~req_r2 & req_r1;
endmodule
Testbench
`timescale 1ns/1ps //仿真时间单位1ns 仿真时间精度1ps
module cdc_sbit_handshake_tb;
//信号申明
reg aclk;
reg arst_n;
reg signal_a;
reg bclk;
reg brst_n;
wire signal_b;
//例化
cdc_sbit_handshake u_cdc_sbit_handshake(
.aclk (aclk),
.bclk (bclk),
.arst_n (arst_n),
.brst_n (brst_n),
.signal_a (signal_a),
.signal_b (signal_b)
);
//快时钟域慢时钟生成
always #5 aclk =~ aclk;
always #15 bclk =~ bclk;
//初始信号赋值与激励
initial begin
signal_a = 0;
aclk = 0;
bclk = 0;
arst_n = 1;
brst_n = 1;
#15;
arst_n = 0;
brst_n = 0;
#15;
arst_n = 1;
brst_n = 1;
signal_a = 1;
#10;
signal_a = 0;
end
endmodule
仿真结果

二、多比特CDC传输
- 多比特为能不能使用二级同步器传输?使用格雷码也不行吗?什么情况下可以使用同步器加格雷码跨时钟传输?
先给结论:多比特信号不能用二级同步器跨时钟传输,哪怕使用格雷码大部分情况也不行,只有在格雷码自增或自减顺序变化才可以跨时钟传输。对于多比特数据,在进行传输时候会因为时序问题导致所有寄存器不会同时翻转(不是不翻转,是不同时翻转!),所以容易在跨时钟传输的时候出现中间态。使用格雷码可以避免这种现象,但是当格雷码不是按计数顺序变化(非顺序变化相当于每次变化不止一位),这同样是不允许的,因为格雷码每次只有一位发生变化的前提是,数据是递

本文详细介绍了跨时钟域传输的原理和方法,包括单比特传输中的慢到快、快到慢策略,如延迟打拍和握手协议,并提供了Verilog代码示例。对于多比特传输,由于时序问题,不能直接使用二级同步器,而应采用MUX同步器法或异步FIFO。异步FIFO作为一种通用解决方案,适用于快慢时钟间的双向传输,能有效处理数据流的高速传输需求。
&spm=1001.2101.3001.5002&articleId=131076559&d=1&t=3&u=abe8e310c41a4195af123ca509b9871b)
1438

被折叠的 条评论
为什么被折叠?



