新ちゃん 发表于 2021-1-20 10:04:19

Glitch Free时钟切换技术

本帖最后由 新ちゃん 于 2021-1-20 10:03 编辑

我不生产知识,我只是信息的搬运工,我期望可以做到的,尽量保持信息的正确性和权威性
多频时钟被用于芯片越来越多,特别是在通信领域,通常会在芯片运行过程中进行时钟切换,芯片中有两个时钟源,通过内部逻辑控制多路复用器来实现时钟源切换。本文将会介绍两种时钟切换方法,分别对应两种情况,第一种时两个时钟源的频率呈倍数关系,第二种是两个时钟源完全没有关系,异步时钟。
两个时钟的频率可能完全无关或者呈倍数关系,所以如果采用直接切换的方法,例如assign outclk = sel? clk0: clk1;上面这个写法太烂了。。。
肯定会产生毛刺,这对整个系统是很危险的,因为有些寄存器可能会捕获到时钟沿其他没捕获到,造成系统的不稳定。下面是使用AND-OR型多路复用器逻辑进行简单的时钟切换。

可以看出,当SELECT信号改变时,如果当前时钟源正好处于高电平,这样切换则引起了毛刺。
assign outclk = (clk1 & select) | (~select & clk0);仿真结果如图,显而易见。

避免毛刺的方法继续往下看,下图针对的是两个时钟源频率成倍数关系。在每个时钟源的选择路径中插入一个下降沿触发的D触发器,这样可以保证上面的情况被避免,确保在切换时钟源时,即使任意时钟处于高电平,也不会引起输出的变换,时钟源切换时,这个反馈能保证一个时钟被完全取消选择后,输出传播另一个时钟,从而避免产生任何毛刺。
这个电路有三个时序路径需要考虑,SELECT到两个触发器的任何一个,DFF0到DFF1,DFF1到DFF0,这三条路径上的输入信号与时钟边沿同时发生变化,都可能会引起亚稳态,所以需要将触发器的触发边沿和SELECT信号的变换边沿分开,这可以通过时序约束来实现,因为这两个时钟是呈倍数的关系。

芯片在启动时,两个触发器都应该处于0状态。
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);
仿真结果同样显而易见。
第二种方法是针对两个异步时钟源的切换,这个方法是在第一种方法的基础上,在选择路径上再插入一个上升沿触发D触发器,这是为了针对对两个异步时钟源产生的反馈信号以及异步信号SELECT,对选择信号进行同步处理,这样即使是两个异步的时钟源进行切换,也可以避免亚稳态的产生。
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);
页: [1]
查看完整版本: Glitch Free时钟切换技术