我们知道,在单比特信号的跨时钟域传输时,如果是从慢时钟域到快时钟域,那么我们可以采用打两拍的方式。然而,这个方法在快时钟域传输到慢时钟域时并不可行,因为如果快时钟域的该信号的宽度小于慢时钟的周期,那么慢时钟很可能无法采样到,如下图所示:
为了解决这个问题,一个自然的想法就是将signal_a信号展宽,保证能被慢时钟域采样到,具体的方法是:每当快时钟域clka检测到Signal_a脉冲信号为高时,让wide_a信号取反,使得Signal_a的第一个脉冲变为wide_a信号的上升沿,Signal_a的第二个脉变为wide_a信号的下降沿。这样就使快速时钟域clka的脉冲信号Signal_a展宽之后在慢速时钟域clkb中能够被采集到。在接收方,慢时钟将wide_a打两拍同步到慢速时钟域clkb,再通过双边缘检测将wide_b2转换为脉冲信号。
整个过程如下图所示:
RTL代码实现:
发送端:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/03/08 10:38:57
// Design Name:
// Module Name: ont_bit_sync
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ont_bit_sync(
input logic clka,
input logic rst,
input logic pluse_a,
output logic wide_a
);
always@(posedge clka,posedge rst)
if(rst)
wide_a<=0;
else if(pluse_a)
wide_a<=~wide_a;
endmodule
接收端:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/03/08 10:41:32
// Design Name:
// Module Name: one_bit_sync_recv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module one_bit_sync_recv(
input logic clkb,
input logic rst,
input logic wide_a,
output logic pluse_b
);
logic a_ff1;
logic a_ff2;
logic a_ff3;
always_ff@(posedge clkb,posedge rst)
if(rst)
{a_ff3,a_ff2,a_ff1}<=3'b000;
else
{a_ff3,a_ff2,a_ff1}<={a_ff2,a_ff1,wide_a}; //对wide信号打两拍同步,第三拍用于边沿检测
//边沿检测
assign pluse_b=a_ff3^a_ff2;
endmodule
测试平台
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/03/08 10:45:00
// Design Name:
// Module Name: test_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module test_tb(
);
logic clka;
logic clkb;
logic pluse_a;
logic pluse_b;
logic wide_a;
logic rst;
logic [31:0] cnt;
//
initial begin
clka=0;
forever begin
#5 clka=~clka;
end
end
//
initial
begin
clkb=0;
forever begin
#17 clkb=~clkb;
end
end
//rst
initial
begin
rst=1;
#50
rst=0;
end
always_ff@(posedge clka,posedge rst)
if(rst)
cnt<=0;
else
cnt<=cnt+1;
//pluse_a
always_ff@(posedge clka,posedge rst)
if(rst)
pluse_a<=0;
else if(cnt==13||cnt==23||cnt==31)
pluse_a<=1;
else
pluse_a<=0;
ont_bit_sync U1(.*
// input logic clka,
// input logic rst,
// input logic pluse_a,
// output logic wide_a
);
//
one_bit_sync_recv U2(.*
// input logic clkb,
// input logic rst,
// input logic wide_a,
// output logic pluse_b
);
endmodule
波形展示:
然而,该方法仍然存在一些问题:相邻两个输入脉冲的间隔至少是两个同步器时钟(clkb)周期才行,否则wide_a不够两个clkb周期,两个脉冲同步过来之后,中间的跳变沿就会消失,即下图中红框会消失,从而无法检测到边沿,导致最终无法区分pluse_a的两个脉冲,此时,需要采用握手信号的方法来进一步改进。