隨著各種應(yīng)用場景的限制,芯片在運(yùn)行時(shí)往往需要在不同的應(yīng)用下切換不同的時(shí)鐘源,例如低功耗和高性能模式就分別需要低頻率和高頻率的時(shí)鐘。兩個(gè)時(shí)鐘源有可能是同源且同步的,也有可能是不相關(guān)的。直接使用選擇邏輯進(jìn)行時(shí)鐘切換大概率會導(dǎo)致分頻時(shí)鐘信號出現(xiàn)毛刺現(xiàn)象,所以時(shí)鐘切換邏輯也需要進(jìn)行特殊的處理。
直接采用選擇邏輯對時(shí)鐘進(jìn)行切換的電路圖如下所示。
假如時(shí)鐘選擇信號 sel_clk1 與兩個(gè)時(shí)鐘都是異步的,那么時(shí)鐘切換時(shí)刻就是任意的。假如時(shí)鐘由 clk1 切換到 clk2,且切換時(shí)刻為 clk1 輸出電平為高的時(shí)候,此時(shí)立即切換時(shí)鐘就會導(dǎo)致輸出時(shí)鐘出現(xiàn)毛刺(glitch)。波形示意圖如下:
在兩個(gè)電平相反的時(shí)候切換時(shí)鐘,肯定有毛刺;電平相同的時(shí)候,即使不產(chǎn)生毛刺,時(shí)鐘切換后的第一個(gè)時(shí)鐘的周期或占空比也不是理想的。所以,為避免毛刺的產(chǎn)生,需要在兩個(gè)時(shí)鐘都為低電平的時(shí)候進(jìn)行時(shí)鐘切換。
一種典型的時(shí)鐘切換電路如下所示。
該電路利用時(shí)鐘下降沿對時(shí)鐘選擇信號 sel_clk1 進(jìn)行緩存。同時(shí)一個(gè)時(shí)鐘選擇信號對另一個(gè)時(shí)鐘進(jìn)行反饋控制,保證同一時(shí)刻只能有一路時(shí)鐘有效。最后采用"或操作"將兩路時(shí)鐘合并,完成時(shí)鐘切換的過程。
采用上述電路完成時(shí)鐘切換(clk1->clk2)的波形示意圖如下所示。
由圖可知,clk1 向 clk2 切換時(shí),先關(guān)閉 clk1, 然后打開 clk2。由于時(shí)鐘選擇信號被同步到時(shí)鐘下降沿,所以切換過程中不會出現(xiàn)毛刺。
clk2 向 clk1 切換的波形示意圖如下所示。
考慮到選擇信號有可能是異步信號,需要在時(shí)鐘選擇信號的緩存觸發(fā)器之前加兩級觸發(fā)器進(jìn)行同步處理,來減少亞穩(wěn)態(tài)的傳播,結(jié)構(gòu)圖如下。該時(shí)鐘切換電路更具有普遍性。
普遍且安全的時(shí)鐘切換邏輯描述如下。
module clk_switch(
input rstn ,
input clk1,
input clk2,
input sel_clk1 , // 1 clk1, 0 clk2
output clk_out
);
reg [2:0] sel_clk1_r ;
reg [1:0] sel_clk1_neg_r ;
reg [2:0] sel_clk2_r ;
reg [1:0] sel_clk2_neg_r ;
//使用3拍緩存,同步另一個(gè)時(shí)鐘控制信號與本時(shí)鐘控制信號的"與"邏輯操作
always @(posedge clk1 or negedge rstn) begin
if (!rstn) begin
sel_clk1_r <= 3'b111 ; //注意默認(rèn)值
end
else begin
//sel clk1, and not sel clk2
sel_clk1_r <= {sel_clk1_r[1:0], sel_clk1 & (!sel_clk2_neg_r[1])} ;
end
end
//在下降沿,使用2拍緩存時(shí)鐘選擇信號
always @(negedge clk1 or negedge rstn) begin
if (!rstn) begin
sel_clk1_neg_r <= 2'b11 ; //注意默認(rèn)值
end
else begin
sel_clk1_neg_r <= {sel_clk1_neg_r[0], sel_clk1_r[2]} ;
end
end
//使用3拍緩存,同步另一個(gè)時(shí)鐘控制信號與本時(shí)鐘控制信號的"與"邏輯操作
always @(posedge clk2 or negedge rstn) begin
if (!rstn) begin
sel_clk2_r <= 3'b0 ; //注意默認(rèn)值
end
else begin
//sel clk2, and not sel clk1
sel_clk2_r <= {sel_clk2_r[1:0], !sel_clk1 & (!sel_clk1_neg_r[1])} ;
end
end
//在下降沿,使用2拍緩存時(shí)鐘選擇信號
always @(negedge clk2 or negedge rstn) begin
if (!rstn) begin
sel_clk2_neg_r <= 2'b0 ; //注意默認(rèn)值
end
else begin
sel_clk2_neg_r <= {sel_clk2_neg_r[0], sel_clk2_r[2]} ;
end
end
//時(shí)鐘邏輯運(yùn)算時(shí),一般使用特定的工藝單元庫。
//這里用 Verilog 自帶的邏輯門單元代替
wire clk1_gate, clk2_gate ;
and (clk1_gate, clk1, sel_clk1_neg_r[1]) ;
and (clk2_gate, clk2, sel_clk2_neg_r[1]) ;
or (clk_out, clk1_gate, clk2_gate) ;
endmodule
testbench 描述如下,主要產(chǎn)生異步時(shí)鐘的選擇信號。
`timescale 1ns/1ps
module test ;
reg clk_100mhz, clk_200mhz ;
reg rstn ;
reg sel ;
wire clk_out ;
always #(2.5) clk_200mhz = ~clk_200mhz ;
always @(posedge clk_200mhz)
clk_100mhz = #1 ~clk_100mhz ;
initial begin
clk_100mhz = 0 ;
clk_200mhz = 0 ;
rstn = 0 ;
sel = 1 ;
#11 rstn = 1 ;
#36.2 sel = ~sel ;
#119.7 sel = ~sel ;
end
clk_switch u_clk_switch(
.rstn (rstn),
.clk1 (clk_100mhz),
.clk2 (clk_200mhz),
.sel_clk1 (sel),
.clk_out (clk_out));
initial begin
forever begin
#100;
if ($time >= 10000) $finish ;
end
end
endmodule
仿真結(jié)果如下,可見時(shí)鐘相互切換時(shí)沒有產(chǎn)生毛刺,但是存在延遲。
點(diǎn)擊這里下載源碼
更多建議: