设计一个小数(分数)分频电路?
请设计一个小数(分数)分频电路?
例:设计一个3.6的分频电路。
计算原理: N=M.D>1 分频 M整数部分 D小数部分
使用M分频和M+1分频 来构成 M.D分频
设M分频 A次 M+1分频 B次 可得
M*A+(M+1)*B 周期内可看作 [M*A+(M+1)*B] / (A+B)=N 分频
代值可得:
N=3.6 M=3 M+1=4
36/3=10...6
即: 3*A+4*B=36 和 A+B=10 两式
解的 A=4 B=6
即在36个源时钟内,进行4次3分频,和6次4分频。即可得到3.6分频。
这个方法被称作”双模前置小数分频“,其最重要的核心是M分频和M+1分频这个相近频率。
一般会采用后两种平均插入的方法进行小数分频操作:即进行一次M分频,下一次进行M+1分频,再进行M分频,直到分频结束。这样做的好处:有效避免相位抖动过大。
小数分频代码&激励&仿真波形
module Fract_div #( parameter NUM =36 , parameter DIV_NUM =10 ) ( input sys_clk , input sys_rst_n , output div_clk ); parameter M=NUM/DIV_NUM ; // M=36/10=3 parameter W=M+1 ; //W=M+1; 4 parameter S=NUM-M*DIV_NUM ; //S=36-30=6 //采用平均插入的方式 reg [7:0] cnt_change ; //可变分频系数 reg [7:0] cnt ; //分频计数器 reg [7:0] cnt_diff ; //差值缓存 reg div_clk_reg ; //输出寄存 wire [7:0] cnt_diff_0 ; //差值 wire cnt_en ; //差值新赋值的使能信号 // 差值缓存大于 10 则差值 赋值为 差值缓存-10+6 // 差值缓存小于 10 则差值 赋值为 差值缓存+6 assign cnt_diff_0 =(cnt_diff>=DIV_NUM)?cnt_diff-10+S:cnt_diff+S; //小数分频运行逻辑如下: // cnt_diff=0 // cnt_diff_0=6 cnt_change = 2 div_clk_reg 0 0 1 cnt==cnt_change==2 cnt_en=1 cnt_diff=6 // cnt_diff_0=12 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=12 // cnt_diff_0=8 cnt_change = 2 div_clk_reg 0 0 1 cnt==cnt_change==2 cnt_en=1 cnt_diff=8 // cnt_diff_0=14 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=14 // cnt_diff_0=10 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=10 // cnt_diff_0=6 cnt_change = 2 div_clk_reg 0 0 1 cnt==cnt_change==2 cnt_en=1 cnt_diff=6 // cnt_diff_0=12 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=12 // cnt_diff_0=8 cnt_change = 2 div_clk_reg 0 0 1 cnt==cnt_change==2 cnt_en=1 cnt_diff=8 // cnt_diff_0=14 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=14 // cnt_diff_0=10 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=10 // cnt_diff_0=6 cnt_change = 2 div_clk_reg 0 0 1 cnt==cnt_change==2 cnt_en=1 cnt_diff=6 // cnt_diff_0=12 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=12 // cnt_diff_0=8 cnt_change = 2 div_clk_reg 0 0 1 cnt==cnt_change==2 cnt_en=1 cnt_diff=8 // cnt_diff_0=14 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=14 // cnt_diff_0=10 cnt_change = 3 div_clk_reg 0 0 0 1 cnt==cnt_change==3 cnt_en=1 cnt_diff=10 //规律 M=3 M+1=4 3*A+4*B=36 A+B=10 A=4 B=6 //平均插入 ABABBABABB 2323323233 这样就平均插入 // 确定分频系数 在cnt_diff_0小于10 为M-1 在cnt_diff_0大于10 为M always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt_change<=M-1; else if(cnt_diff_0>=10) cnt_change<=W-1; else cnt_change<=M-1; end //差值新赋值的使能信号 在分频计数器等于可变分频系数有效 assign cnt_en=(cnt==cnt_change)?1'b1:1'b0; //在差值新赋值的使能信号有效 差值缓存给差值 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt_diff<=8'd0; else if(cnt_en) cnt_diff<=cnt_diff_0; else cnt_diff<=cnt_diff; end always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cnt<=8'd0; div_clk_reg<=1'b0; end else if(cnt==cnt_change) begin //计数器计数到达预设可变分频系数时 清零 cnt<=8'd0; div_clk_reg<=1'b1; //并输出信号拉高 这里可以与下改变占空比 end else begin cnt<=cnt+8'd1; div_clk_reg<=1'b0; //并输出信号拉低 这里可以与上改变占空比 end end assign div_clk=div_clk_reg; endmodule
`timescale 1ns/1ns module tb_Fract_div(); reg sys_clk ; reg sys_rst_n ; wire div_clk ; initial begin sys_clk<=1'b0; sys_rst_n<=1'b0; #20 sys_rst_n<=1'b1; end always #10 sys_clk <=~sys_clk; Fract_div #( .NUM(36) , .DIV_NUM(10) ) Fract_div_inst ( .sys_clk (sys_clk ) , .sys_rst_n (sys_rst_n) , .div_clk (div_clk ) ); endmodule
其中时钟周期有3+4+3+4+4+3+4+3+4+4=36个 源时钟周期为50Mhz 即分频为50/36=1.3888Mhz 完成 3.6分频
可以修改激励代码中的分频参数,和设计代码中,调整占空比。
下面为 4.6分频 和 2.3分频 为例。
50/46=1.08695Mhz
46/4=10...6
4*A+5*B=46 A+B=10 解的 A=4 B=6
平均插入排列: ABABBABABB
50/23=2.1739
23/2=10...3
2*A+3*B=23 A+B=10 解的 A=7 B=3
AABAABAAAB
若有不对的地方,敬请指正,万分感谢。
参考资料: