在現(xiàn)代芯片中,芯片運行時有必要在兩個不同的時鐘之間切換。如果我們使用普通的多路復用器進行切換時鐘會發(fā)生什么?多路復用器有一個名為 SELECT 的控制信號,該信號在設置為“零”時將 CLK1 傳播到輸出,或者在設置為“1”時將 CLK2 傳播到輸出。當 SELECT 值更改時,由于輸出從當前時鐘源立即切換到下一個時鐘源,可能會引起毛刺。

圖1普通多路復用器
verilog代碼:
module clk_select1(
input clk1,
input clk2,
input rst_n,
input sel,
output out_clk
);
assign out_clk = sel?clk2:clk1;
endmodule

圖2時鐘切換的正常多路復用器實現(xiàn)的波形(有毛刺)
假如時鐘由 clk1 切換到 clk2,且切換時刻為 clk1 輸出電平為高的時候,此時立即切換時鐘就會導致輸出時鐘出現(xiàn)毛刺(glitch)。在兩個時鐘電平相反的時候切換時鐘,肯定有毛刺;電平相同的時候,即使不產(chǎn)生毛刺,時鐘切換后的第一個時鐘的周期或占空比也不是理想的。所以,為避免毛刺的產(chǎn)生,需要在兩個時鐘都為低電平的時候進行時鐘切換。
時鐘切換方案的設計思路
1.先關斷當前選擇的時鐘,再新選擇的時鐘;
2.在時鐘為低電平的時鐘進行時鐘切換;
一種典型的時鐘切換電路如下所示。其中左邊部分存在一個 互鎖結構 ,與SR鎖存器結構類似,不同之處是中間嵌入了2個下降沿觸發(fā)器,這個設計非常巧妙。 互鎖電路保證了當輸出穩(wěn)定后,其兩端的輸出值是互斥的 。插入dff后,電路有了記憶功能, 將互鎖的邏輯用下降沿DFF抓一拍后反饋給另一側(cè),即使當目前select發(fā)現(xiàn)變化,只要當前選擇的時鐘下降沿沒有到來時,不會切換時鐘,只有當select發(fā)生變化,且當前選擇的時鐘下降沿到來后,關閉當前選擇的時鐘系統(tǒng),等到另一個時鐘系統(tǒng)下降沿到來時,切換至另一個時鐘系統(tǒng),完成時鐘無毛刺切換 ,具體如下:
- 當select穩(wěn)定值為0時,此時系統(tǒng)選擇的是clk1時鐘,i_and1=1,flop1_o=1;i_and2=0,flop2_o=0;
- 當selec由0向1進行變化時,i_and1輸出變?yōu)?,但是在clk1下降沿到來前,flop1_0會穩(wěn)定輸出為1,因此i_and2仍然輸出0,flop2_o保持為0,此時選擇的是clk1時鐘;
- 當clk1下降沿到來時,flop1_0輸出變?yōu)?,關閉clk1,i_and2的輸出會變?yōu)?,在clk2下降沿到來前,flop2_o保持為0,此時系統(tǒng)輸出低電平;
- 當clk2下降沿到來時,flop2_0輸出變?yōu)?,打開clk2,此時系統(tǒng)選擇的時clk2時鐘;

圖3無毛刺時鐘多路復用器
verilog代碼:
module clk_select2(
input clk1,
input clk2,
input rst_n,
input sel,
output out_clk
);
reg ff1;
reg ff2;
always @(negedge clk1 or negedge rst_n) begin
if(!rst_n)
ff1 <= 1'b0;
else begin
ff1 <= ~ff2 & !sel;
end
end
always @(negedge clk2 or negedge rst_n) begin
if(!rst_n)
ff2 <= 1'b0;
else begin
ff2 <= ~ff1 & sel;
end
end
assign out_clk = (ff1 & clk1) | (ff2 & clk2);
endmodule
考慮到選擇信號有可能是異步信號,需要在時鐘選擇信號的緩存觸發(fā)器之前加兩級觸發(fā)器進行同步處理,來減少亞穩(wěn)態(tài)的傳播,結構圖如下。該時鐘切換電路更具有普遍性。

圖4無毛刺時鐘多路復用器(使用雙同步器)
verilog代碼:
module clk_select3(
input clk1,
input clk2,
input rst_n,
input sel,
output out_clk
);
reg ff1,ff1_d;
reg ff2,ff2_d;
always @(negedge clk1 or negedge rst_n) begin
if(!rst_n)
{ff1,ff1_d} <= 2'b00;
else begin
ff1_d <= ~ff2 & !sel;
ff1 <= ff1_d;
end
end
always @(negedge clk2 or negedge rst_n) begin
if(!rst_n) {ff2,ff2_d} <= 2'b00;
else begin
ff2_d <= ~ff1 & sel;
ff2 <= ff2_d;
end
end
assign out_clk = (ff1 & clk1) | (ff2 & clk2);
endmodule
-
時鐘
+關注
關注
11文章
1980瀏覽量
135053 -
鎖存器
+關注
關注
8文章
957瀏覽量
45185 -
多路復用器
+關注
關注
9文章
1058瀏覽量
66788 -
觸發(fā)器
+關注
關注
14文章
2061瀏覽量
63431 -
CLK
+關注
關注
0文章
132瀏覽量
18054 -
時鐘切換電路
+關注
關注
0文章
7瀏覽量
5911
發(fā)布評論請先 登錄
關于如何讓多路復用器變得簡單
使用普通的多路復用器進行切換時鐘會發(fā)生什么?
評論