一个时钟异步切换原理图

电子说

1.3w人已加入

描述

原理如下图(为了方便简洁,去掉了rst_n)

波形是这样的

时钟

代码就是根据电路图写的

 1 ///////////////////////////////////////////////////////////////////////////////////////////
 2 //  DATE    :   Wed Jun  6 23:31:57 CST 2012
 3 ///////////////////////////////////////////////////////////////////////////////////////////
 4 module clk_sw(
 5     input   wire    clk_a
 6 ,   input   wire    clk_b
 7 ,   input   wire    rst_n
 8 ,   input   wire    sel
 9 ,   output  wire    clk_o
10 );
11 ///////////////////////////////////////////////////////////////////////////////////////////
12 // variable declaration
13 reg     clk_a_en ;
14 reg     clk_b_en ;
15 ///////////////////////////////////////////////////////////////////////////////////////////
16 // logic
17 always @(posedge clk_a or negedge rst_n) begin
18     if(~rst_n)                          clk_a_en     <=  1'b0               ;
19     else                                clk_a_en     <=  ~sel & ~clk_b_en   ;
20 end
21 always @(posedge clk_b or negedge rst_n) begin
22     if(~rst_n)                          clk_b_en     <=  1'b0               ;
23     else                                clk_b_en     <=  sel  & ~clk_a_en   ;
24 end
25 assign  clk_o   =   (clk_a & clk_a_en) | (clk_b & clk_b_en) ;
26 ///////////////////////////////////////////////////////////////////////////////////////////
27 
28 endmodule   //          CREATED by poiu_elab@1207
29 
30 ///////////////////////////////////////////////////////////////////////////////////////////

testbench是这样的

 1 ///////////////////////////////////////////////////////////////////////////////////////////
 2 //  DATE    :   Wed Jun  6 23:42:58 CST 2012
 3 ///////////////////////////////////////////////////////////////////////////////////////////
 4 `define CLK_A_CYCLE   23
 5 `define CLK_B_CYCLE   47
 6 module tb();
 7 ///////////////////////////////////////////////////////////////////////////////////////////
 8 // variable declaration
 9 reg     clk_a   ;
10 reg     clk_b   ;
11 reg     rst_n   ;
12 reg     sel     ;
13 wire    clk_o   ;
14 ///////////////////////////////////////////////////////////////////////////////////////////
15 // stimulation generation
16 initial forever #(`CLK_A_CYCLE/2) clk_a = ~clk_a;
17 initial forever #(`CLK_B_CYCLE/2) clk_b = ~clk_b;
18 initial begin
19     rst_n           =   1'b0            ;
20     clk_a           =   1'b1            ;
21     clk_b           =   1'b1            ;
22     sel             =   1'b0            ;
23 #500;
24     rst_n           =   1'b1            ;
25 #500;
26 #({$random}%13+500);
27     sel             =   ~sel            ;
28 #({$random}%23+500);
29     sel             =   ~sel            ;
30 #({$random}%33+500);
31     sel             =   ~sel            ;
32 #({$random}%43+500);
33     sel             =   ~sel            ;
34 #({$random}%53+500);
35     sel             =   ~sel            ;
36 #({$random}%63+500);
37     sel             =   ~sel            ;
38 #({$random}%73+500);
39     sel             =   ~sel            ;
40 #({$random}%83+500);
41     sel             =   ~sel            ;
42 #({$random}%93+500);
43     sel             =   ~sel            ;
44 #({$random}%13+500);
45     sel             =   ~sel            ;
46 #({$random}%23+500);
47     sel             =   ~sel            ;
48 #({$random}%33+500);
49     sel             =   ~sel            ;
50 #({$random}%43+500);
51     sel             =   ~sel            ;
52 #({$random}%53+500);
53     sel             =   ~sel            ;
54 #({$random}%63+500);
55     sel             =   ~sel            ;
56 #({$random}%73+500);
57     sel             =   ~sel            ;
58 #({$random}%83+500);
59     sel             =   ~sel            ;
60 #({$random}%93+500);
61     sel             =   ~sel            ;
62 #5000;
63 $stop;
64 end
65 ///////////////////////////////////////////////////////////////////////////////////////////
66 // module instaniation
67 clk_sw u_clk_sw(
68     .clk_a  (   clk_a   )
69 ,   .clk_b  (   clk_b   )
70 ,   .rst_n  (   rst_n   )
71 ,   .sel    (   sel     )
72 ,   .clk_o  (   clk_o   )
73 );
74 ///////////////////////////////////////////////////////////////////////////////////////////
75 
76 endmodule   //          CREATED by poiu_elab@1207
77 
78 ///////////////////////////////////////////////////////////////////////////////////////////

这里的核心就是你的sel发生翻转的时候,首先肯定是在本时钟域内的clk_en会先变低(invalid),之后才会使得另外时钟域内的clk_en变高(valid),这时另外一个时钟域内的时钟才能和clk_en相与输出。

简而言之,比如一开始是clk_a有效,clk_out为clk_a,sel翻转后,clk_a_en在clk_a的时钟域内先关断(拉低),使得clk_out持续拉低,clk_a_en变低后,clk_b_en在clk_b的时钟域内才能被拉高有效,这时同步的clk_b_en信号与clk_b相与就能使得clk_out成功切换到clk_b了。

原理就是这样,其中clk_a_en和clk_b_en不会同时有效就避免了时钟切换的时候窄脉冲及毛刺的生成,但是我觉得由于是组合逻辑输出的时钟总归还是会有一些缺点和不足的。不知道有没有什么更好的办法。
编辑:hfy

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分