为什么我的VHDL计数器没有按照需要输出脉冲?

时间:2013-08-07 02:38:56

标签: counter vhdl fpga

我正在创建一个可变频率脉冲序列来控制电机,并使用以下代码使用计数器生成脉冲,该计数器按一些输入增量值inc_i计数。然后,我将计数器dout_o[N-1]输出的MSB传送到FPGA上的输出引脚。这应该给我一个所需频率的50%占空比方波,但我只是看到一个信号从低电平开始,变高,然后再也没有关闭。我的代码有明显错误吗?

--****************************************************************************
-- Load required libraries
--****************************************************************************
library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

--****************************************************************************
-- Define the inputs, outputs, and parameters
--****************************************************************************
entity var_count is

    generic(N: integer :=32);               -- for generic counter size
    port(
            inc_i       : in    std_logic_vector(N-1 downto 0);
            load_i      : in    std_logic;
            clk_i       : in    std_logic;
            clear_i     : in    std_logic;
            clk_en_i    : in    std_logic;
            count_en_i  : in    std_logic;
            msb_o       : out   std_logic
        );

end var_count;

--****************************************************************************
-- Define the behavior of the counter
--****************************************************************************
architecture behavior of var_count is

    -- Define our count variable. No need to initialize in VHDL.
    signal count : unsigned(N-1 downto 0) := to_unsigned(0, N);
    signal incr  : unsigned(N-1 downto 0) := to_unsigned(0, N);

