我们知道,在单比特信号的跨时钟域传输时,如果是从慢时钟域到快时钟域,那么我们可以采用打两拍的方式。然而,这个方法在快时钟域传输到慢时钟域时并不可行,因为如果快时钟域的该信号的宽度小于慢时钟的周期,那么慢时钟很可能无法采样到,如下图所示:
为了解决这个问题,一个自然的想法就是将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的两个脉冲,此时,需要采用握手信号的方法来进一步改进。
