在 Verilog 中从 50 MHz 时钟生成 100 Hz 时钟

电器工程 FPGA 验证日志
2022-01-09 07:26:19

我有一个带有 50 Mhz 时钟的 DE0 板,我试图在 Verilog 中将其降低到 100 Hz。谁能帮我写代码来做到这一点?

1个回答

建立一个 18 位计数器。每次达到 250,000 时,触发触发器。50 兆赫/250,000 = 200 赫兹。以 200 Hz 切换引脚可为您提供 100 Hz 和 50% 的占空比。如果您只需要一个重复频率为 100 Hz 的脉冲,那么构建一个 19 位计数器并在达到 500,000 时生成一个脉冲。

幸运的是,250,000 和 500,000 都是偶数。使用奇数除数生成完美的 50% 占空比意味着您需要在上升沿打开输出,在下降沿关闭输出。在 Xilinx FPGA 上,这可以通过 ODDR/ODDR2 和带有一点头的计数器来完成,以正确设置 D0/D1 输入。不过,这仅适用于通过 I/O 引脚将信号从芯片发送出去,因为 ODDR/ODDR2 的输出不能在设计中使用。不过,脉冲确实是您在设计中所需要的。

生成具有非整数比率的任何东西都更加复杂。如果它是一个有理分数,您可以单独使用 PLL 或 DDS 来提供帮助,或者与计数器结合使用。如果它不是一个有理分数,那么除非你能用一个有理分数来近似它,否则你或多或少地不走运。如果 PLL 不可用、不够低,或者您无法从 PLL 和计数器组合中获得正确的比率,那么您可以使用小数 DDS。小数 DDS 的想法是在每个时钟周期向累加器添加一个常数,并在累加器翻转时切换输出。这将产生一个带有一点抖动的输出,但它可以产生一个平均精确的频率。要使用 32 位累加器产生 100 Hz 50% 占空比的方波,您需要做的就是添加 100*2^32/50e6 = 8589。93459 ~= 8590 每个时钟周期。累加器的 MSB 将在 50e6/(2^32*8590) = 100.00076145 Hz 处切换。累加器越大,这将越准确。32 位累加器的频率分辨率非常好——如果上升或下降 1 LSB,则得到 98.989119 或 100.012403 Hz。但是,您将获得所谓的确定性抖动的 +/- 1 个时钟周期。换句话说,边沿由时钟周期量化,因此可以提前或延迟多达 1/2 个时钟周期。与常规抖动不同,如果您在示波器上查看确定性抖动,您将看到具有两个或多个离散平均值的非常双峰的周期时间分布,而不是一个平滑分布。此外,由于 .00076145 是偏移量而不是平均值,因此相位将相对于系统时钟缓慢移动。

以 50% 占空比从 50 MHz 生成 100 Hz 的示例 verilog:

// generate 100 Hz from 50 MHz
reg [17:0] count_reg = 0;
reg out_100hz = 0;

always @(posedge clk_50mhz or posedge rst_50mhz) begin
    if (rst_50mhz) begin
        count_reg <= 0;
        out_100hz <= 0;
    end else begin
        if (count_reg < 249999) begin
            count_reg <= count_reg + 1;
        end else begin
            count_reg <= 0;
            out_100hz <= ~out_100hz;
        end
    end
end

从 50 MHz 时钟生成 100 Hz 重复 10 ns 脉冲的示例 verilog:

// generate 100 Hz pulse chain from 50 MHz
reg [18:0] count_reg = 0;
reg out_100hz = 0;

always @(posedge clk_50mhz or posedge rst_50mhz) begin
    if (rst_50mhz) begin
        count_reg <= 0;
        out_100hz <= 0;
    end else begin
        out_100hz <= 0;
        if (count_reg < 499999) begin
            count_reg <= count_reg + 1;
        end else begin
            count_reg <= 0;
            out_100hz = 1;
        end
    end
end

示例 verilog 从 Spartan 6 上的 ODDR2 的 250 MHz 时钟生成具有 50% 占空比的 10 MHz 输出:

// generate 10 MHz from 250 MHz
// 25 cycle counter, falling edge interpolated
reg [4:0] count_reg = 0;
reg q0 = 0;
reg q1 = 0;

always @(posedge clk_250mhz or posedge rst_250mhz) begin
    if (rst_250mhz) begin
        count_reg <= 0;
        q0 <= 0;
        q1 <= 0;
    end else begin
        if (count_reg < 24) begin
            count_reg <= count_reg + 1;
        end else begin
            count_reg <= 0;
        end
        q0 <= count_reg < 12;
        q1 <= count_reg < 13;
    end
end

ODDR2
clk_10mhz_out_oddr2_inst
(
    .Q(clk_10mhz_out),
    .C0(clk_250mhz),
    .C1(~clk_250mhz),
    .CE(1),
    .D0(q0),
    .D1(q1),
    .R(0),
    .S(0)
);

使用累加器以 50% 占空比从 50 MHz 生成 100 Hz 的示例 verilog 代码:

// generate 100 Hz from 50 MHz
reg [31:0] count_reg = 0;
wire out_100hz = count_reg[31];

always @(posedge clk_50mhz or posedge rst_50mhz) begin
    if (rst_50mhz) begin
        count_reg <= 0;
    end else begin
        count_reg <= count_reg + 8590; //(((100 * 1 << 32) + 50000000/2) / 50000000)
    end
end