Creating a frequency divider in VHDL

medivh picture medivh · Jun 7, 2011 · Viewed 8.8k times · Source

MAJOR EDIT:

Problem was solved after reading Will Dean's comment. The original question is below the revised code:

-- REVISED CODE (NOW WORKS)
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

entity CLOCK_DIVIDER is
    port(
        reset   :   in std_logic;
        clk :   in std_logic;
        half_clk    :   out std_logic
        );
end CLOCK_DIVIDER;


architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;

begin

    process(clk, reset)
    begin
        if reset = '1' then
            tick <= '0';
        elsif clk = '1' and clk'EVENT then
            if tick = '0' then
                tick <= '1';
            elsif tick = '1' then
                tick <= '0';
            end if;
        end if;
    end process;

    process(tick)
    begin
        half_clk <= tick;
    end process

end CLOCK_DIVIDER;

The synthesized logic block of the revised code is a single asynchronous-reset DFF that takes half_clk as output and inverted half_clk as input, which means the value of half_clk changes on every rising edge of clk.

Thanks, Will Dean :)

==== ==== ==== ==== ====

Original question below:

==== ==== ==== ==== ====

I need a simple clock divider (just divide-by-two) and instead of usinga template, I thought I'd try to write one myself to keep in training.

Unfortunately, the synthesized logic block does not appear to work - I present the logic block and the code (which I really think ought to work), in that order.

logic block http://img808.imageshack.us/img808/3333/unledly.png

What I'm really wondering is what the devil is up with the "tick" DFF - it apparently takes its input from the mux-selector which is... Yeah.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

entity CLOCK_DIVIDER is
    port(
        reset   :   in std_logic;
        clk :   in std_logic;
        half_clk    :   out std_logic
        );
end CLOCK_DIVIDER;


architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;

begin
    process(clk, reset)
    begin
        if reset = '1' then
            half_clk <= '0';
            tick <= '0';
        elsif clk = '1' and clk'EVENT then
            if tick = '0' then
                half_clk <= '0';
                tick <= '1';
            elsif tick = '1' then
                half_clk <= '1';
                tick <= '0';
            end if;
        end if;
    end process;
end CLOCK_DIVIDER;

I'm sure the error in the code is obvious but I've been staring myself blind trying to find it.

Answer

Josh picture Josh · Jun 7, 2011

If halfclk is to be used as an enable and not a true clock, disregard this advice...

If this is for an FPGA target and "half_clk" is really being used as a clock (e.g. going to the clock pin on a DFF, and not the enable pin)... Don't do this.

Creating derived clocks using general FPGA logic/fabic will lead to problems with build tools, and can eventually lead to failed builds (won't meet timing), or builds that do not behave as expected because constraints not correctly passed through to all clock networks.

Instead use clock management blocks that are built into FPGA fabric especially for this purpose. In the world of Xilinx parts, these are called Digital Clock Managers (DCM) or Mixed Mode Clock Manager (MMCM). I am not sure what the equivalent Altera component is. Read up on the documentation to determine the best use for your application.