Design Question - Clock Dividers and Duty Cycle

The ubiquitous Divide-by-3 Counter with 50% Duty Cycle and its siblings.

In RTL Design interviews, it's common to encounter questions about clock divider circuits. While many interviewees might have quick answers ready from a cursory Google search, this topic has much more depth that often goes unexplored. This post aims to delve into practical implementations, going beyond general knowledge.

Need for a Clock Divider

Clock divider circuits reduce clock frequency for slower components, generate multiple clocks, and synchronize data between different clock speeds. They manage power by enabling slower speeds, adjust timing, and are used in PWM and motor control. They aid in serial communication, simplify testing by slowing speeds, and are crucial in digital filters for specific sampling rates.

Interview Questions

  • Design a Clock Divider circuit to divide the input clock by a factor of 4 (or any other power of 2)
  • Design a Clock Divider circuit to divide the input clock by a factor of 3 (or any other odd number)
    • Modify the design to generate an output clock with 50% duty cycle

Solution - Divide by 4 Circuit

The divide by 4 (or any other power of 2, or for that matter any even number) circuit is a simple counter that runs from 0 to n-1 (in this case, 3) and then rolls over back to 0.

If you are dividing the incoming clock by a factor of 4, the output should have one rising edge for every set of four rising edges of the input clock.

The counter cycles through the values 0123. For two consecutive states of the counter, the output should be a 0, and for the other two states it should be a 1.

A snippet of code for the Divide by 4 counter -

logic [ 1: 0]  sig_div4_cnt; 

// Divide by 4 counter
always_ff @(posedge clk)
begin
   if (rst)
   begin
      sig_div4_cnt <= '0;
   end
   else
   begin
      sig_div4_cnt <= sig_div4_cnt + 1;
   end
end

// Generating the divided down version of clk
assign clk_div_4 = sig_div4_cnt[1];

Divide by 4 Counter

In the above example, the MSB of the 2-bit counter is used to hold the output LOW in counter states 0 and 1, and HIGH in the other two states of the counter.

One additional advantage of implementing the output this way, instead of using a case or an if-else statement is that the output is sequential, as opposed to combinatorial.

Can you figure out a way to generate the output clock with a 25% duty cycle?

Solution - Divide by 3 Circuit

Division by odd numbers is where things start getting a little trickier. The design concept is still the same as the earlier example. We have a 2-bit counter that runs from 0 to 2 and then gets reset to 0. The counter now has 3 states, 01 and 2. Assuming we do not have the 50% duty cycle requirement, we can simply design the circuit as follows -

logic [ 1: 0]  sig_div3_cnt;

// Divide by 3 counter
// No duty-cycle management
always_ff @(posedge clk)
begin
   if (rst)
   begin
      sig_div3_cnt <= '0;
   end
   else if (sig_div3_cnt == 2'd2)       // Roll over back to 0
   begin
      sig_div3_cnt <= '0;
   end
   else
   begin
      sig_div3_cnt <= sig_div3_cnt + 1;
   end
end

// Generating the divided down version of clk
assign sig_clk_div_3 = (sig_div3_cnt == 2) ? 1'b1 : 1'b0;
assign clk_div_3     = sig_clk_div_3;

Divide by 3 Counter

This generates an output clock with 33% duty cycle.

Pasted image 20241011164043.png

In order to create an output with 50% duty cycle, we need the output, clk_div_3 to be asserted for another half clock cycle. Referring to the diagram below, the extended output is shown in orange.

Pasted image 20241011164418.png

In order to drive any signal for half a clock cycle, we have to utilize the negative edge of the clock.
Let's take the Divide by 3 circuit explained earlier and add this additional functionality.

// For 50% dutycycle, we need the output to be asserted
// for half a clock cycle more
always_ff @(negedge clk)
begin
   sig_clk_div_3_ne <= sig_clk_div_3;
end

// Generating the divided down version of clk (50% duty cycle)
assign clk_div_3_dc50 = sig_clk_div_3 | sig_clk_div_3_ne;

Divide by 3 Counter (with 50% duty cycle)

Pasted image 20241011165022.png

The primary downside of this design is that the generated output signal is combinatorial.

Practical Considerations for FPGA Design

This is an absolutely horrible way to generate divided down versions of the master clock in an FPGA design. Clocks in an FPGA have a certain status and have their own exclusive, low-jitter distribution routing. Signals from the FPGA fabric cannot easily enter this special clock routing network. As can be seen from above examples, the generated clocks are either on the Q output of a Flip-Flop or are purely combinatorial. Driving a bunch of sequential logic from a clock generated in this manner will cause a lot of issues in an FPGA.

For the 50% duty cycle design, one must realize that the path from sig_clk_div_3 to sig_clk_div_3_ne is required to be traversed in half a clock cycle. This puts an extra burden on the synthesis tools.

Considerations for Clock Dividers in an FPGA

Xilinx FPGAs have dedicated clock management resources that can take care of clock division. Users have access to PLLs and their superset, MMCMs (Mixed Mode Clock Managers). For simple division, the Xilinx primitive BUFGCE_DIV can be used.

Takeaways

While these questions are understandable for interview purposes, it is important to recognize that, in proactive, clock division in FPGAs is typically achieved using dedicated FPGA primitives. Achieving a 50% duty cycle output clock becomes complex when dealing with odd division factors and requires utilizing both clock edges.

Subscribe to fpgadesign.io

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe