文章目录
前言
学习打卡第五天,继续学习,每天进步一点点!
上一节介绍了跨时钟域传输的方法,从快时钟域到慢时钟域有脉冲同步器,但是该方法对输入信号要求较高,所以继续介绍跨时钟域传输的其他方法
一、单bit信号跨时钟域传输
1、双锁存器法/电平同步器
优点:结构简单、易于实现、面积消耗较少
缺点:增加了两个触发器的延时
条件:适合于慢时钟域到快时钟域,都可以
假设第一级触发器不满足其建立时间,产生亚稳态,在下一个时钟沿到来之前,它的亚稳态在一段时间后必须稳定下来,且满足第二级触发器的建立时间,因此第二级触发器就不会发生亚稳态。
三级以及更多级可以使亚稳态发生的概率降低更多,但是电路延时也会增加
该方法只是降低发生概率,不能从根本上进行去除亚稳态
同步器有效条件:
- 第一级触发器进入亚稳态的恢复时间 + 第二级触发器建立时间 <= 时钟周期
- 输入脉冲宽度 > 同步时钟周期 + 第一级触发器的保持时间
- 更保险的说法:脉冲宽度 > 两倍同步时钟周期
2、边沿检测同步器(慢时钟域到快时钟域)
如果只是边沿检测,只需要一级触发器即可,由于这里介绍的是跨时钟域传输,所以前面加了一级/两级同步器。
边沿检测原因:慢时钟的一个周期信号在快时钟看来就是几个信号周期,所以检测边沿是最合理的,检测边沿的上升或者下降。
检测上升沿
、下降沿
、双边沿
,并发出相应的脉冲。
适用条件: 输入数据宽度 > 同步时钟周期+Th(最安全的是大于两个同步时钟周期)
2.1 上升沿检测
下面这个图是out = a_r & ~a_rr
;按道理输出脉冲应该滞后一个周期,不是下面波形图画的那样。
下面波形图应该是out = a & ~a_r
;才是同步输出。
module pos(
input clk,
input a,
input rst_n,
output o_pos
);
reg a_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
a_r <= 0;
else
a_r <= a;
end
assign o_pos = a & ~a_r;
endmodule
2.2 下降沿检测
module neg(
input clk,
input a,
input rst_n,
output o_neg
);
reg a_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
a_r <= 0;
else
a_r <= a;
end
assign o_pos = ~a & a_r;
endmodule
2.3 边沿检测同步器
前面两级用于同步,后一级用于边沿检测
module delay_clap(
input clk1,
input clk2,
input rst_n,
input sig,
output sig_rise,
output sig_down,
output sig_dual,
output sig_out
);
reg [2:0] sig_r; //3级缓存
always@(posedge clk2 or negedge rst_n)begin //注意这里是clk2,目标时钟
if(!rst_n)
sig_r <= 0;
else
sig_r[1:0] <= {sir_r[0], sig};
end
assign sig_rise = sig_r[1] & !sig_r[2];
assign sig_down = !sig_r[1] & sig_r[2];
assign sig_dual = sig_r[1] ^ sig_r[2]; //双边沿检测,是同步前和同步后的信号进行异或
assign sig_out = sig[1]; //信号直接输出
endmodule
3、脉冲同步器/结绳法(快时钟域到慢时钟域)
在慢时钟域去采样快时钟域信号,可能会采样不到,所以采用翻转电路
将原时钟域下的脉冲信号,转化为电平信号(异或门或选择器),再进行同步,同步之后,再把新时钟域下的电平信号转化为脉冲信号(边沿检测的原理)。这样就从快时钟域取出一个单时钟宽度脉冲,在慢时钟域建立新的单时钟宽度脉冲。
- 输入脉冲时间间隔必须大于两个接收时钟周期,否则新的脉冲会变宽,就不再是单时钟宽度脉冲了。
- 如果输入脉冲相互过近,则新时钟域中的输出脉冲也紧密相邻,结果是输出脉冲宽度比一个时钟周期宽。
翻转电路
:将快时钟域前后间隔多个周期的信号进行标定,形成了toggle的波形
优点:可以解决快时钟域到慢时钟域的信号传输问题,适用范围较广
缺点:较为复杂,效率不是太高
module pulse_detect(
input clk1,
input clk2,
input rst_n,
input data_in,
output dataout
);
reg [3:0] data_r;
always@(posedge clk1 or negedge rst_n)begin //注意这里为clk1
if(!rst_n)
data_r[0] <= 0;
else
//两种写法,选择器和异或门
data_r[0] <= data_in ? ~data_r[0] : data_r[0];
data_r[0] <= data_in ^ data_r[0];
end
always@(posedge clk2 or negedge rst_n)begin //注意这里为clk2
if(!rst_n)
data_r[3:1] <= 0;
else
data_r[3:1] <= {data_r[2:1], data_r[0]};
end
assign dataout = data_r[3] ^ data_r[2];
endmodule
4、三种同步器比较
慢时钟域到快时钟域 | 快时钟域到慢时钟域 |
---|---|
只考虑亚稳态问题 | 考虑亚稳态问题,也要考虑慢时钟的采样速率问题(采样频率要高于信号最高频率的两倍) |
二、verilog手撕代码,展宽1bit信号为32bit
对1bit的脉冲信号进行展宽,转为32bit位宽,并产生有效信号
module zhankuan(
input clk,
input rst_n,
input pulse_in,
output reg pulse_out,
output p_flag
);
reg in_r,in_rr;
reg [4:0] cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
in_r<=1'b0;
in_rr<=1'b0;
end
else begin
in_r<=pulse_in;
in_rr<=in_r;
end
assign p_flag=(~in_rr)&in_r; //上升沿检测
always @(posedge clk or negedge rst_n)
if(!rst_n)
pulse_out<=1'b0;
else if(p_flag)
pulse_out<=1'b1;
else if(cnt==5'd31)
pulse_out<=1'b0;
else
pulse_out<=pulse_out;
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt<=5'b0;
else if(pulse_out==1'b1)
cnt<=(cnt==5'd31)?0:cnt+1'b1;
else
cnt<=cnt;
endmodule