How to implement the design of odd frequency dividers in Verilog?

 There are two common, FPGA-friendly ways to “divide by an odd number” in Verilog:

  1. Stay in one clock domain and generate a clock-enable (CE) pulse every N cycles. (Best practice.)

  2. If you truly need a new clock with ~50% duty, use both clock edges (posedge + negedge) to alternate half-period lengths. (Use sparingly; route through a clock buffer.)


1) Preferred: odd divider as a clock-enable pulse

This avoids creating a new clock domain and all the CDC/timing pain. Your logic runs on the original clock, gated by a CE that goes high every N cycles.

// Odd (or even) divider -> 1-cycle clock-enable pulse each N cycles module ce_divider #( parameter integer N = 5 // N >= 2 (odd or even) ) ( input wire clk, input wire rst_n, // active-low synchronous reset output reg ce // 1-cycle pulse every N cycles ); localparam W = $clog2(N); reg [W-1:0] cnt; always @(posedge clk) begin if (!rst_n) begin cnt <= '0; ce <= 1'b0; end else begin if (cnt == N-1) begin cnt <= '0; ce <= 1'b1; end else begin cnt <= cnt + 1'b1; ce <= 1'b0; end end end endmodule

Use ce to step your state machines or to toggle a flop:

// Example: make a slow toggling signal using CE (period = 2*N base cycles) reg slow_tog; always @(posedge clk) begin if (!rst_n) slow_tog <= 1'b0; else if (ce) slow_tog <= ~slow_tog; end

 Pros: one clean clock domain, simple timing, portable to all FPGAs/ASICs.


2) If you must output a 50% clock for odd N

A 50% duty cycle with odd division isn’t possible with a single edge. The trick is to toggle the output on alternating counts so that one half-cycle lasts floor(N/2) input cycles and the other half lasts ceil(N/2) input cycles. Implement that by using both edges (posedge/negedge) of the input clock (or by counting edges).

Generic odd divider with ~50% duty (uses both edges)

// Generate ~50% duty clock for odd N by alternating half-period lengths. // WARNING: Produces a new clock domain. On FPGA, route clk_out via a global buffer (e.g., BUFG). module clk_div_odd #( parameter integer N = 5 // N must be odd >= 3 ) ( input wire clk, // base clock input wire rst_n, output reg clk_out ); // Half-periods: one is floor(N/2), the other is ceil(N/2) localparam integer A = N/2; // floor localparam integer B = N - A; // ceil // Count *edges* (both posedge and negedge) by sampling on both edges. // We implement two small counters, one for each edge domain, then OR their terminal events. reg [$clog2(B):0] cnt_pos; reg [$clog2(B):0] cnt_neg; reg sel_pos; // which half to generate on posedge reg sel_neg; // which half to generate on negedge // On posedge: count to A or B depending on phase select, then toggle always @(posedge clk) begin if (!rst_n) begin cnt_pos <= 0; sel_pos <= 1'b0; // start with short half on posedge end else begin if (cnt_pos == (sel_pos ? B-1 : A-1)) begin cnt_pos <= 0; sel_pos <= ~sel_pos; clk_out <= ~clk_out; // toggle on posedge completion end else begin cnt_pos <= cnt_pos + 1'b1; end end end // On negedge: same idea, alternate the other half lengths always @(negedge clk) begin if (!rst_n) begin cnt_neg <= 0; sel_neg <= 1'b1; // start with long half on negedge end else begin if (cnt_neg == (sel_neg ? B-1 : A-1)) begin cnt_neg <= 0; sel_neg <= ~sel_neg; clk_out <= ~clk_out; // toggle on negedge completion end else begin cnt_neg <= cnt_neg + 1'b1; end end end endmodule

Notes:

  • This makes clk_out toggle after A edges, then B edges, alternating → average 50% duty for odd N.

  • In most FPGAs it’s better to avoid dual-edge always blocks. An alternative is to count both edges using an input DDR primitive (IDDR) or by doubling the reference with a PLL/MMCM and then dividing by an even number.

  • If you must distribute clk_out, feed it into a global clock buffer (e.g., BUFG/BUFGCTRL on Xilinx, Global Clock on Intel) to avoid skew.

  • Prefer PLL/MMCM/DCM/Clocking resources for clocks. Use fabric logic only when absolutely necessary.


Concrete, simple examples

A) Divide-by-3 (50% duty) using posedge+negedge counters (classic)

module clk_div3 ( input wire clk, input wire rst_n, output wire clk_div3 ); reg [1:0] cnt_p, cnt_n; always @(posedge clk) begin if (!rst_n) cnt_p <= 2'd0; else cnt_p <= (cnt_p == 2'd2) ? 2'd0 : cnt_p + 2'd1; end always @(negedge clk) begin if (!rst_n) cnt_n <= 2'd0; else cnt_n <= (cnt_n == 2'd2) ? 2'd0 : cnt_n + 2'd1; end // Two phase clocks, OR them to get ~50% duty at /3 wire clk_p = (cnt_p == 2'd0); wire clk_n = (cnt_n == 2'd1); assign clk_div3 = clk_p | clk_n; // ~50% duty endmodule

B) Divide-by-5 (50% duty) with alternating half-period counts

Use the clk_div_odd generic above with N=5; it alternates 2 and 3 input edges per half-cycle.


What should you use when?

  • Most FPGA designs: Use the CE pulse method (Section 1). Keep a single clock domain; gate logic with ce.

  • When an external block needs a real slower clock (and you can’t use a PLL/MMCM):

    • Try to use a vendor clocking primitive (PLL/MMCM/DCM/BUFGCE_DIV).

    • If not possible, the both-edges fabric divider works, but route through a clock buffer and constrain it.


Quick testbench skeleton (for the CE divider)

module tb_ce_divider; reg clk = 0, rst_n = 0; wire ce; // 100 MHz clock always #5 clk = ~clk; ce_divider #(.N(5)) dut (.clk(clk), .rst_n(rst_n), .ce(ce)); initial begin $dumpfile("tb.vcd"); $dumpvars(0, tb_ce_divider); repeat (4) @(posedge clk); rst_n = 1; repeat (100) @(posedge clk); $finish; end endmodule

评论

此博客中的热门博文

How To Connect Stm32 To PC?

How do you set up ADC (Analog-to-Digital Converter) in STM32?

What is a Look-Up Table (LUT) in an FPGA, and how does it work?