原理
假设19/9分频,利用公式
(19/9) * (a+b)=2a+3b
===>
a=8
b=1
即可以由8个2分频+1个3分频,在8*2+1*3=19
个参考时钟周期内,实现19/9分频。
优点是算法简单。
缺点是占空比不是50%,因为2分频和3分频交叉组合而成,所以周期性抖动较差。
总之,用于普通的数字逻辑实现基于频率的带宽精细微调,还是很有用处的。
波形
module代码
分频系数=分子/分母。
module clkFracDiv(
output reg clkout,
input rstn,
input refclk,
input [31:0] fenzi,//fenzi/fenmu must equal or more than 2
input [31:0] fenmu //fenzi/fenmu must equal or more than 2
);
reg [2:0] rstn_syn;
reg [31:0] cnt;
//1. reset synchronization;
//2. indicate that refclk is already stable
always @(posedge refclk) begin
rstn_syn[0] <= rstn;
rstn_syn[1] <= rstn_syn[0];
rstn_syn[2] <= rstn_syn[1];
end
//1. main algorithm
always @(posedge refclk or negedge rstn_syn[2]) begin
if(!rstn_syn[2]) cnt <= 0;
else begin
if(cnt < fenzi) cnt <= cnt + fenmu;
else cnt <= cnt + fenmu - fenzi;
end
end
//1. base the above algorithm, deduce clkout
always @(posedge refclk or negedge rstn_syn[2]) begin
if(!rstn_syn[2]) clkout <= 0;
else begin
if(((cnt > (fenzi>>1)) || (cnt == (fenzi>>1))) && (cnt < fenzi)) clkout <= 1;
else clkout <= 0;
end
end
endmodule
testbench代码
`timescale 1ns/10ps
module tb_top;
reg refclk;
initial begin
refclk = 0;
end
always #0.2 refclk = !refclk;
reg rstn;
initial begin
rstn = 0;
#100;
rstn = 1;
end
reg [31:0] fenzi;
reg [31:0] fenmu;
reg enable_clkFracDiv;
initial begin
fenzi=32'd19;
fenmu=32'd9;
enable_clkFracDiv=0;
#200;
enable_clkFracDiv=1;
end
clkFracDiv clkFracDiv(
/*output reg */.clkout (clkout),
/*input */.rstn (rstn && enable_clkFracDiv ),
/*input */.refclk (refclk),
/*input [31:0] */.fenzi (fenzi ),//fenzi/fenmu must equal or more than 2
/*input [31:0] */.fenmu (fenmu ) //fenzi/fenmu must equal or more than 2
);
endmodule
算法解析
主要算法,在clkFracDiv.v的第二段实现代码里。
第三段实现代码,只是基于这个算法推演clkout波形而已。
基于实例说明,19/9分频。换个说法,即19个参考时钟refclk里,划分9段。
因为分母是9,所以计数器是+9计算的,如果超过19,意味着当前两个上升沿之间的周期大于期望周期值,余数需要考虑进下一个周期里。总共需要的周期数,就是前文的8*2+1*3=19
个参考时钟周期内。
理论上,只要分频系数大于或者等于2的各种整数分频、小数分频,都是可以的。
参考文档
32任意分数分频Verilog实现
http://3y.uu456.com/bp-4ecb3facd1f346q3daef3e2e-1.html