一、偶數分頻器
偶數分頻器原理不在介紹,直接給出verilog代碼。
module even_div
#(
parameter DIV = 4,
parameter WIDTH = 8
)(
input clk,
input en,
input rst_n,
output reg locked,
output reg clk_out
);
reg [WIDTH-1:0] div_reg = DIV;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
locked <= 1'b0;
clk_out <= 1'b0;
div_reg <= 0;
end
else begin
if(!en)begin
locked <= 1'b0;
clk_out <= 1'b0;
div_reg <= 0;
end
else begin
//clk_out locked.
locked <= 1'b1;
//divide counter
if(div_reg < (DIV-1'b1))begin
div_reg <= div_reg + 1'b1;
end
else begin
div_reg <= 0;
end
//According value in Divide Counter, clk_out is output
if(div_reg<(DIV>>1))begin
clk_out <= 1'b1;
end
else begin
clk_out <= 1'b0;
end
end
end
end
endmodule
二、奇數分頻
任意奇數分頻器的關鍵在于clk_a和clk_b的實作,若能實作clk_a和clk_b,然後将兩個信号進行或運算即可。如下圖所示的信号。
奇數分頻
奇數分頻的代碼:
module odd_div
#(
parameter DIV = 5,
parameter WIDTH = 8
)
(
input clk,
input en,
input rst_n,
output clk_out,
output clk_locked
);
reg [WIDTH-1:0] cnt_a;
reg clk_a;
reg clk_b;
reg clk_lock_a;
assign clk_out = clk_a | clk_b;
assign clk_locked = clk_lock_a;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
clk_a <= 1'b0;
clk_lock_a <= 1'b0;
cnt_a <= 0;
end
else begin
if(!en)begin
clk_a <= 1'b0;
clk_lock_a <= 1'b0;
cnt_a <= 0;
end
else begin
if(cnt_a < ((DIV-1)/2))begin
clk_a <= 1'b1;
end
else begin
clk_a <= 1'b0;
end
if(cnt_a < (DIV-1))
cnt_a <= cnt_a + 1'b1;
else begin
cnt_a <= 0;
clk_lock_a <= 1'b1;
end
end
end
end
[email protected](negedge clk)begin
clk_b <= clk_a;
end
endmodule
三、任意小數分頻
事實上我們不能單純地利用FPGA實作非常精确的小數分頻。所謂小數分頻,我們是建立在統計學之上的。例如:5.3分頻(clk_div5_3),并不是真正意義上的5.3分頻,而是在一段很長的時間内滿足5.3分頻即可。比如在53個時鐘上對應有10個時鐘輸出即可。我們可以這麼了解:
5.3分頻在5分頻和6分頻之間,并且在53個時鐘周期上滿足10個時鐘輸出,則有:
其中n是5分頻後的時鐘個數,m是6分頻後的時鐘個數,總數為10;又因為一共有53個輸入時鐘,是以“clk_div5的個數乘5”加“clk_div6的個數乘6”的和為53。解這個方程得:n=7,m=3.也就是說我們7個clk_div5和3個clk_div6組合到一起就是統計學上的5.3分頻。
同理,4.3分頻,6.7分頻,6.18分頻也是如此。下圖給出4.3分頻的仿真圖(輸入時鐘周期為20ns,刻度2為860ns,即43個時鐘,期間一共有10個輸出時鐘):
4.3分頻仿真圖
4.3分頻,例化了上述的偶數分頻、奇數分頻子產品(注意參數傳遞的注釋)。代碼如下:
module decimal_div
#(
parameter CNT_TOTAL = 43,
parameter CNT_DIV = 10,
parameter CNT_PREP = CNT_TOTAL / CNT_DIV,
parameter CNT_POSTP = CNT_PREP + 1,
parameter NUM_POST = CNT_TOTAL - CNT_PREP*CNT_DIV,
parameter NUM_PRE = CNT_DIV - NUM_POST,
parameter WIDTH = 8
)(
input clk_in,
input en,
input rst_n,
output reg locked,
output clk_out
);
reg [WIDTH-1:0] cnt_pre = 0;//
reg [WIDTH-1:0] cnt_post = 0;//
reg cnt_clk_div = 0;
reg sm_en = 1'b0;
reg clk_out_r;
[email protected](posedge clk_in or negedge rst_n)begin
if(!rst_n)begin
locked <= 1'b0;
clk_out_r <= 1'b0;
end
else begin
if(!en)begin
locked <= 1'b0;
clk_out_r <= 1'b0;
end
else begin
sm_en <= 1'b1;
end
end
end
/*******************************
State Machine
********************************/
reg [4:0] state = 4'h0;
localparam s_0 = 4'd0;//3 div
localparam s_1 = 4'd1;//3 div
localparam s_2 = 4'd2;//4 div
reg even_clk_en;
reg odd_clk_en;
reg switch;
wire clk_odd;
wire clk_even;
assign clk_out = switch? clk_odd : clk_even;
[email protected](negedge clk_in)begin
case(state)
//ideal
s_0:begin
if(sm_en==1'b0)begin
state <= s_0;
locked <= 1'b0;
end
else begin
locked <= 1'b0;
state <= s_1;
if(CNT_PREP[0]==1'b1)
switch <= 1'b1;
else
switch <= 1'b0;
end
end
//div = 3
s_1:begin
if(cnt_pre < (NUM_PRE*CNT_PREP - 1))begin
cnt_pre <= cnt_pre + 1'b1;
end
else begin
cnt_pre <= 0;
state <= s_2;
switch <= switch^1'b1;
end
end
//div = 4;
s_2:begin
if(cnt_post < (NUM_POST*CNT_POSTP - 1))begin
cnt_post <= cnt_post + 1'b1;
end
else begin
cnt_post <= 0;
state <= s_1;
switch <= switch^1'b1;
locked <= 1'b1;
end
end
default:begin
state <= s_0;
end
endcase
end
odd_div #(
//decimal X.Y
.DIV (CNT_POSTP),//X is even, DIV=CNT_POSTP;if not DIV=CNT_PREP.
.WIDTH (8)
)
u_odd(
.clk (clk_in),
.en (switch),
.rst_n (1),
.clk_out (clk_odd),
.clk_locked ()
);
even_div #(
//decimal X.Y
.DIV (CNT_PREP),//X is odd, DIV=CNT_POSTP;if not DIV=CNT_PREP.
.WIDTH (8)
)
u_even(
.clk (clk_in),
.en (~switch),
.rst_n (1),
.locked (),
.clk_out (clk_even)
);
endmodule