全局同步电路
电路中,所有受时钟控制的单元(触发器、寄存器),全部由一个统一的全局时钟控制。
优点:
- 在同步设计中,EDA工具可以保证电路系统的时序收敛,有效避免了电路设计中竞争与冒险现象。
- 由于触发器只有在时钟边缘才能改变取值,很大限度地减少了整个电路受毛刺和噪声的影响的可能。
缺点:
-
时钟偏斜(clock skew) -
时钟抖动(clock jitter) -
时钟树综合,需要加入大量的延迟单元,使得电路的面积和功耗大大增加。
个人理解:单纯的fpga开发工程师,上述缺点是不可避免的,毕竟fpga厂商就是这么设计的,只能在设计中注意到这些缺点,即可。
全局异步电路
全局异步设计跟同步设计最大的不同就是他的电路中的数据传输可以在任何时候发生,电路中没有一个全局或者局部的控制时钟。
由于时钟不同,则两个DFF则相对独立。 优点:
- 模块化特性突出
- 对信号的延迟不敏感
- 没有时钟偏斜问题
- 有潜在的高性能特性
- 好的电磁兼容性
- 具有低功耗的特性
缺点:
- 设计复杂
- 缺少相应EDA工具支持
- 大规模集成电路设计中,应避险异步电路设计
同步时钟包括:板载晶振时钟和其由内部锁相环所分频或倍频的时钟。否则,就是异步时钟。
亚稳态
亚稳态定义 触发器无法在某个规定时间段达到一个可确认的状态。
个人理解: 在”时序收敛与约束“中存在一个参数“Tsu”(setup time ,建立时间)和“Thold”(holding time,保持时间),Tsu这个参数的物理意义是,数据流到达DFF的D端口的时间与DFF的时钟触发沿之间的差值,必须要大于Tsu。Thold这个参数的物理意义是,数据在DFF的时钟触发沿必须保持大于Thold时间。若上述两个参数条件不满足,则会出现亚稳态现象。
当一个触发器进入亚稳态时,既无法预测该电平的输出电平,也无法预测何时输出才能稳定在某个正确的电平。
在这个期间,触发器输出一些中间级电平,或者可能处于振荡状态,并且这种无用的输出电平可以沿信号通道上的各个触发器级联传播下去。
亚稳态不能从根本上消除,但可以通过采取一定的措施,使其对电路造成的影响降低。 关于亚稳态性能公式: 所以就有了跨时钟域电路的第一个思想电平同步器
双锁存器电平同步器
为了避免上节所述的亚稳态问题,就应当使参数MTBF竟可能的大,通常采用的方法是双锁存器法,即在一个信号进入另一个时钟域之前,将该信号用两个锁存器连续锁存两次,最后的得到的采样结果就可以消除亚稳态问题。 在学习FPGA时,基本上最先接触的通信协议是UART。而UART的接收数据线,是异步数据线,所以在进入接收数据处理模块之前,均会采用打两拍的方式减少亚稳态,使用打过两拍的数据流进行下一步处理。
reg [1:0] r_rxd_sync;
always@(posedge i_clk)
begin
r_rxd_sync[0] <= i_rxd_bus;
r_rxd_sync[1] <= r_rxd_sync[0];
end
优点:
- 设计结构简单、易于实现
缺点:
- 增加了两级触发器延迟,如果对于速率要求很高。
- 当快时钟域到慢时钟域时,易造成慢时钟采样丢失(来不及采样)
故双锁存器同步法常应用于慢时钟域转到快时钟域。 本人是还处于菜鸟阶段,所参与的项目对于时钟还不是这么严苛,所以对于慢时钟域到快时钟域的数据信号均采用双锁存器同步法。(比如低速串行接口通信的速率均远远低于FPGA板载时钟)。
单bit信号的跨时钟域传输
边沿检测同步器
边沿检测同步器电路,应用在慢速向快速时钟传递过程中,可以输出输入脉冲信号的上升沿,也可以输出它的下降沿,作为输出脉冲信号。 慢时钟域的一个周期脉冲信号(图中脉冲信号应该只占据慢时钟域的一个周期)往往会在快时钟域占据多个周期。直接使用这样的信号,往往就会与自己想要描述的电路功能严重不符。所以快时钟域的脉冲信号也应该只占据一个周期,所以即边沿检测同步器。 限制:
- 输入信号必须保持两个接收时钟周期宽度
- 低频时钟域向高频时钟域传输
RTL:
`timescale 1ns / 1ns
module DectEdgeSlow2Fast(
input i_clk2, //Fast clock
input i_rst_n,
input i_slow_data_go,
output o_fast_data_pedge_go,
output o_fast_data_nedge_go
);
reg [1:0] r_slow_data_sync;
always @(posedge i_clk2 or negedge i_rst_n)
begin
if(!i_rst_n)
r_slow_data_sync <= #1 2'd0;
else
r_slow_data_sync <= #1 {r_slow_data_sync[0],i_slow_data_go};
end
assign o_fast_data_pedge_go = r_slow_data_sync == 2'b01;
assign o_fast_data_nedge_go = r_slow_data_sync == 2'b10;
endmodule
TestBench:
`timescale 1ns / 1ns
`define slow_clk_period 50 //clk freq = 20Mhz
`define fast_clk_period 20 //clk freq = 50Mhz
module DectEdgeSlow2Fasttb;
reg fast_clk;
reg i_rst_n;
reg i_slow_data_go;
wire o_fast_data_pedge_go;
wire o_fast_data_nedge_go;
initial
begin
i_slow_data_go = 0;
i_rst_n = 0;
#(`slow_clk_period * 2 +1);
i_rst_n = 1;
#(`slow_clk_period * 5);
i_slow_data_go = 1;
#(`slow_clk_period);
i_slow_data_go = 0;
#(`slow_clk_period * 10);
$stop;
end
initial fast_clk = 1;
always#(`fast_clk_period / 2) fast_clk = ~fast_clk;
DectEdgeSlow2Fast u_DectEdgeSlow2Fast(
.i_clk2 ( fast_clk ),
.i_rst_n ( i_rst_n ),
.i_slow_data_go ( i_slow_data_go ),
.o_fast_data_pedge_go ( o_fast_data_pedge_go ),
.o_fast_data_nedge_go ( o_fast_data_nedge_go )
);
endmodule
wave 由上图可以得出结论,慢时钟域中单脉冲信号的长度是50ns(慢时钟的一个周期,须大于接收周期的两倍或以上),在其进入快时钟域中,无论是上升沿还是下降沿检测,脉冲均为快时钟的一个周期。达到了符合的要求!!!
脉冲同步器:
限制:
- 同步单脉冲脉冲信号。
- 输入的脉冲时间距离必须保持两个接收时钟周期以上。
- 高频时钟域向低频时钟域传输
RTL:
`timescale 1ns/1ns
module DectEdgeFast2Slow(
input i_slow_clk,
input i_rst_n,
input i_fast_data_go,
output o_slow_data_go
);
reg [2:0] r_fast_data_sync;
always @(posedge i_slow_clk or negedge i_rst_n)
begin
if(!i_rst_n)
r_fast_data_sync <= #1 2'd0;
else
r_fast_data_sync <= #1 {r_fast_data_sync[1:0],i_fast_data_go};
end
assign o_slow_data_go = r_fast_data_sync[2] ^ r_fast_data_sync[1];
endmodule
TestBench:
`timescale 1ns/1ns
`define slow_clk_period 50 //clk freq = 20Mhz
`define fast_clk_period 20 //clk freq = 50Mhz
module DectEdgeFast2Slowtb;
reg i_slow_clk;
reg i_fast_clk;
reg i_rst_n;
reg i_fast_data_go;
reg r_fast_data_tog;
wire o_slow_data_go;
initial
begin
i_slow_clk = 1;
i_fast_clk = 1;
end
always #(`slow_clk_period / 2) i_slow_clk = ~i_slow_clk;
always #(`fast_clk_period / 2) i_fast_clk = ~i_fast_clk;
//TFF :T触发器
always @(posedge i_fast_clk or negedge i_rst_n)
begin
if(!i_rst_n)
r_fast_data_tog <= 1'b0;
else
r_fast_data_tog <= i_fast_data_go ? ~r_fast_data_tog : r_fast_data_tog;
end
initial
begin
i_fast_data_go = 0;
i_rst_n = 0;
#(`slow_clk_period * 2 +1);
i_rst_n = 1;
#(`slow_clk_period * 5);
i_fast_data_go = 1;
#(`fast_clk_period);
i_fast_data_go = 0;
#(`slow_clk_period * 2);
i_fast_data_go = 1;
#(`fast_clk_period);
i_fast_data_go = 0;
#(`slow_clk_period * 10);
$stop;
end
DectEdgeFast2Slow u_DectEdgeFast2Slow(
.i_slow_clk ( i_slow_clk ),
.i_rst_n ( i_rst_n ),
.i_fast_data_go ( r_fast_data_tog ),
.o_slow_data_go ( o_slow_data_go )
);
endmodule
Wave: 由于我还未在实际用应用到快时钟域数据到慢时钟域的项目,所以对这一部分并没有什么见解,代码也仅仅是根据电路图和波形进行编写,等有了项目经历,在对这一部分加以阐述。 本文的EDA平台是Diamond 12.0 本文的仿真平台是Diamond Modelsim 代码文件下载地址: https://download.csdn.net/download/ZipingPan/21854466.
总结
上文,在实际的工程中,使用的很多。本文中参考的是邸志雄老师所授课程,注重版权,侵删。 本文长期更新,如果你有好的想法和建议,欢迎在本文底部留言。另外也欢迎其他Verilog语言学习者与我共同交流,有任何疑问可以到本博客“评论专区”提出,我必知无不言,言无不尽。 日期:2021-9-2; 网址: https://blog.csdn.net/ZipingPan/article/details/120064729.
|