设计一个单比特跨时钟域传输电路?从慢到快&从快到慢
Clock Domain Crossing (CDC) : 跨时钟域设计中,信号adat从aclk domain传播到bclk domain;aclk与bclk之间的频率,相位没有固定关系,为asynchronous异步关系的时钟。
分为单比特跨时钟域和多比特跨时钟域。
多比特跨时钟域:采用异步FIFO。
单比特跨时钟域:分为从慢到快,和从快到慢。
从慢到快:电平信号同步方法:一级寄存器产生亚稳态并经过自身后可以稳定输出的概率为70%~80%左右,第二级寄存器可以稳定输出的概率为99%左右,再后面改善就不明显了,所以数据进来后一般选择打两拍即可。
从快到慢:脉冲信号同步方法:快时钟域脉冲展宽+慢时钟域延迟打拍。注意:在快时钟域展宽的信号宽度必须是慢时钟域周期的1.5倍以上,须满足奈克斯特采样定理。
从慢到快的设计代码&激励&仿真波形
module CDC ( input clk_1 , input clk_2 , input rst_n , input in , output out ); //跨时钟域 单比特传输 从慢到快 //采用打两拍 即可采样 reg out_ff0 ; reg out_ff1 ; reg out_ff2 ; always@(posedge clk_1 or negedge rst_n) begin if(!rst_n) out_ff0<=1'b0; else out_ff0<=in; end always@(posedge clk_2 or negedge rst_n) begin if(!rst_n) begin out_ff1<=1'b0; out_ff2<=1'b0; end else begin out_ff1<=out_ff0; out_ff2<=out_ff1; end end assign out=out_ff2 ; endmodule
`timescale 1ns/1ns module tb_CDC(); reg clk_1 ; reg clk_2 ; reg rst_n ; reg in ; wire out ; initial begin clk_1<=1'b0; clk_2<=1'b0; rst_n<=1'b0; in<=1'b0; #20 rst_n<=1'b1; #15 in<=1'b1; #35 in<=1'b0; #300 in<=1'b1; #20 in<=1'b0; #450 in<=1'b1; #20 in<=1'b0; #250 in<=1'b1; #20 in<=1'b0; end always # 5 clk_2<=~clk_2 ; //快时钟域 always # 10 clk_1<=~clk_1 ; //慢时钟域 CDC CDC_inst ( .clk_1 (clk_1) , .clk_2 (clk_2) , .rst_n (rst_n) , .in (in ) , .out (out ) ); endmodule
从快到慢的设计代码&激励&仿真波形
module CDC ( input clk_1 , input clk_2 , input rst_n , input in , output out ); //跨时钟域 单比特传输 从快到慢 //先在快时钟域展宽 展宽为慢时钟域至少2个时钟周期 方便慢时钟采样 reg in_ff0 ; // 输入打一拍 reg in_ff1 ; // 输入打两拍 reg in_data ; // 展宽寄存 reg in_q1 ; // 反馈信号 取消展宽 //reg in_q2 ; reg out_ff1 ; //慢时钟域打一拍 reg out_ff2 ; //慢时钟域打两拍 wire in_pos ; //检测输入上升沿 表示一个脉冲输入 assign in_pos =in_ff0&&(~in_ff1); // 输入打两拍 检测输入上升沿 always@(posedge clk_1 or negedge rst_n) begin if(!rst_n) begin in_ff0<=1'b0; in_ff1<=1'b0; end else begin in_ff0<=in; in_ff1<=in_ff0; end end // 在快时钟域下 对脉冲信号展宽至反馈有效有效时拉低 always@(posedge clk_1 or negedge rst_n) begin if(!rst_n) in_data<=1'b0; else if(in_pos) in_data<=1'b1; else if(in_q1) in_data<=1'b0; end // 在慢时钟域下 对脉冲信号展宽采样 即打两拍 防止亚稳态产生 always@(posedge clk_2 or negedge rst_n) begin if(!rst_n) begin out_ff1<=1'b0; out_ff2<=1'b0; end else begin out_ff1<=in_data; out_ff2<=out_ff1; end end //在慢时钟域下 产生反馈信号 拉低展宽信号 always@(posedge clk_2 or negedge rst_n) begin if(!rst_n) begin in_q1<=1'b0; //in_q2<=1'b0; end else begin in_q1<=out_ff1; //采用in_q1 为反馈信号 输出为2个慢时钟周期 //in_q2<=in_q1; //采用in_q2 为反馈信号 输出为3个慢时钟周期 end end assign out=out_ff2 ; //得到输出 endmodule
`timescale 1ns/1ns module tb_CDC(); reg clk_1 ; reg clk_2 ; reg rst_n ; reg in ; wire out ; initial begin clk_1<=1'b0; clk_2<=1'b0; rst_n<=1'b0; in<=1'b0; #20 rst_n<=1'b1; #15 in<=1'b1; #35 in<=1'b0; #300 in<=1'b1; #20 in<=1'b0; #450 in<=1'b1; #20 in<=1'b0; #250 in<=1'b1; #20 in<=1'b0; end always # 5 clk_1<=~clk_1 ; //快时钟域 always # 10 clk_2<=~clk_2 ; //慢时钟域 CDC CDC_inst ( .clk_1 (clk_1) , .clk_2 (clk_2) , .rst_n (rst_n) , .in (in ) , .out (out ) ); endmodule
若有不对的地方,敬请指正,万分感谢。
参考资料: