在通信领域当中,经常会在芯片运行过程当中进行时钟切换,特别是当芯片内部中有两个时钟源时,往往通过内部逻辑控制多路复用器来实现时钟源的切换。
时钟切换的分类:
第一种:第一种时两个时钟源的频率呈倍数关系;
第二种:两个时钟源完全没有关系,异步时钟。
解决方法:
当两个时钟可能完全无关,也可能成倍数关系。当听到要进行时钟切换时,第一个想到的语法就是三目运算。完全合乎逻辑。但是在网上查阅资料的时候,发现原来是最烂的一种设计。
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
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
仿真图形:
第二种方法是针对两个异步时钟源的切换,这个方法是在第一种方法的基础上,在选择路径上再插入一个上升沿触发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
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
仿真波形
参考文献:https://www.eetimes.com/techniques-to-make-clock-switching-glitch-free/
多多指教。点头致谢!