硬件架构的艺术:时钟分频器

1. 概述

  时钟分频器按照分频系数可以为整数或小数,整数中又分为奇数和偶数,本文将分析以上几种分频器的设计方法。

2. 整数分频器

  偶数分频器的实现比较简单,通过计数器即可实现,奇数分频器略微复杂。

2.1 偶数分频器

2.1.1 设计原理及结构

  偶数分频器的结构如下图所示,主要由计数器和时钟生成模块组成。其中分频系数为N时,计数器的计数范围为[0,N/2-1],时钟生成模块输出时钟在计数器输出为N/2-1时取反。

在这里插入图片描述
  

2.1.2 代码实现

//=================================================================================
// module      : clk_even_div.v
// description : clock divide by even number
// data        : 2022/3/16
// author      : souther meditating
//=================================================================================
module clk_even_div{
    clk_i,
    rsti_n,
    clk_o
};

//=================================================================================
// parameter & localparam
//=================================================================================

//=================================================================================
// parameter
parameter DIV_NUM               = 'd4;

//=================================================================================
// localparam
localparam DIV_NUM_WIDTH        = clog2(DIV_NUM);
localparam DIV_NUM_HALF         = DIV_NUM/2;

//=================================================================================
// I/O
//=================================================================================
input                               clk_i;
input                               rsti_n;
output                              clk_o;

//=================================================================================
// signal
//=================================================================================
reg     [DIV_NUM_WIDTH-1:0]         count;
wire    [DIV_NUM_WIDTH-1:0]         div_num_half_m1;

//=================================================================================
// main body
//=================================================================================

//=================================================================================
// 1. count div_num_half

assign div_num_half_m1 = DIV_NUM_HALF - 'd1;

always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        count <= {DIV_NUM_WIDTH{1'b0}};
    end
    else if(count == div_num_half_m1) begin
        count <= {DIV_NUM_WIDTH{1'b0}};
    end
    else begin
        count <= count + 'b1;
    end
end

//=================================================================================
// 2. generate output clock
always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        clk_o <= 1'b0;
    end
    else if (count == div_num_half_m1) begin
        clk_o <= ~clk_o;
    end
end

endmodule

2.2 奇数分频器

  奇数分频器有两种实现方法,一种是Mohit Arora提出的“生成两个相位相差90度,频率为目标频率一半的时钟(该时钟为源时钟的偶数分频)”,另一种方法是“产生两个相位相差90度,频率为目标频率一半的时钟,但该时钟占空比不等于50%”。

2.2.1 方法一(Mohit Arora)

2.2.1.1 设计原理及结构

  Mohit Arora的方法分为四步:
  1) 产生一个计数器,计数范围为[0,N-1];
  2) 根据计数值产生两个信号,cnt=0时tff1_en有效,cnt=(N+1)/2时tff2_en有效;
  3) 根据tff1_en和tff2_en产生两个分频时钟,div1在时钟上升沿且tff1_en有效时取反,div2在时钟下降沿且tff2_en有效时取反;
  4) 将div1和div2异或输出。
  下图为分频系数等于3时的波形,通过90度的相位差得到奇数分频的系数,而且最后的输出时钟不会存在毛刺。
在这里插入图片描述
  奇数分频的结构图如下所示,共包含3个寄存器。
在这里插入图片描述

2.2.1.2 代码实现
// module      : clk_div_odd_func0.v
// description : clock divide by odd number
// data        : 2022/3/16
// author      : souther meditating
//=================================================================================
module clk_div_odd_func0{
    clk_i,
    rsti_n,
    clk_o
};

//=================================================================================
// parameter & localparam
//=================================================================================

//=================================================================================
// parameter
parameter DIV_NUM               = 'd5;

//=================================================================================
// localparam
localparam DIV_NUM_WIDTH        = clog2(DIV_NUM);
localparam DIV_NUM_M1           = DIV_NUM - 1;



//=================================================================================
// I/O
//=================================================================================
input                               clk_i;
input                               rsti_n;
output                              clk_o;

//=================================================================================
// signal
//=================================================================================
reg [DIV_NUM_WIDTH-1:0]             count;

wire                                tff1_en;
wire                                tff2_en;

reg                                 div1;
reg                                 div2;

//=================================================================================
// main body
//=================================================================================

//=================================================================================
// N divide clock,duty clock not 50%

