Verilog分频器设计_学习总结

分频器设计_Verilog

1. 偶分频

1.1 寄存器级联法

实现偶数分频,例如二分频、四分频,占空比为50%。

//2/4分频(任意偶数分频),要求50%占空比
module clk_div2(clk, rstn, clk2, clk4);
input       clk, rstn;
output reg  clk2, clk4;
​
always @(posedge clk or negedge rstn) begin
    if (!rstn)
        clk2 <= 0;
    else
        clk2 <= ~clk2;
endalways @(posedge clk2 or negedge rstn) begin
    if (!rstn)
        clk4 <= 0;
    else
        clk4 <= ~clk4;
endendmodule

具体时序图如下:

1.2 计数器法

从0开始计数至N/2-1,可得到任意偶数N分频时钟,占空比为50%。

//6分频(任意偶数分频),要求50%占空比
module clk_div2(clk, rstn, clkn);
input       clk, rstn;
output reg  clkn;
​
parameter N  = 6;
parameter WD = $clog2(N);
reg [WD-1:0] count;
​
always @(posedge clk or negedge rstn) begin
    if (!rstn || count == N/2-1)
        count <= 0;
    else
        count <= count + 1'b1;
endalways @(posedge clk or negedge rstn) begin
    if (!rstn)
        clkn <= 0;
    else if (count == N/2 - 1)
        clkn <= ~clkn;
    else
        clkn <= clkn;
end
endmodule

例如N=6,得到6分频时序图如下:

 

若需要占空比不满足50%的6分频电路,可使用计数器/状态机,在定义的6个计数状态中,选择某几个状态输出时钟为1,其余为0,以控制特殊占空比。

2. 奇分频

2.1 q != 50%

不需要占空比50%的奇分频,例如三分频,采用计数器法,每次遇到count=0或1时翻转。

//3分频(任意奇数分频),不要求50%占空比
module clk_div3(clk, rstn, clk3);
input       clk, rstn;
output reg  clk3;
​
parameter N  = 3;
parameter WD = $clog2(N);
reg [WD-1:0] count;
​
always @(posedge clk or negedge rstn) begin
    if (!rstn || count == N-1)
        count <= 'd0;
    else
        count <= count + 1'b1;
endalways @(posedge clk or negedge rstn) begin
    if (!rstn)
        clk3 <= 1'b0;
    else if (count == 'd0 || count == 'd1)
        clk3 <= !clk3;
    else 
        clk3 <= clk3;
endendmodule

可得到时序图如下:

2.2 q == 50%

需要占空比50%的奇分频,例如三分频,需要两个计数器,分别是上升沿计数器和下降沿计数器,执行同样的操作,均在count=0或1时翻转。

//N分频(任意奇数分频),要求50%占空比
module clk_div_odd(clk, rstn, clk_o);
input   clk, rstn;
output  clk_o;
​
reg clk_pos, clk_neg;
​
parameter N  = 3;
//parameter WD = $clog2(N);
localparam WD = 31;
reg [WD:0] count_pos, count_neg;
​
assign clk_o = clk_pos || clk_neg;
​
always @(posedge clk or negedge rstn) begin
    if(!rstn || count_pos == N-1)
        count_pos <= 0;
    else
        count_pos <= count_pos + 1;
endalways @(negedge clk or negedge rstn) begin
    if(!rstn || count_neg == N-1)
        count_neg <= 0;
    else
        count_neg <= count_neg + 1;
endalways @(posedge clk or negedge rstn) begin
    if(!rstn)
        clk_pos <= 0;
    else if (count_pos == N>>1 || count_pos == (N-1))
        clk_pos <= ~clk_pos;
    else
        clk_pos <= clk_pos;
endalways @(negedge clk or negedge rstn) begin
    if (!rstn)
        clk_neg <= 0;       
    else if (count_neg == N>>1 || count_neg == (N-1))
        clk_neg <= ~clk_neg;
    else
        clk_neg <= clk_neg;
endendmodule

时序图如下:

3. 小数分频

小数分频常采用两种方法,使用方法二实现。

方法一:用数字锁相环实现,利用锁相环电路将输入时钟倍频,再对新产生的高频信号分频得到所需频率。例如产生8.6分频信号,可以先把输入时钟10倍频,再进行86分频,可精确实现8.6的小数分频。一般只在某些对信号频率精度要求较高的场合下使用。

方法二:设计两个不同分频比的整数分频器,通过控制分频出现次数获得所需小数分频,但硬件电路难以实现小数计时,此处所指的是平均意义上的小数分频。

3.1 任意小数分频

3.1.1 整数分频计算

例如8.6分频,时钟周期为10ns,得到的输出时钟应为5个周期有效信号430ns,推导如下:

 

$$
T = 8.6 = M.N = M + \frac{b}{a+b} = \frac{Ma + (M+1)b}{a+b}
$$

 

其中M=8, N=6, a+b 是平均意义的时钟周期,也即使用a个M分频和b个M+1分频。

