使能时钟的设计,使用时能时钟代替分频时钟

1 使能时钟分频

        FPGA 内部时钟使用逻辑计数分频产生的时钟,一般不推荐直接将其用于内部逻辑。若不希望使用 PLL 资源,可以考虑使用使能时钟进行分频。

        使能时钟进行分频的好处:

        (1)避免时钟过多,会造成不稳定;

        (2)保持一个时钟,减少跨时钟域;

        (3)时序设计可以使用 “ 多周期约束 ” 。

2 举例

        (1)设计要求

                输入时钟 100MHz ,产生 5MHz 的使能时钟信号,并利用此使能时钟信号进行 0 到 15 的周期计数。

        (2)设计思路

                输入时钟 100MHz ,使能时钟信号 5MHz ,100MHz/5MHz = 20 ,说明利用输入时钟进行 20 分频产生使能时钟信号。

                需要注意,使能时钟信号与普通的低频信号不同。以同样是 10 分频举例,普通的低频信号设置为前 10 个时钟内是高电平,后 10 个时钟内是低电平;使能信号设置为前 19 个时钟内是低电平,最后 1 个时钟内是高电平。具体如图:

3 Verilog 代码

`timescale 1ns / 1ps
// 使能时钟分频
// 需求说明:
// 1 输入时钟 100 MHz ,输出使能时钟信号 5 MHz 。
// 2 使用使能信号进行 0 ~ 15 的周期计数。

// 设计思路:
// 1 100MHz/5MHz = 20 ,即输入信号做 20 分频。
// 2 设置计数器 cnt_div ,对输入信号做 0 到 19 的计数实现分频。
// 3 使能信号与普通的分频不同,只有在 20 分频的最后一个输入时钟是高电平,其余时刻是低电平。即 cnt_div 是 0 到 18 时 clk_en 是低电平,cnt_div 是 19 时 clk_en 是高电平。



module divider(
    input clk,          // 100MHz
    input rst_n,

    output reg clk_en,
    output reg [3:0] cnt_16
    );

    reg [4:0] cnt_div;                           // 分频计数器
    localparam cnt_div_max = 5'd19;             // 分频计数器的最大值
    localparam cnt_16_max = 4'd15;              // 利用使能信号进行计数的最大值

    // 分频计数器 cnt_div 的初始化和赋值
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_div = 4'd0;
        end
        else begin
            if(cnt_div < cnt_div_max)
                cnt_div = cnt_div + 1'b1;
            else
                cnt_div = 5'd0;
        end
    end

    // 使能时钟信号 clk_en 的产生
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            clk_en = 1'b0;
        end
        else begin
            if(cnt_div == cnt_div_max)          // 使能时钟信号只有在 20 分频时钟周期的最后一个时钟是高电平
                clk_en = 1'b1;
            else
                clk_en = 1'b0;
        end
    end

    // 计数器 cnt_16 的初始化和赋值
    // 利用使能时钟进行 0 到 15 的计数
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_16 = 4'd0;
        end
        else begin
            if(cnt_16 == cnt_16_max + 1 )                        // 使能时钟信号只有在 20 分频时钟周期的最后一个时钟是高电平
                cnt_16 = 4'd0;
            else begin
                if(clk_en)
                    cnt_16 = cnt_16 + 1'b1;
                else
                    cnt_16 = cnt_16;
            end
        end
    end

endmodule

4 Testbench 代码

`timescale 1ns / 1ps

module divider_tb;

parameter CLK_PERIOD = 10;  // 输入信号频率是 100MHz ,所以输入信号的时钟周期是 10ns

reg clk;
reg rst_n;
wire  clk_en;
wire  [3:0]cnt_16;

// 例化待测文件的顶层模块,其端口与 tb 中的激励信号连接
divider divider_0( .clk(clk), .rst_n(rst_n), .clk_en(clk_en), .cnt_16(cnt_16) );     

// 时钟信号和复位信号的初始化
initial begin
    #1;
    clk = 0;                    // 初始时没有时钟信号

    rst_n = 1;                  // 初始时复位信号为高电平
    #1;                         // 经过 1 X 1ns = 1ns 后,复位信号为低电平
    rst_n = 0;
    #(CLK_PERIOD*2);            // 经过 2 个 CLK_PERIOD 后,复位信号为高电平
    rst_n = 1;
end

always #(CLK_PERIOD/2) clk = ~clk;      // 时钟信号每 5 ns 跳变一次

initial begin
    @(posedge clk);             // 等待复位信号结束的第一个输入信号的上升沿开始产生激励信号
    @(posedge rst_n);

    // 从 0 到 15 计数需要 16 个使能信号,1 个使能信号需要 20 个时钟信号,所以使能信号计数 1 轮需要 20*16 个时钟信号。
    // 想要观察到 6 轮计数,所以需要产生 20*16*6 个时钟信号的上升沿作为激励
    repeat(20*16*6) begin
        @(posedge clk);
    end

    #10_000;                    // 仿真持续 10_000 ns 后停止
    $stop;
end

endmodule

5 仿真波形

        使能信号周期 200000 ps ,即 5MHz 。

6 存在的问题

        

        设计的思路是在使能信号为高电平时,计数器 cnt_16 加 1 。但根据波形可以看出在 clk_en 高电平时 clk_16 没有加 1 ,产生了滞后。

        改进的思路是:改变 cnt_16 加 1 的触发条件,同时改变 cnt_16 的复位条件,如下:

    // 计数器 cnt_16 的初始化和赋值
    // 利用使能时钟进行 0 到 15 的计数
    always @(posedge clk_en or negedge rst_n) begin
        if(!rst_n) begin
            cnt_16 = 4'd0;
        end
        else begin
            if(cnt_16 == cnt_16_max)
                cnt_16 = 4'd0;
            else
                cnt_16 = cnt_16 + 1'b1;
        end
    end

(注意与前述的 verilog 代码的 cnt_16 赋值块进行对比)

        新的波形:

        可以看出,在 clk_en 为高电平时,cnt_16 进行了加 1 操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值