开发者

Creating a frequency divider in VHDL

开发者 https://www.devze.com 2023-03-11 03:04 出处:网络
MAJOR EDIT: Problem was solved after reading Will Dean\'s comment. The original question is below the revised code:

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 :)

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

Origin开发者_StackOverflow社区al 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.


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.


Based on your revised code, I offer this modification to the architecture:

-- REVISED CODE (NOW WORKS) and simplified and synthesisable
architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
    signal tick : std_logic;
begin
    process(clk, reset)
    begin
        if reset = '1' then
            tick <= '0';
        elsif rising_edge(clk) then -- use of rising_edge() is the correct idiom these days
            tick <= not tick;
        end if;
    end process;

    half_clk <= tick;
end CLOCK_DIVIDER;

I've removed this process and replaced with a concurrent assignment:

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

as what this is asking for is a flipflop clocked on both edges of tick.

This will appear to achieve what you want in terms of the waveforms wiggling the way you want them to, but will not synthesise. It also adds an extra delta delay to the output which may or may not cause problems if you use it as a clock "down the road". As others have commented, this is not a good plan anyway in most architectures (but for some it is "the right way").


Are you sure you're resetting at startup? The way you've got your conditional for tick defined, nothing will happen if tick isn't zero or one (ie: it could be U, Z, X, etc).

I generally suggest covering all cases with your conditional expressions, ie:

        if tick = '0' then
            half_clk <= '0';
            tick <= '1';
        else 
            half_clk <= '1';
            tick <= '0';
        end if;

or

        if tick = '0' then
            half_clk <= '0';
            tick <= '1';
        elsif tick = '1' then
            half_clk <= '1';
            tick <= '0';
        else
            -- Throw error or something here
        end if;


A simple counter does the trick (proper way is DCM of course):

signal cnt : std_logic_vector(3 downto 0);

...

clk_div_2  <= cnt(0);
clk_div_4  <= cnt(1);
clk_div_8  <= cnt(2);
clk_div_16 <= cnt(3);

...

process(clk)
 if clk'event and clk = '1' then
  cnt <= cnt + 1;
 end if;
end process;
0

精彩评论

暂无评论...
验证码 换一张
取 消