一、“打两拍”处理多比特信号跨时钟域的问题
如上图所示adata信号从2’b00变到2‘b11,一段时间之后再变为2’b00,但是因为寄存器同步器的delay有随机性,可能是一个周期之后就同步过去了,也可能需要两个周期。
这样我们就可能在bdata1上看到一个周期的2’b01,之后也可能看到一个周期的2’b10,这两个值都是adata没有出现过的,也就是说bdata1出现了错误的值。
为了解决这个问题,我们介绍一种"MUX/DMUX同步器“来解决多比特信号的跨时钟域问题。
二、MUX/DMUX同步器
2.1 电路波形图
如上图所示,MUX/DMUX同步器主要是用于带有数据有效标志信号的多比特数据跨时钟域问题,且多比特数据要保持一段时间。
上图红色虚线框内是主要是对数据有效标志信号的处理,可以发现其实就是对单比特的数据有效标志信号在bclk时钟域打了两拍,其实就是单比特从慢速时钟域到快速时钟域的处理方式。数据有效标志信号在时钟bclk下打两拍后就同步于该打拍的时钟域了,此时同步于aclk的数据依然保持有效,将同步后的数据有效标志信号作为多路选择器的选通信号,将数据也同步于bclk时钟域中。
此外,对adata_valid_rr在bclk还打了一拍主要是为了让数据有效标志信号和同步bclk的数据匹配。
在这里,需要注意的是,如果bclk的时钟速率小于aclk的时钟速率,我们只需要把上图红色虚线框内电路换成单比特从快速时钟域到慢速时钟域的处理方式即可。
2.2 代码
module mux_synchronizer(
input adata_valid,
input [7:0] adata,
input brst_n,
input bclk,
output reg [7:0] bdata,
output reg bdata_valid
);
reg adata_valid_r;
reg adata_valid_rr;
always@(posedge bclk or negedge brst_n)
begin
if(brst_n==1'b0)
{bdata_valid,adata_valid_rr,adata_valid_r}<=3'b0;
else
{bdata_valid,adata_valid_rr,adata_valid_r}<={adata_valid_rr,adata_valid_r,adata_valid};
end
always@(posedge bclk or negedge brst_n)
begin
if(brst_n==1'b0)
bdata<=8'b0;
else if(adata_valid_rr==1'b1)
bdata<=adata;
end
endmodule
三、使用MUX/DMUX同步器处理多比特数据跨时钟域问题
问题,假设两个异步时钟aclk和bclk,aclk=148.5M,bclk=145M。
如图,bclk时钟域中一个8bit数据data通过data_valid标记有效,持续有效约8个时钟周期,该时间内数据保存稳定且不会变化,每40ms更新一次。
要求bclk时钟域该数据信号同步到aclk时钟域,data_valid在aclk时钟域持续1个时钟周期,请用你熟悉的hdl语言描述。设计中请用异步低复位。
3.1 电路波形图
3.2 代码
module mux_synchronizer(
input aclk,
input arst_n,
input [7:0] data,
input data_valid,
output reg [7:0] adata,
output reg adata_valid
);
reg[2:0] adata_valid_r;
wire adata_valid_rise;
always@(posedge aclk or negedge arst_n)
begin
if(arst_n==1'b0)
adata_valid_r[2:0]<=3'd0;
else
adata_valid_r[2:0]<={adata_valid_r[1:0],data_valid};
end
assign adata_valid_rise=~adata_valid_r[2]&adata_valid_r[1];//检测data_valid的上升沿
always@(posedge aclk or negedge arst_n)
begin
if(arst_n==1'b0)
adata<=8'd0;
else if(adata_valid_rise==1'b1)
adata<=data;
end
always@(posedge aclk or negedge arst_n)
begin
if(arst_n==1'b0)
adata_valid<=1'b0;
else
adata_valid<=adata_valid_rise;
end
endmodule
3.3 验证
module mux_synchronizer_tb();
reg aclk;
reg arst_n;
reg [7:0] data;
reg data_valid;
wire adata_valid;
wire [7:0] adata;
reg bclk;
always #3.448 bclk=~bclk;
always #3.365 aclk=~aclk;
initial begin
aclk=1;
bclk=1;
arst_n=0;
data_valid=0;
data=0;
#200;
arst_n=1;
//第一次数据
@(posedge bclk)
data_valid=1;
data=1;
#53.84;
@(posedge bclk)
data_valid=0;
#400;
//第二次数据
@(posedge bclk)
data_valid=1;
data=2;
#53.84;
@(posedge bclk)
data_valid=0;
end
mux_synchronizer u1(
.aclk(aclk),
.arst_n(arst_n),
.data(data),
.data_valid(data_valid),
.adata(adata),
.adata_valid(adata_valid)
);
endmodule
四、其他多比特数据跨时钟域处理方法
4.1 异步FIFO
4.2 握手反馈
链接给的单比特数据跨时钟域处理,多比特数据跨时钟域处理方式原理和此类似。
五、参考文献
多bit信号跨时钟域怎么办?
如何用MUX/DMUX处理多比特数据跨时钟域