Glitch Free时钟切换技术

Glitch Free时钟切换技术

我不生产知识,我只是信息的搬运工,我期望可以做到的,尽量保持信息的正确性和权威性

多频时钟被用于芯片越来越多,特别是在通信领域,通常会在芯片运行过程中进行时钟切换,芯片中有两个时钟源,通过内部逻辑控制多路复用器来实现时钟源切换。本文将会介绍两种时钟切换方法,分别对应两种情况,第一种时两个时钟源的频率呈倍数关系,第二种是两个时钟源完全没有关系,异步时钟。

两个时钟的频率可能完全无关或者呈倍数关系,所以如果采用直接切换的方法,例如

1
assign 	outclk = sel? clk0: clk1;

上面这个写法太烂了。。。

肯定会产生毛刺,这对整个系统是很危险的,因为有些寄存器可能会捕获到时钟沿其他没捕获到,造成系统的不稳定。

下面是使用AND-OR型多路复用器逻辑进行简单的时钟切换。

image

可以看出,当SELECT信号改变时,如果当前时钟源正好处于高电平,这样切换则引起了毛刺。

1
assign outclk = (clk1 & select) | (~select & clk0);

image

image

仿真结果如图,显而易见。

避免毛刺的方法继续往下看,下图针对的是两个时钟源频率成倍数关系。在每个时钟源的选择路径中插入一个下降沿触发的D触发器,这样可以保证上面的情况被避免,确保在切换时钟源时,即使任意时钟处于高电平,也不会引起输出的变换,时钟源切换时,这个反馈能保证一个时钟被完全取消选择后,输出传播另一个时钟,从而避免产生任何毛刺。

这个电路有三个时序路径需要考虑,SELECT到两个触发器的任何一个,DFF0到DFF1,DFF1到DFF0,这三条路径上的输入信号与时钟边沿同时发生变化,都可能会引起亚稳态,所以需要将触发器的触发边沿和SELECT信号的变换边沿分开,这可以通过时序约束来实现,因为这两个时钟是呈倍数的关系。

image

芯片在启动时,两个触发器都应该处于0状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
reg     out1;
reg out0;
always @(negedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out1 <= 0;
end
else begin
out1 <= ~out0 & select;
end
end


always @(negedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out0 <= 0;
end
else begin
out0 <= ~select & ~out1;
end
end

assign outclk = (out1 & clk1) | (out0 & clk0);

image

image

仿真结果同样显而易见。

第二种方法是针对两个异步时钟源的切换,这个方法是在第一种方法的基础上,在选择路径上再插入一个上升沿触发D触发器,这是为了针对对两个异步时钟源产生的反馈信号以及异步信号SELECT,对选择信号进行同步处理,这样即使是两个异步的时钟源进行切换,也可以避免亚稳态的产生。

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
reg     out_r1;
reg out1;
reg out_r0;
reg out0;

always @(posedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out_r1 <= 0;
end
else begin
out_r1 <= ~out0 & select;
end
end

always @(negedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out1 <= 0;
end
else begin
out1 <= out_r1;
end
end

always @(posedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out_r0 <= 0;
end
else begin
out_r0 <= ~select & ~out1;
end
end

always @(negedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out0 <= 0;
end
else begin
out0 <= out_r0;
end
end

assign outclk = (out1 & clk1) | (out0 & clk0);

image

image

仿真结果显而易见。

多个时钟源切换可以根据本文方法进行拓展。

Reference

https://www.eetimes.com/document.asp?doc_id=1202359

image

image

NingHeChuan wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!