always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        count <= {DIV_NUM_WIDTH{1'b0}};
    end
    else if (count == DIV_NUM_M1) begin
        count <= {DIV_NUM_WIDTH{1'b0}};
    end
    else begin
        count <= count + 'd1;
    end
end

assign tff1_en = (count == {DIV_NUM_WIDTH{1'b0}});
assign tff2_en = (count == (DIV_NUM+1)/2);

//=================================================================================
// generate two clock,difference of phase is 90 deg

always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        div1 <= 1'b0;
    end
    else if (tff1_en == 1'b1) begin
        div1 <= ~div1;
    end
end

always @(negedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        div2 <= 1'b0;
    end
    else if (tff2_en == 1'b1) begin
        div2 <= ~div2;
    end
end

assign clk_o = (div1 ^ div2);

endmodule

2.2.2 方法二

2.2.2.1 设计原理及结构

  方法二也可以分为4步:
  1) 产生一个计数器,计数范围[0,N-1];
  2) 产生占空比为((N-1)/2)/N的N分频时钟;
  3) 分别在上升沿和下降沿对该时钟采样,得到div1和div2,此时div1和div2为相位差90度的N分频时钟,但占空比仍为((N-1)/2)/N;
  4) Div1和div2进行“或”操作,得到占空比为50%的N分频时钟。
  方法二的奇数分频结构图如下所示。

在这里插入图片描述

2.2.2.2 代码实现
// module      : clk_div_odd_func1.v
// description : clock divide by odd number
// data        : 2022/3/16
// author      : souther meditating
//=================================================================================
module clk_div_odd_func1{
    clk_i,
    rsti_n,
    clk_o
};

//=================================================================================
// parameter & localparam
//=================================================================================

//=================================================================================
// parameter
parameter DIV_NUM               = 'd5;

//=================================================================================
// localparam
localparam DIV_NUM_WIDTH        = clog2(DIV_NUM);
localparam DIV_NUM_M1           = DIV_NUM - 1;
localparam DIV_NUM_M1_HALF      = (DIV_NUM - 1)/2;



//=================================================================================
// I/O
//=================================================================================
input                               clk_i;
input                               rsti_n;
output                              clk_o;

//=================================================================================
// signal
//=================================================================================
reg [DIV_NUM_WIDTH-1:0]             count;

reg                                 clk_div_n;
wire                                clk_turn_flag;

reg                                 div1;
reg                                 div2;

//=================================================================================
// main body
//=================================================================================

//=================================================================================
// N divide clock,duty clock is ((N-1)/2)/N

always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        count <= {DIV_NUM_WIDTH{1'b0}};
    end
    else if (count == DIV_NUM_M1) begin
        count <= {DIV_NUM_WIDTH{1'b0}};
    end
    else begin
        count <= count + 'd1;
    end
end

assign clk_turn_flag = ((count == {DIV_NUM_WIDTH{1'b0}}) || (count == DIV_NUM_M1_HALF));

always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        clk_div_n <= 1'b0;
    end
    else if (clk_turn_flag == 1'b1) begin
        clk_div_n <= ~clk_div_n;
    end
end

//=================================================================================
// generate two clock,difference of phase is 90 deg

always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        div1 <= 1'b0;
    end
    else begin
        div1 <= clk_div_n;
    end
end

always @(negedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        div2 <= 1'b0;
    end
    else begin
        div2 <= clk_div_n;
    end
end

assign clk_o = (div1 | div2);

endmodule

3. 小数分频器

3.1 设计原理及结构

  Mohit Arora提出了一种基于移位寄存器的小数分频器的设计方法,但时钟占空比不等于50%。以4.5分频为例,在9个时钟内要产生两个重复的脉冲,该方法可以分为三步:
  1) 定义9bit寄存器count,复位时count=9’b0_0000_0001,在时钟的上升沿对count进行逻辑左移;
  2) 在时钟的下降沿对count[0]进行采样得到count_0_deg90,将count[0]、count[1]、count_0_deg90相与,得到第一个脉冲的高电平;
  3) 在时钟的下降沿对count[4]、count[5]进行采样得到count_4_deg90、count_5_deg90,将count[5]、count_4_deg90、count_5_deg90相与,得到第二个脉冲的高电平。
  引用Mohit Arora的波形图,其中波形中的第0bit为count[1],需要特别注意。
在这里插入图片描述

3.2 代码实现

// module      : clk_div_decimal.v
// description : clock divide by decimal
// data        : 2022/3/16
// author      : souther meditating
//=================================================================================
module clk_div_decimal{
    clk_i,
    rsti_n,
    clk_o
};

//=================================================================================
// parameter & localparam
//=================================================================================

//=================================================================================
// parameter decimal = numerator/denominator
parameter DIV_DENOM             = 'd2;
parameter DIV_NUMER             = 'd9;
parameter DIV_COUNT             = 'd9;

//=================================================================================
// localparam

//=================================================================================
// I/O
//=================================================================================
input                               clk_i;
input                               rsti_n;
output                              clk_o;

//=================================================================================
// signal
//=================================================================================
reg [DIV_COUNT-1:0]                 count;

reg                                 ps_count0;
reg                                 ps_count4;
reg                                 ps_count5;

//=================================================================================
// main body
//=================================================================================

//=================================================================================
// count implementation , reset value is 9'd0_0000_0001

always @(posedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        count <= 9'b0_0000_0001;
    end
    else begin
        count <= (count << 1);
    end
end

//=================================================================================
// count bit 0,4,5 phase shifter 180

always @(negedge clk_i or negedge rsti_n) begin
    if (rsti_n == 1'b0) begin
        ps_count0 <= 1'b0;
        ps_count4 <= 1'b0;
        ps_count5 <= 1'b0;
    end
    else begin
        ps_count0 <= count[0];
        ps_count4 <= count[4];
        ps_count5 <= count[5];
    end
end

//=================================================================================
// generate decimal clock

assign clk_o = (ps_count0 || count[0] || count[1]) ||   // first pluse
               (ps_count4 || ps_count5 || count[5]);    // second pluse


endmodule
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值