EDN Access

 

August 15, 1997


VHDL code implements 50%-duty-cycle divider

Brian Boorman, Harris RF Communications, Rochester, NY

Realizing a 50%-duty-cycle, divided-down clock is not always a trivial task, particularly when the divisor rate is an odd number. You can use the VHDL source code in Listing 1 to synthesize an FPGA or a CPLD circuit that produces a 50%-duty-cycle waveform for any integer N greater than 0. This code uses synchronous clock transitions to generate all logic-output changes, thereby eliminating the use of "glitch logic." Figure 1 shows the resulting waveforms when you use the code to generate a divide-by-5 counter. (Click here to download the listing DI-SIG, #2060.)

The code includes a package-declaration section, so a simple use clause makes this section visible in a higher level design. The architecture of the design requires three inputs. The first parameter, which makes this design powerful, is a natural number that indicates the divisor rate. If you do not specify the number, it defaults to three. The second and third parameters are an active-high asynchronous reset signal and a clock-input signal, respectively. The code assumes that the input clock is a 50%-duty-cycle square wave for odd division. If this situation does not occur, the odd divisor may not work properly. Assuming 50%-duty-cycle input, the output after an asynchronous reset is 50%-duty-cycle within N input-clock periods.

The first part of the architecture section creates a constrained subtype of natural, which effectively tells the synthesizer how many bits wide the generated counter should be. The next part checks that the generic parameter is greater than 0, forcing the compiler (or simulator) to halt if that is not the case.

The next section uses four "if...generate" clauses to create logic as needed for the following cases: N=1, N=2, N>2 and odd, and N>2 and even. If N=1, the code generates a buffered clock that goes low whenever reset is active. When N=2, the code generates a T flip-flop. Again, the clock output is low whenever reset is active.

The third generate statement, gOdd, contains the most useful part of the design. Conceptually, the easiest way to create an add divider with a 50% duty cycle is to generate two clocks at half the desired output frequency with a quadrature-phase relationship. You can then generate the output frequency by exclusive-ORing the two waveforms together. Because of the constant 90° phase offset, only one transition occurs at a time on the input of the exclusive-OR gate, effectively eliminating any glitches on the output waveform.

This section begins by creating a counter that counts from 0 to N­1 and always clocks on the rising edge of clkin. The code then uses the output count to create the combinatorial signals, en_tff1 and en_tff2. These signals are enable signals for T flip-flops pOddDiv1 and pOddDiv2, which generate the divide-by-2N waveforms. Note that pOddDiv1 clocks on the rising edge of clkin and that pOddDiv2 clocks on the falling edge of clkin. This arrangement makes it possible to generate a quadrature offset between the two waveforms when the divisor is odd. Also note that this arrangement creates a timing constraint. The net en_tff2 has an effective clock-frequency-timing constraint of twice the input-clock frequency. If the input clock is a high frequency, make sure that the design meets its timing requirements. The final line of this section exclusive-ORs the two waveforms to generate the output, and the output is low when reset is active.

The last generate statement, gEven, creates an even divisor circuit. Again, the code creates a counter that counts from 0 to N­1. This circuit always clocks using the rising edge of clkin, so a 50% duty cycle is unnecessary for these divisors. The output is low when reset is active. (DI #2060)


Figure 1

15di2060

The VHDL code for a 50%-duty-cycle divider creates various timing relationships, such as that for a divide-by-5 implementation.
Listing 1 --VHDL code for 50%-duty-cycle divider
library ieee;

use ieee.std_logic_1164.all;

package clk_ctrl is

component clkdiv
  generic(
    n: natural;
  );
port(
    clkin: in std_logic;
reset: in std_logic;
clkout: out std_logic
  );
end component;

end clk_ctrl;

library ieee;

use ieee.std_logic_1164.all;

entity clkdiv is
  generic(
    n: natural := 3
  );
port(
    clkin: in std_logic; — 50% Duty Cycle Input Clock

reset: in std_logic; — Active high reset

clkout: out std_logic

  );
end clkdiv;

architecture fpga of clkdiv is

  — This subtype will constrain counter width.
subtype divtype is natural range 0 to n-1;

signal counter: divtype;
signal en_tff1: std_logic;
signal en_tff2: std_logic;
signal div1: std_logic;
signal div2: std_logic;

begin

  assert ( n > 1 )
    report "Clock divisor must be a positive number > 0!" severity failure;
  gOne: if (n=1) generate — pass clock through, gated low by reset
    clkout <= clkin when reset = ‘0’ else ‘0’;
  end generate;

gTwo: if (n=2) generate — generate a T Flip-Flop
    pTwo: process(clkin, reset, div1)
begin
      if reset = ‘1’ then
        div1 <= ‘0’;
      elsif rising_edge(clkin) then
        div1 <= not(div1);
      end if;
    end process;

clkout <= div1;
  end generate;

— Check if N is odd and greater than 2
gOdd: if ((((n/2)*2)) = (n-1)) and (n>2)) generate
    pOdd: process(clkin, reset, counter, load1)
begin
      if (reset = ‘1’) then
        counter <= 0;
      elsif rising_edge(clkin) then
        if (counter = (n-1)) then
          counter <= 0;
        else
          counter <= counter + 1;
        end if;
      end if;
    end process;

en_tff1 <= ‘1’ when counter = 0 else ‘0’;
en_tff2 <= ‘1’ when counter = (((n-1)/2)+1) else ‘0’;

pOddDiv1: process(clkin, reset, en_tff1, div1)
begin
      if (reset = ‘1’) then
        div1 <= ‘1’;
      elsif rising_edge(clkin) then
        if (en_tff1 = ‘1’) then
          div1 <= not(div1);
        end if;
      end if;
    end process;

pOddDiv2: process(clkin, reset, en_tff2, div2)
begin
      if (reset = ‘1’) then
        div2 <= ‘1’;
      elsif falling_edge(clkin) then
        if (en_tff2 = ‘1’) then
          div2 <= not(div2);
        end if;
      end if;
    end process;

clkout <= div1 xor div2;
  end generate;

— Check if N is even and greater than 2
gEven: if ((((n/2)*2)) = n) and (n>2)) generate
    pEvenDiv: process(clkin, reset, counter)
begin
      if (reset = ‘1’) then
        counter <= 0;
      elsif rising_edge(clkin) then
        if (counter = (n-1)) then
          counter <= 0;
        else
          counter <= counter + 1;
        end if;
      end if;
    end process;

en_tff1 <= ‘1’ when ( (counter = 0) or (counter = ((n/2)-1)) ) else ‘0’;

pEvenDiv1: process(clkin, reset, en_tff1, div1)
begin
      if (reset = ‘1’) then
        div1 <= ‘0’;
      elsif rising_edge(clkin) then
        if (en_tff1 = ‘1’) then
          div1 <= not(div1);
        end if;
      end if;
    end process;

clkout <= div1;
  end generate;
end fpga;

| EDN Access | Feedback | Table of Contents |


Copyright © 1997 EDN Magazine, EDN Access. EDN is a registered trademark of Reed Properties Inc, used under license. EDN is published by Cahners Publishing Company, a unit of Reed Elsevier Inc.