$$
\left\{ \begin{array}{**lr**} 8a+9b=43 \\ a+b=5 \end{array} \right.
$$

 

得到a=2,b=3,也即使用2个8分频和3个9分频。

该方法为双模前置小数分频,最重要的是以M分频和M+1分频两个相近频率实现。

再举例实现5.3分频,有:

$$
T=5.3=\frac{5a+6b}{a+b}=> \left\{ \begin{array}{**ls**} 5a+6b=53 \\ a+b=10 \end{array} \right.
$$

 

a=7, b=3, 也即使用7个5分频和3个6分频。

分频方法并不唯一,比如8.6分频可以使用1个11分频和4个8分频,但得到的信号在平均周期中的每个周期有效时间差别较大,信号质量差。

同样地,为了得到时钟频率较为均匀的信号,2个8分频和3个9分频实现的顺序如下,将2次8分频均匀插入3次9分频中:

3.1.2 RTL+testbench

//8.6分频,以2个8分频和3个9分频实现
module clk_div_fraction(clk, rst_n, clk_out);
input       clk, rst_n  ;
output reg  clk_out     ;
​
reg [2:0] cnt               ;
reg [3:0] cnt_odd, cnt_even ;
​
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt      <= 3'd0;
        cnt_odd  <= 4'd0;
        cnt_even <= 4'd0;
    end
    else if (cnt == 3'd0 || cnt == 3'd2) begin
    //cnt=0/2 9分频
        if (cnt_odd == 4'd8) begin
            cnt_odd <= 4'd0;
            cnt     <= cnt + 1'b1;
        end
        else begin
            cnt_even <= 4'd0;
            cnt_odd  <= cnt_odd + 1'b1;
        end
    end
    else if (cnt == 3'd4) begin
    //cnt=4 9分频
        if (cnt_odd == 4'd8) begin
            cnt_odd <= 4'd0;
            cnt     <= 3'd0;
        end
        else begin
            cnt_even <= 4'd0;
            cnt_odd  <= cnt_odd + 1'b1;
        end
    end
    else if (cnt == 3'd1 || cnt == 3'd3) begin
    //cnt=1/3 8分频
        if (cnt_even == 4'd7) begin
            cnt_even <= 4'd0;
            cnt      <= cnt + 1'b1;
        end
        else begin
            cnt_odd  <= 4'd0;
            cnt_even <= cnt_even + 1'b1;
        end
    end
    else begin
        cnt      <= 3'd0;
        cnt_odd  <= 4'd0;
        cnt_even <= 4'd0;
    end
endalways @(*) begin
    if (cnt_odd == 4'd8 || cnt_even == 4'd7)
        clk_out = 1'b1;
    else
        clk_out = 1'b0;
endendmodule

testbench如下:

`timescale 1ns/1ps
module clk_div_fraction_tb();
​
reg     clk, rst_n  ;
wire    clk_out     ;
​
clk_div_fraction u0(
        .clk        (clk        ),
        .rst_n      (rst_n      ),
        .clk_out    (clk_out    )
    );
​
always #5 clk = ~clk;
​
initial begin
    clk         = 0;
    rst_n       = 1;
    #15 rst_n   = 0;
    #15 rst_n   = 1;
endinitial begin
    #3000 $stop;
endendmodule

仿真结果如下图,可以看到输出时钟5个周期为430ns,满足8.6分频。

3.2 半整数仿真

上述任意小数分频已涵盖N.5分频,但对于N.5分频特殊情况,可以使用更为有效的电路结构优化缩小面积。

例如3.5分频,使用3.1节方法需要1个4分频和1个3分频得到输出时钟,平均的概念使时钟抖动很大,信号质量得不到保证。

用上升沿和下降沿分别产生一个7分频的时钟信号,两个信号距离是3.5个时钟周期。

//3.5分频电路,上升沿下降沿分别产生两个7分频,
//两个信号距离是3.5个时钟周期,逻辑或
module half_div(clk, rstn, clk_out);
input   clk, rstn;
output  clk_out;
​
reg [3:0] p_cnt, n_cnt;
wire p_out, n_out;
​
always @(posedge clk or negedge rstn) begin
    if (!rstn)
        p_cnt <= 0;
    else if (p_cnt < 4'd6)
        p_cnt <= p_cnt + 1;
    else
        p_cnt <= 0;
endalways @(posedge clk or negedge rstn) begin
    if (!rstn)
        n_cnt <= 0;
    else if (n_cnt < 4'd6)
        n_cnt <= n_cnt + 1;
    else 
        n_cnt <= 0;
endassign p_out = p_cnt == 4'd0;
assign n_out = n_cnt == 4'd4;
assign clk_out = p_out || n_out;
​
endmodule

testbench如下:

`timescale 1ns/1ps
module half_div_tb();
​
reg     clk, rst_n  ;
wire    clk_out     ;
​
half_div u0(
        .clk        (clk        ),
        .rstn       (rst_n      ),
        .clk_out    (clk_out    )
    );
​
always #5 clk = ~clk;
​
initial begin
    clk         = 0;
    rst_n       = 1;
    #15 rst_n   = 0;
    #15 rst_n   = 1;
endinitial begin
    #4000 $stop;
endendmodule

仿真结果如下图,输入时钟周期10ns,得到35ns周期3.5分频信号:

 

参考

【数字IC手撕代码】Verilog半整数分频|题目|原理|设计|仿真_myhhhhhhhh的博客-CSDN博客

以及其他资料

 

 

posted @ 2022-03-13 18:27  Strange9  阅读(2086)  评论(0)    收藏  举报