【问题标题】:Creating a frequency divider in VHDL在 VHDL 中创建分频器
【发布时间】:2011-06-07 07:12:31
【问题描述】:

主要编辑:

在阅读了 Will Dean 的评论后,问题得到了解决。原来的问题在修改后的代码下面:

-- 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;

修改后的代码的综合逻辑块是一个异步复位DFF,它以half_clk为输出,反相half_clk为输入,这意味着half_clk的值在clk的每个上升沿发生变化。

谢谢,威尔迪恩 :)

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

原始问题如下:

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

我需要一个简单的时钟分频器(只需除以二),我想我会尝试自己编写一个以继续训练,而不是使用模板。

不幸的是,合成的逻辑块似乎不起作用 - 我按顺序呈现逻辑块和代码(我真的认为应该起作用)。

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

我真正想知道的是,“tick”DFF 到底是怎么回事——它显然是从 mux-selector 获取输入的……是的。

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;

我确信代码中的错误很明显,但我一直在盯着自己瞎找。

【问题讨论】:

  • 我是 Verilog 人而不是 VHDL,但我不明白为什么需要两个寄存器来除以二。除了 'tick' 的(延迟)反转之外,'half_clock' 是什么?
  • 我不需要两个寄存器,也不知道为什么会推断出两个寄存器。 half_clck 是逻辑块的输出,而 tick 是内部信号 - 如果我让 tick 输出,它无法读取它,如果我让 half_clk 成为内部信号,我无法输出它。但是:它现在可以工作了——记住你所说的,我从 if 语句中删除了 half_clk 并创建了一个单独的进程,它始终将 tick 的值分配给 half_clk ,现在它可以工作了。

标签: vhdl intel-fpga


【解决方案1】:

如果将 halfclk 用作启用而不是真正的时钟,请忽略此建议...

如果这是用于 FPGA 目标并且“half_clk”确实被用作时钟(例如,进入 DFF 上的时钟引脚,而不是启用引脚)...... 不要这样做。

使用通用 FPGA 逻辑/fabic 创建派生时钟会导致构建工具出现问题,并最终导致构建失败(不符合时序要求),或者由于约束未正确传递到所有时钟网络。

请改为使用内置于 FPGA 架构中的时钟管理模块,特别是为此目的。在 Xilinx 器件领域,这些器件称为数字时钟管理器 (DCM) 或混合模式时钟管理器 (MMCM)。我不确定等效的 Altera 组件是什么。阅读文档以确定最适合您的应用程序的用途。

【讨论】:

  • 您会惊讶地发现,这实际上是用户指南为我正在使用的 CPLD 推荐的方式。 clk 是一个外部晶振,half_clk 将被路由到一个内置的全局时钟网络。
  • 好的,太好了。想向您和其他人指出这一点,我看到这样的事情经常发生(当不建议这样做时),这会在路上造成很多痛苦。
【解决方案2】:

根据您修改后的代码,我对架构进行了修改:

-- 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;

我已经删除了这个进程并替换为并发分配:

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

因为这要求的是在tick 的两个边缘上计时的触发器。

这似乎可以实现您想要的波形,波形按照您想要的方式摆动,但不会合成。它还为输出增加了额外的增量延迟,如果您将其用作“未来”的时钟,这可能会或可能不会导致问题。正如其他人所评论的那样,无论如何这在大多数架构中都不是一个好计划(但对于某些人来说这是“正确的方式”)。

【讨论】:

    【解决方案3】:

    您确定要在启动时重置吗?你已经定义了tick条件的方式,如果tick不是零或一(即:它可能是U、Z、X等),什么都不会发生。

    我一般建议用你的条件表达式覆盖所有情况,即:

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

            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;
    

    【讨论】:

    • 使用 elsif 是如此根深蒂固,以至于我什至没有考虑过这一点,但这是一个合理的建议 - 我绝对希望它能够初始化,即使 tick 开始时有一个奇怪的值。
    【解决方案4】:

    一个简单的计数器就可以解决问题(正确的方法当然是 DCM):

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-18
      • 1970-01-01
      • 2020-09-04
      相关资源
      最近更新 更多