verilog奇偶分頻詳解
文章目錄
奇偶分頻是一個很常見的問題,這裡探討的分頻都是對於佔空比為50%的訊號分頻,分頻後的訊號也是50%佔空比。分頻原訊號 N N N倍,意味分頻後的訊號的高低電平持續時間是原來訊號的高低電平持續時間的 N N N倍。
偶分頻
原訊號是一個50ns為週期的訊號
在verilog裡面要分頻首先想到的就是用到計數器來對高低電平計數從而產生符合要求分頻訊號,我們目標要產生50%的佔空比的訊號,所以我們可以先不管分頻訊號的低電平的計數,先來看看高電平的計數。
假設用1個計數器來計數,由於在對於暫存器的操作都是以一個週期為單位,意味著無論你的高電平計數為多少,都是以原訊號1個週期為單位計數,同樣無論你的低電平計數為多少,也都是1個週期為單位計數,那麼可以知道高電平持續的時間一定是原訊號高電平持續時間的
2
N
2N
2分頻
module even (
input clk,
output reg div_clk = 0
);
always @(posedge clk) begin
div_clk <= ~div_clk;
end
endmodule
`timescale 1ns / 1ps module tb (); reg clk; wire div_clk; even eventest( .clk(clk), .div_clk(div_clk) ); initial begin clk = 1; end always clk = #25 ~clk; endmodule
2分頻甚至都不需要用計數器
2N分頻
module even # (parameter div_2n = 4)( input clk, output reg div_clk = 0 ); parameter width = $clog2(div_2n); reg [width-1:0] cnt = 0; always @(posedge clk) begin if(cnt < div_2n/2-1) cnt <= cnt + 1'b1; else begin cnt <= 0; div_clk <= ~div_clk; end end endmodule
`timescale 1ns / 1ps
module tb ();
reg clk;
wire div_clk;
even #
(.div_2n(6)) eventest(
.clk(clk),
.div_clk(div_clk)
);
initial begin
clk = 1;
end
always clk = #25 ~clk;
endmodule
模擬可以看到確實是6分頻。
奇分頻
同樣我們先只考慮分頻高電平持續時間的情況,前面已經分析過了,對於高電平持續的時間一定是原來訊號高電平持續時間的 2 N 2N 2N倍,而奇分頻要求分頻後的訊號的高電平時間是原來訊號高電平持續時間的奇數倍,那麼分頻後的一個clk做不到,就用兩個clk,先看3分頻
3分頻高電平
如下圖所示我們可以讓clk2相比clk1往後延一個原訊號的高電平時間(25ns),在將clk1與clk2或起來,就能得到相比於原來訊號的高點平(25)3倍的高電平訊號,並且也滿足每個時鐘訊號的高電平是原訊號高電平時間的 2 N 2N 2N倍,這裡的 N N N是1
3分頻低電平
前面已經描述了低電平持續的時間也是1個週期為單位計算,那麼假設讓clk1和clk2的低電平持續時間和高電平持續時間一致。如下圖
那麼得到的分頻訊號clk高電平和低電平持續時間並不相等,不是50%佔空比。沒有達到50%分頻比的要求,這裡可以看到就像是分頻訊號clk的高電平向低電平借了半個週期(原訊號)的持續時間,導致分頻比是75%,但是此時只要在將clk1和clk2的低電平在延續一個週期,那麼clk就可以達到50%佔空比。如下圖
因此為了實現3分頻,低電平需要持續2個時鐘週期,高電平需要持續1個週期,且clk2要相比與clk1延遲半個原訊號週期,在將clk1和clk2或起來就能得到3分頻的分頻訊號。
module odd (
input clk,
output div_clk
);
reg clk1 = 0;
reg clk1_cnt = 0;
wire clk1_num = clk1?1'b0:1'b1;
reg clk2 = 0;
reg clk2_cnt = 0;
wire clk2_num = clk2?1'b0:1'b1;
always @(posedge clk) begin
if(clk1_cnt < clk1_num)
clk1_cnt <= clk1_cnt + 1'b1;
else begin
clk1_cnt <= 0;
clk1 <= ~clk1;
end
end
always @(negedge clk) begin
if(clk2_cnt < clk2_num)
clk2_cnt <= clk2_cnt + 1'b1;
else begin
clk2_cnt <= 0;
clk2<= ~clk2;
end
end
assign div_clk = clk1||clk2;
endmodule
`timescale 1ns / 1ps
module tb ();
reg clk;
wire div_clk;
odd oddtest(
.clk(clk),
.div_clk(div_clk)
);
initial begin
clk = 1;
end
always clk = #25 ~clk;
endmodule
一般結果推導
我們唯一能夠控制的就是高低電平的持續時間。
T
o
是
原
信
號
的
的
周
期
T
o
h
是
原
信
號
的
高
電
平
時
間
T
o
l
是
原
信
號
的
低
電
平
時
間
T
o
h
=
T
o
l
T
o
=
2
T
o
h
=
2
T
o
l
T_o 是原訊號的的週期\\ T_{oh}是原訊號的高電平時間\\ T_{ol}是原訊號的低電平時間\\ T_{oh}=T_{ol}\quad T_o=2T_{oh}=2T_{ol}
To是原信號的的周期Toh是原信號的高電平時間Tol是原信號的低電平時間Toh=TolTo=2Toh=2Tol
假設我們控制高電平時間
N
h
N_h
Nh,低電平
N
l
N_l
Nl個時鐘週期,並且將其中一個clk延遲半個原訊號週期與另一個clk的時鐘或起來,能夠得到或後的時鐘
T
o
r
h
或
後
的
時
鍾
高
電
平
持
續
時
間
T
o
r
l
或
後
的
時
鍾
低
電
平
持
續
時
間
T
o
r
h
=
N
h
T
o
+
T
o
h
=
2
N
h
T
o
h
+
T
o
h
=
(
2
N
h
+
1
)
T
o
h
T
o
r
l
=
N
l
T
o
l
−
T
o
l
=
2
N
l
T
o
l
−
T
o
l
=
(
2
N
l
−
1
)
T
o
l
T_{orh}或後的時鐘高電平持續時間\\ T_{orl}或後的時鐘低電平持續時間\\ \begin{aligned} T_{orh} &= N_hT_o+T_{oh}\\ &= 2N_hT_{oh}+T_{oh}\\ &= (2N_h+1)T_{oh}\\ T_{orl} &= N_lT_{ol}-T_{ol}\\ &= 2N_lT_{ol}-T_{ol}\\ &= (2N_l-1)T_{ol} \end{aligned}
Torh或後的時鍾高電平持續時間Torl或後的時鍾低電平持續時間TorhTorl=NhTo+Toh=2NhToh+Toh=(2Nh+1)Toh=NlTol−Tol=2NlTol−Tol=(2Nl−1)Tol
又因為50%佔空比得到
T
o
r
h
=
T
o
r
l
T
o
h
=
T
o
l
T_{orh}=T_{orl}\quad T_{oh}=T_{ol}
Torh=TorlToh=Tol,因此
2
N
h
+
1
=
2
N
l
−
1
N
h
=
N
l
−
1
\begin{aligned} 2N_h+1&=2N_l-1\\ N_h &=N_l-1 \end{aligned}
2Nh+1Nh=2Nl−1=Nl−1
當
N
h
=
1
,
N
l
=
2
N_h =1,N_l =2
Nh=1,Nl=2是3分頻,當
N
h
=
2
,
N
l
=
3
N_h =2,N_l =3
Nh=2,Nl=3是5分頻。
module odd #
(parameter div_2n1 = 3)
(
input clk,
output div_clk
);
parameter width = $clog2(div_2n1);
reg clk1 = 0;
reg [width-1:0]clk1_cnt = 0;
wire [width-1:0] clk1_num = clk1?(div_2n1/2-1):div_2n1/2;
reg clk2 = 0;
reg [width-1:0] clk2_cnt = 0;
wire [width-1:0] clk2_num = clk2?(div_2n1/2-1):div_2n1/2;
always @(posedge clk) begin
if(clk1_cnt < clk1_num)
clk1_cnt <= clk1_cnt + 1'b1;
else begin
clk1_cnt <= 0;
clk1 <= ~clk1;
end
end
always @(negedge clk) begin
if(clk2_cnt < clk2_num)
clk2_cnt <= clk2_cnt + 1'b1;
else begin
clk2_cnt <= 0;
clk2<= ~clk2;
end
end
assign div_clk = clk1||clk2;
endmodule
`timescale 1ns / 1ps
module tb ();
reg clk;
wire div_clk;
odd #
(.div_2n1(5))
oddtest(
.clk(clk),
.div_clk(div_clk)
);
initial begin
clk = 1;
end
always clk = #25 ~clk;
endmodule
根據仿真確實是5分頻。