数字电路设计之奇数分频

奇数分频几乎是初学逻辑电路设计时,必然会遇到的一个问题。假如对时钟的占空比没有要求,相信任何一个初学者都可以立马写出分频的RTL代码。而奇数分频的难点就在于对50%占空比的处理,其核心思想就在于要学会利用寄存器的不同捕获边沿进行分频操作。
假设奇数分频的值为2N+1,为了实现占空比为50%的奇数分频,需要用到一个计数器和2路分频信号,第1路根据计数器的值在上升沿分频,即分别在计数器走到N-12N时,进行时钟信号的反转;而第2路则根据计数器的值在下降沿分频,同样是在计数器走到N-12N时,进行时钟信号反转。因为,一个时钟的上升沿和下降沿之间的时间差正好是50%的时钟周期,所以将两路信号进行或逻辑运算,就可以实现50%占空比的奇数分频。
以5分频为例,其时序示意图如下:

Timing.JPG

如图所示,5分频的情况下,计数器计数范围0~4,clk_div1是第1路分频信号,以上升沿为时钟有效沿,在计数值走到1和4时反转,此时占空比为:2/5 = 40%;而clk_div2是第2路分频信号,以下降沿为时钟有效沿,同样在计数值走到0和2时反转,占空比也为: 2/5 = 40%clk_div_out是最终输出的时钟信号,由clk_div1clk_div2相或得到,满足占空比50%的要求。
奇数分频的RTL代码如下:

module clk_div
#(parameter DIV = 3)
(
    input   clk            , // 输入时钟
    input   rst_n          , // 输入复位信号,低有效
    output  clk_div_out      // 输出分频时钟信号
    );


parameter        WIDTH    = $clog2(DIV) ; // 分频计数器位宽计算
parameter        HALF_DIV = (DIV-1)/2   ; // 半分频计数

reg [WIDTH-1:0]               cnt       ; // 分频计数器
reg                           clk_div1  ; // 上升沿分频
reg                           clk_div2  ; // 下降沿分频

assign clk_div_out = clk_div1 | clk_div2 ;    // 上升沿与下降沿分频信号,相或输出最终 50% 占空比时钟

//*************** 分频计数 *******************
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin       
        cnt <= 0;
    end
    else begin
        if (cnt == DIV - 1'b1) begin
            cnt <= 0;
        end
        else begin
            cnt <= cnt + 1'b1;
        end // 
    end
end

//************** 上升沿分频 ******************
always @ (posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        clk_div1 <= 0;
    end // 
    else begin
        if (cnt == HALF_DIV-1) begin
            clk_div1 <= 1'b0;
        end // 
        else if (cnt == DIV-1) begin
            clk_div1 <= 1'b1;
        end //  
        else begin
            clk_div1 <= clk_div1 ;
        end // 
            
    end // 
end // 
    
//************** 下降沿分频 *******************
always @ (negedge clk or negedge rst_n) begin
    if (~rst_n) begin
        clk_div2 <= 0;
    end // 
    else begin
        if (cnt == HALF_DIV-1) begin
            clk_div2 <= 1'b0;
        end // 
        else if (cnt == DIV-1) begin
            clk_div2 <= 1'b1;
        end //  
        else begin
            clk_div2 <= clk_div2 ;
        end // 
            
    end // 
end // 
endmodule

上述代码适用于任意奇数分频,只要给定分频值DIV,其中计数器位宽WIDTH可以通过verilog函数clog2获得,其主要功能是实现求2的对数的功能,并对结果向上取整。
DIV = 3时,代码的RTL图如下所示:

奇数分频RTL.JPG

其实奇数分频的方式很简单,只要利用好触发器下降沿,采用或逻辑,与逻辑还是异或逻辑,都可以得到相应的50%占空比分频信号,只要根据相应的逻辑操作转换相应的信号电平即可,这个可以留给读者自己去探索。

你可能感兴趣的:(数字电路设计之奇数分频)