begin   
    -- Define our clock process
    clk_proc : process(clk_i, clear_i, load_i)
    begin
        -- Asynchronous clear
        if clear_i = '1' then
            count <= to_unsigned(0, N);
        end if;

        -- Asynchronous load
        if load_i = '1' then
            incr <= unsigned(inc_i);
        end if;

        -- Define processes synch'd with clock.
        if rising_edge(clk_i) and clk_en_i = '1' then
            if count_en_i = '1' then            -- increment the counter
                count <= count + incr;
            end if;
        end if;     
    end process clk_proc;

    -- Output the MSB for the sake of generating a nice easy square wave.
    msb_o <= count(count'left);

end behavior;

对于N位计数器,方波频率应由公式pulse_freq = clock_freq * inc_i / 2^N给出。

我也试图通过将计数器输出(msb_o(k))的MSB通过单位DQ触发器来生成单个时钟周期脉冲,以获得msb_o(k-1),然后执行:

pulse = ~msb_o(k) * msb_o(k-1)

其中~代表逻辑NOT*代表逻辑AND。这应该只在计数器翻转时给我一个时钟周期脉冲。当我使用示波器读取输出引脚时,这个和MSB本身(50%占空比方波)都没有出现。如果您在我的代码中发现任何错误,请通知我。

感谢您的帮助!

我过去常常将这些内容放在一起hereherehere

编辑1:我已根据用户提出的建议更新了问题中的代码。现在当我输出计数器的MSB时,它变高并且再也不会关闭。我需要在溢出时重置计数器(我在上面尝试过)。有关如何做到这一点的任何建议吗?

编辑2 我意识到由于我的增量值inc_i不一定是1,因此我可能无法达到翻转计算的2**N - 1值。因此,我将翻转条件更改为:

if count > (2**N - unsigned(inc_i) - 1) then
    count <= to_unsigned(0, N);

我现在似乎正在获得脉冲,但它们并不是50%的占空比(我认为这是有道理的)并且当我更改增量值inc_i时它们似乎没有按预期发生变化。知道为什么费率不变?

编辑3:我意识到我所关心的所有应用程序都是计数器的MSB,因为我将使用它来生成50%占空比的方波,或者翻滚时发出脉冲。鉴于此,我将实体声明中的dout_o替换为:

`msb_o : out std_logic`

我在最后用以下内容替换了并发赋值语句:

msb_o <= '1' when count > (2**(N-1) - 1) else '0';

我仍然得到非常奇怪的脉冲,它们的占空比不是50%,或者必须是正确的频率。任何进一步的建议将不胜感激。

编辑4 :通过进一步更改更新了我的代码。同时将this free book添加到参考列表中。

编辑5:将我的代码更新为(最终)工作版。

2 个答案:

答案 0 :(得分:3)

该流程不符合要识别的流程的一般规则 合成工具的触发器,因为条件的外层确实如此 不覆盖过程灵敏度列表中的信号。综合工具有 可能会给出一个或多个警告。

重写流程以遵守可合成的一般规则的一种方法 人字拖鞋是:

clk_proc : process (CLK)
begin
  if (CLK'event and CLK = '1') then
    if CLEAR = '1' then           -- clear the counter
      COUNT <= COUNT - COUNT;
    elsif CLK_EN = '1' then       -- increment the counter
      COUNT <= COUNT + INC;
    end if;
  end if;
end process clk_proc;

这将时钟边缘的检查放在外层,并假定为 CLEAR是同步的。

例如,有关寄存器的VHDL编码风格的更多信息 Xilinx XST User Guide

您对单个时钟周期脉冲的描述看起来不错,所以原因就在于此 它不起作用可能源于上述。

可以考虑对模块进行更大的重写,以便应用这些 有用的VHDL编码规则:

  • 输入和输出端口以_i和_o命名,因为这样便于阅读 模块实例化的代码
  • 没有默认值的信号,因为这可能不适用于所有FPGA 技术
  • 只有大写的常量标识符,因为这会使代码读取 更容易。
  • 不要使用std_logic_unsigned,因为这是Synopsys库而不是VHDL 标准
  • 使用rising_edge()进行边缘检测,以提高可读性
  • 使用(others => '0')清除,而不是COUNT - COUNT,因为这有效 在模拟中,即使COUNT都是X的

以下代码中的示例:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity var_count is
  port(
    inc_i    : in  std_logic_vector(31 downto 0);
    clk_i    : in  std_logic;
    clear_i  : in  std_logic;
    clk_en_i : in  std_logic;
    dout_o   : out std_logic_vector(31 downto 0));
end var_count;

architecture behavior of var_count is

  -- Define our count variable
  signal count : std_logic_vector(31 downto 0);

begin

  -- Define our clock process
  clk_proc : process (clk_i)
  begin
    if rising_edge(clk_i) then
      if clear_i = '1' then           -- clear the counter
        count <= (others => '0');
      elsif clk_en_i = '1' then       -- increment the counter
        count <= std_logic_vector(unsigned(count) + unsigned(inc_i));
      end if;
    end if;
  end process clk_proc;

  -- Concurrent assignment statement
  dout_o <= count;

end behavior;

如果您还没有使用模拟器,那么ModelSim可能很棒 改进你的工具箱。 Alera有ModelSim-Altera Starter Edition 这是免费的,可以用于小型设计。

答案 1 :(得分:2)

  • 初始化信号是没有意义的,如果该信号是寄存器,则将其复位为零(或任何其他所需值),并确保您的设计在复位状态下启动。 / LI>
  • 您的定时进程对CLEAR不敏感,IEEE.numeric_std.all会在此过程中读取。我假设你想要一个异步CLEAR。
  • std_logic_vectors无法使用COUNT-COUNT直接添加,建议在不同工具之间兼容。
  • 当你使用(others => '0')将它们全部驱动为零时,重置寄存器library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity VAR_COUNT is port( INC : in std_logic_vector(31 downto 0); CLK : in std_logic; CLEAR : in std_logic; CLK_EN : in std_logic; DOUT : out std_logic_vector(31 downto 0) ); end VAR_COUNT; architecture behavior of VAR_COUNT is -- Initialising a signal has no effect in hardware signal COUNT:std_logic_vector(31 downto 0) := x"00_00_00_00"; -- Define our clock process, your clocked process was not senstive to CLEAR begin clk_proc:process(CLK,CLEAR) begin if CLEAR = '1' then -- clear the counter COUNT <= (others=>'0'); --always use this to reset elsif CLK_EN = '1' then -- increment the counter if (CLK'EVENT AND CLK = '1') then COUNT <= std_logic_vector(unsigned(COUNT) + unsigned(INC)); end if; end if; end process clk_proc; -- concurrent assignment statement DOUT <= COUNT; end behavior; 没有意义。

请参阅下面的代码。

{{1}}