在通信领域当中,经常会在芯片运行过程当中进行时钟切换,特别是当芯片内部中有两个时钟源时,往往通过内部逻辑控制多路复用器来实现时钟源的切换。

时钟切换的分类

   第一种:第一种时两个时钟源的频率呈倍数关系;

   第二种:两个时钟源完全没有关系,异步时钟。

解决方法

   当两个时钟可能完全无关,也可能成倍数关系。当听到要进行时钟切换时,第一个想到的语法就是三目运算。完全合乎逻辑。但是在网上查阅资料的时候,发现原来是最烂的一种设计。

     1 assign outclk = sel? clk0: clk1; 

  写法不入眼……而且这样写的话,考虑的实际工程的问题太少了。肯定会产生毛刺,对搭建的整个系统是非常危险的,因为有些寄存器可能会捕获到时钟沿其他没捕获到,造成系统的不稳定。在此写法上继续升级。使用AND-OR型多路复用器逻辑进行简单的时钟切换。如下图所示:

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

 

 

 

 

 

从图中可以看出,如果当Select信号发生改变时,信号源正好处于高电平的时刻,那么就会产生毛刺。从而影响后续的电路。仿真一下电路可以看出来效果。实现的代码:

 

  

 1 // *********************************************************************************
 2 // Project Name : 
 3 // weixin       : li15226499835
 4 // Website      : https://www.cnblogs.com/lgy-gdeu/
 5 // Create Time  : 2020// 
 6 // File Name    : .v
 7 // Module Name  : 
 8 // Abstract     :
 9 // editor        : sublime text 3
10 // *********************************************************************************
11 // Modification History:
12 // Date         By              Version                 Change Description
13 // -----------------------------------------------------------------------
14 // 2020//          Liguoyong           1.0                     Original
15 //  
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 module  first_glitch_free(
19     //system signals
20     input               wire            sclk    ,
21     input                wire            rst_n    ,
22     //others
23     input                wire             clk_1    , 
24     input                wire             clk_2    ,
25     input               wire            select  , 
26     output              wire            out_clk
27     
28 
29 );
30 
31 //=============================================================================
32 //****************************     Main Code    *******************************
33 //=============================================================================
34 
35 assign     out_clk  =  (select & sclk)|(~select & clk_2);
36 
37     
38 endmodule

 

tb测试的激励文件:

 1 // *********************************************************************************
 2 // Project Name : 
 3 // weixin       : li15226499835
 4 // Website      : https://www.cnblogs.com/lgy-gdeu/
 5 // Create Time  : 2020// 
 6 // File Name    : .v
 7 // Module Name  : 
 8 // Abstract     :
 9 // editor        : sublime text 3
10 // *********************************************************************************
11 // Modification History:
12 // Date         By              Version                 Change Description
13 // -----------------------------------------------------------------------
14 // 2020//          Liguoyong           1.0                     Original
15 //  
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 
19 module first_glitch_free_tb;
20 
21 reg             sclk        ;
22 reg             tb_clk_1    ;
23 reg             tb_clk_2    ;
24 reg             tb_rst_n    ;
25 reg             tb_select   ;
26 wire            tb_out_clk  ;
27 
28 initial begin
29     tb_rst_n   =    0;
30     sclk       =    1;
31     #100
32     tb_rst_n   =    1;
33     tb_select  =    0;
34     #487
35     tb_select  =    1;
36     #2000
37     $finish;
38 end    
39 
40 always   #10  sclk   =  ~sclk ;
41 
42 
43 //=============================================================================
44 //****************************     Main Code    *******************************
45 //=============================================================================
46 
47 
48 always  @(posedge sclk or negedge tb_rst_n )begin
49     if(!tb_rst_n)
50         tb_clk_1 <= 0;
51     else 
52         tb_clk_1 <= ~tb_clk_1 ;
53 end
54 
55 always @(posedge tb_clk_1 or negedge tb_rst_n)begin
56     if(!tb_rst_n)
57         tb_clk_2 <=  0;
58     else 
59         tb_clk_2 <= ~tb_clk_2;        
60 end
61 wire        tb_clk_3 ;
62 assign     tb_clk_3 = ~tb_clk_2;
63 //例化
64 first_glitch_free first_glitch_free_inst(
65     //system signals
66     .sclk                   (sclk    )    ,
67     .clk_1                  (tb_clk_1)    , 
68     .clk_2                  (tb_clk_3)    ,
69     .rst_n                  (tb_rst_n)    ,
70     //output
71     .select                  (tb_select), 
72     .out_clk                 (tb_out_clk)
73     
74 
75 );
76 
77 endmodule

 仿真图:

 

 

 

 

 

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

 

 

 

 

 

 

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

代码:

  

 1 // *********************************************************************************
 2 // Project Name : 
 3 // weixin       : li15226499835
 4 // Website      : https://www.cnblogs.com/lgy-gdeu/
 5 // Create Time  : 2020// 
 6 // File Name    : .v
 7 // Module Name  : 
 8 // Abstract     :
 9 // editor        : sublime text 3
10 // *********************************************************************************
11 // Modification History:
12 // Date         By              Version                 Change Description
13 // -----------------------------------------------------------------------
14 // 2020//          Liguoyong           1.0                     Original
15 //  
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 module  first_glitch_free(
19     //system signals
20     input               wire            sclk    ,
21     input                wire            rst_n    ,
22     //others
23     input                wire             clk_1    , 
24     input                wire             clk_2    ,
25     input               wire            select  , 
26     output              wire            out_clk
27     
28 
29 );
30 //=============================================================================
31 //****************************     Main Code    *******************************
32 //=============================================================================
33 reg                    out_clk1;
34 reg                 out_clk2;
35 
36 //=============================================================================
37 //****************************     Main Code    *******************************
38 //=============================================================================
39 
40 //assign     out_clk  =  (select & sclk)|(~select & clk_2);
41 //out_clk1
42 always  @(posedge sclk or negedge rst_n)begin
43     if(!rst_n)
44         out_clk1    <=   0;
45     else 
46         out_clk1    <=  ~out_clk2 & ~select;        
47 end
48  //out_clk2
49  always @(posedge sclk or negedge rst_n)begin
50      if(!rst_n)
51          out_clk2    <=   0;
52      else 
53          out_clk2    <=  select&~out_clk1    ;    
54  end
55 
56 //out_clk
57 assign     out_clk  =  (clk_2&out_clk2)|(clk_1&out_clk1);
58 
59 
60 endmodule
View Code

tb测试文件

 1 // *********************************************************************************
 2 // Project Name : 
 3 // weixin       : li15226499835
 4 // Website      : https://www.cnblogs.com/lgy-gdeu/
 5 // Create Time  : 2020// 
 6 // File Name    : .v
 7 // Module Name  : 
 8 // Abstract     :
 9 // editor        : sublime text 3
10 // *********************************************************************************
11 // Modification History:
12 // Date         By              Version                 Change Description
13 // -----------------------------------------------------------------------
14 // 2020//          Liguoyong           1.0                     Original
15 //  
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 
19 module first_glitch_free_tb;
20 
21 reg             sclk        ;
22 reg             tb_clk_1    ;
23 reg             tb_clk_2    ;
24 reg             tb_rst_n    ;
25 reg             tb_select   ;
26 wire            tb_out_clk  ;
27 wire            tb_clk_3    ;
28 initial begin
29     tb_rst_n   =    0;
30     sclk       =    1;
31     #100
32     tb_rst_n   =    1;
33     tb_select  =    0;
34     #487
35     tb_select  =    1;
36     #2000
37     $finish;
38 end    
39 
40 always   #10  sclk   =  ~sclk ;
41 
42 //=============================================================================
43 //****************************     Main Code    *******************************
44 //=============================================================================
45 
46 
47 always  @(posedge sclk or negedge tb_rst_n )begin
48     if(!tb_rst_n)
49         tb_clk_1 <= 0;
50     else 
51         tb_clk_1 <= ~tb_clk_1 ;
52 end
53 
54 always @(posedge tb_clk_1 or negedge tb_rst_n)begin
55     if(!tb_rst_n)
56         tb_clk_2 <=  0;
57     else 
58         tb_clk_2 <= ~tb_clk_2;        
59 end
60 
61 
62 assign     tb_clk_3 = ~tb_clk_2;
63 //例化
64 first_glitch_free first_glitch_free_inst(
65     //system signals
66     .sclk                   (sclk    )    ,
67     .clk_1                  (tb_clk_1)    , 
68     .clk_2                  (tb_clk_2)    ,
69     .rst_n                  (tb_rst_n)    ,
70     //output
71     .select                  (tb_select) , 
72     .out_clk                 (tb_out_clk)
73     
74 
75 );
76 
77 endmodule
View Code

仿真图形:

 

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

 

 

 

仿真代码:

 1 // *********************************************************************************
 2 // Project Name : 
 3 // weixin       : li15226499835
 4 // Website      : https://www.cnblogs.com/lgy-gdeu/
 5 // Create Time  : 2020// 
 6 // File Name    : .v
 7 // Module Name  : 
 8 // Abstract     :
 9 // editor        : sublime text 3
10 // *********************************************************************************
11 // Modification History:
12 // Date         By              Version                 Change Description
13 // -----------------------------------------------------------------------
14 // 2020//          Liguoyong           1.0                     Original
15 //  
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 module  first_glitch_free(
19     //system signals
20     input               wire            sclk    ,
21     input                wire            rst_n    ,
22     //others
23     input                wire             clk_1    , 
24     input                wire             clk_2    ,
25     input               wire            select  , 
26     output              wire            out_clk
27     
28 
29 );
30 //=============================================================================
31 //****************************     Main Code    *******************************
32 //=============================================================================
33 reg                    out_clk1;
34 reg                 out_clk1_r;
35 reg                 out_clk2;
36 reg                 out_clk2_r;
37 
38 //=============================================================================
39 //****************************     Main Code    *******************************
40 //=============================================================================
41 
42 //assign     out_clk  =  (select & sclk)|(~select & clk_2);
43 //out_clk1
44 always  @(posedge sclk or negedge rst_n)begin
45     if(!rst_n)
46         out_clk1    <=   0;
47     else 
48         out_clk1    <=  ~out_clk2 & ~select;        
49 end
50 
51 //out_clk1_r
52 always @(posedge sclk or negedge rst_n)begin
53     if(!rst_n)
54         out_clk1_r  <=   0;
55     else 
56         out_clk1_r  <= out_clk1;    
57 end
58 
59  //out_clk2
60  always @(posedge sclk or negedge rst_n)begin
61      if(!rst_n)
62          out_clk2    <=   0;
63      else 
64          out_clk2    <=  select&~out_clk1    ;    
65  end
66 
67 //out_clk2_r
68 always @(posedge sclk or negedge rst_n)begin
69     if(!rst_n)
70         out_clk2_r   <=   0;
71     else 
72         out_clk2_r   <=  out_clk2;    
73 end 
74 
75 //out_clk
76 assign     out_clk  =  (clk_2&out_clk2_r)|(clk_1&out_clk1_r);
77 
78 
79 endmodule
View Code

tb激励代码

 1 // *********************************************************************************
 2 // Project Name : 
 3 // weixin       : li15226499835
 4 // Website      : https://www.cnblogs.com/lgy-gdeu/
 5 // Create Time  : 2020// 
 6 // File Name    : .v
 7 // Module Name  : 
 8 // Abstract     :
 9 // editor        : sublime text 3
10 // *********************************************************************************
11 // Modification History:
12 // Date         By              Version                 Change Description
13 // -----------------------------------------------------------------------
14 // 2020//          Liguoyong           1.0                     Original
15 //  
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 
19 module first_glitch_free_tb;
20 
21 reg             sclk        ;
22 reg             tb_clk_1    ;
23 reg             tb_clk_2    ;
24 reg             tb_rst_n    ;
25 reg             tb_select   ;
26 wire            tb_out_clk  ;
27 wire            tb_clk_3    ;
28 initial begin
29     tb_rst_n   =    0;
30     sclk       =    1;
31     #100
32     tb_rst_n   =    1;
33     tb_select  =    0;
34     #487
35     tb_select  =    1;
36     #2000
37     $finish;
38 end    
39 
40 always   #10  sclk   =  ~sclk ;
41 
42 //=============================================================================
43 //****************************     Main Code    *******************************
44 //=============================================================================
45 
46 
47 always  @(posedge sclk or negedge tb_rst_n )begin
48     if(!tb_rst_n)
49         tb_clk_1 <= 0;
50     else 
51         tb_clk_1 <= ~tb_clk_1 ;
52 end
53 
54 always @(posedge tb_clk_1 or negedge tb_rst_n)begin
55     if(!tb_rst_n)
56         tb_clk_2 <=  0;
57     else 
58         tb_clk_2 <= ~tb_clk_2;        
59 end
60 
61 
62 assign     tb_clk_3 = ~tb_clk_2;
63 //例化
64 first_glitch_free first_glitch_free_inst(
65     //system signals
66     .sclk                   (sclk    )    ,
67     .clk_1                  (tb_clk_1)    , 
68     .clk_2                  (tb_clk_2)    ,
69     .rst_n                  (tb_rst_n)    ,
70     //output
71     .select                  (tb_select) , 
72     .out_clk                 (tb_out_clk)
73     
74 
75 );
76 
77 endmodule
View Code

仿真波形

 

 

参考文献:https://www.eetimes.com/techniques-to-make-clock-switching-glitch-free/

多多指教。点头致谢!