无毛刺的时钟切换电路(Glitch-free clock switching circuit)设计(Verilog)

举报
李锐博恩 发表于 2021/07/15 04:00:33 2021/07/15
【摘要】 从秋招的经验来看,Verilog设计类的题目,如:奇偶分频,状态机,序列检测,波形产生,跨时钟域处理,门控时钟,同步FIFO,格雷码与二进制码转换,异步复位同步释放,时钟切换,异步FIFO等,其中最为复杂的恐怕属于时钟切换了吧。 无毛刺的时钟切换英文名叫:Glitch-free clock switching circuit,不要把 Clock Domain Convers...

从秋招的经验来看,Verilog设计类的题目,如:奇偶分频,状态机,序列检测,波形产生,跨时钟域处理,门控时钟,同步FIFO,格雷码与二进制码转换,异步复位同步释放,时钟切换,异步FIFO等,其中最为复杂的恐怕属于时钟切换了吧。

无毛刺的时钟切换英文名叫:Glitch-free clock switching circuit,不要把 Clock Domain Conversion当成了时钟切换,傻傻地设计了半天答非所问。

Clock Domain Conversion为跨时钟域传输问题,就是最常考也是经常听到的CDC问题(应该会有专门的总结)。

今天的主题是Glitch Free Clock Switching:

就像这样:

clk0和clk1是无关时钟,如何实现二者之间的一个无毛刺切换是接下来需要解决的问题?


先从最容易相当的设计说起:

可以使用纯组合逻辑来设计时钟切换电路,但是这种设计不可避免的产生毛刺:

如下,两种一个道理:

如何改进这种设计呢?

之前的博客也写过这个话题,今天仿真了下,用Verilog描述了下,确实有点意思?


相关时钟源的时钟切换电路:

从前面组合逻辑时钟切换电路的设计,我们得出的切换波形如下:

可见,会产生毛刺,而产生毛刺的原因在于sel信号改变的位置没有和需要切换的时钟对齐。

如何改进这种问题呢?

我们可以用当前时钟的下降沿来采样(sel与反馈的输出相与的结果),可以简单地理解为采样sel信号。具体的设计如下:

可以这么理解,如下图:

sel为0时,选择输出clk0,如上图,先对sel在时钟域clk0进行下降沿采样,得到sel_clk0,取反得到sel_clk0_n,这个信号与时钟clk0相与输出得到clkout0;

sel_clk0反馈到时钟域clk1的输入端,与sel相与之后,再经过clk1下降沿采样得到sel_clk1,这个信号与clk1想与得到输出clkout1;

clkout0与clkout1进行或运算得到输出clkout,这个时钟便是进行时钟切换后的时钟输出。

这样经过下降沿采样以及反馈就可以得到无毛刺的相关时钟切换电路。


对于无关时钟源的无毛刺时钟切换电路设计

上一部分讲了相关时钟源的无毛刺时钟切换,用的是下降沿采样sel信号从而达到去除毛刺的原理;

下面给出无关时钟源的无毛刺时钟切换方案:

如下图:

画出相关波形图:

sel为0时候,先取反得到seln,然后clk0时钟下上升沿采样seln_clk0_r1,之后下降沿采样得到seln_clk0_r2,这个信号与clk0相与得到clkout0;

seln_clk0_r2n反馈到时钟域clk1,与clk1相与,用clk1上升沿采样得到sel_clk1_r1,再用clk1下降沿采样得到sel_clk1_r2,这个信号与clk1相与得到输出clkout1;

最终的输出为clkout0与clkout1的或,即输出clkout为无毛刺的时钟切换波形。

对于无关时钟源的无毛刺时钟切换电路的设计,参考文章

无关时钟源的时钟切换电路设计:

设计的Verilog描述:


  
  1. module glitch_free (
  2. input clk0, // Clock
  3. input clk1,
  4. input select,
  5. input rst_n, // Asynchronous reset active low
  6. output clkout
  7. );
  8. wire mid_clk0;
  9. reg mid_clk0_r1, mid_clk0_r2, mid_clk0_r2n;
  10. wire mid_clk1;
  11. reg mid_clk1_r1, mid_clk1_r2, mid_clk1_r2n;
  12. assign mid_clk1 = select & mid_clk0_r2n;
  13. assign mid_clk0 = ~select & mid_clk1_r2n;
  14. //第一级触发器用上升沿采样,选择信号与反馈信号的与运算
  15. always@(posedge clk1 or negedge rst_n) begin
  16. if(~rst_n) mid_clk1_r1 <= 0;
  17. else mid_clk1_r1 <= mid_clk1;
  18. end
  19. //第二级触发器用下降沿采样
  20. always@(negedge clk1 or negedge rst_n) begin
  21. if(~rst_n) begin
  22. mid_clk1_r2 <= 0;
  23. mid_clk1_r2n <= 1;
  24. end
  25. else begin
  26. mid_clk1_r2 <= mid_clk1_r1;
  27. mid_clk1_r2n <= ~mid_clk1_r1;
  28. end
  29. end
  30. //第一级触发器用上升沿采样,选择信号与反馈信号的与运算
  31. always@(posedge clk0 or negedge rst_n) begin
  32. if(~rst_n) mid_clk0_r1 <= 0;
  33. else mid_clk0_r1 <= mid_clk0;
  34. end
  35. //第二级触发器用下降沿采样
  36. always@(negedge clk0 or negedge rst_n) begin
  37. if(~rst_n) begin
  38. mid_clk0_r2 <= 0;
  39. mid_clk0_r2n <= 1;
  40. end
  41. else begin
  42. mid_clk0_r2 <= mid_clk0_r1;
  43. mid_clk0_r2n <= ~mid_clk0_r1;
  44. end
  45. end
  46. wire mid_clk11, mid_clk00;
  47. assign mid_clk11 = clk1 & mid_clk1_r2;
  48. assign mid_clk00 = clk0 & mid_clk0_r2;
  49. assign clkout = mid_clk11 | mid_clk00;
  50. endmodule

Testbench文件:


  
  1. `timescale 1ns / 1ps
  2. //
  3. //
  4. module test_tb(
  5. );
  6. reg clk0, clk1;
  7. reg select;
  8. wire clkout;
  9. initial begin
  10. clk0 = 0;
  11. forever
  12. #2 clk0 = ~clk0;
  13. end
  14. initial begin
  15. clk1 = 0;
  16. forever
  17. #5 clk1 = ~clk1;
  18. end
  19. reg rst_n;
  20. reg in;
  21. initial begin
  22. select = 0;
  23. rst_n = 0;
  24. #5
  25. rst_n = 1;
  26. #30
  27. select = 1;
  28. #40
  29. select = 0;
  30. end
  31. glitch_free inst_glitch_free (.clk0(clk0), .clk1(clk1), .select(select), .rst_n(rst_n), .clkout(clkout));
  32. endmodule

仿真波形:

 

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/101107058

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。