一、偶数分频器
偶数分频器原理不在介绍,直接给出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;
always@(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,然后将两个信号进行或运算即可。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;
always@(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
always@(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分频,例化了上述的偶数分频、奇数分频模块(注意参数传递的注释)。代码如下:
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;
always@(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;
always@(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