设计一个小数(分数)分频电路?

发布时间 2023-07-31 20:24:25作者: 余你余生

请设计一个小数(分数)分频电路?

例:设计一个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

 若有不对的地方,敬请指正,万分感谢。

参考资料:

1、5.3 Verilog 时钟分频 | 菜鸟教程 (runoob.com)