0

我正在创建一个变频脉冲序列来控制电机,并使用以下代码使用计数器生成脉冲,该计数器按某个输入增量值进行计数inc_i。然后,我将计数器输出的 MSBdout_o[N-1]传输到 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;

方波频率应由pulse_freq = clock_freq * inc_i / 2^NN 位计数器的公式给出。

我还试图通过将我的计数器输出 ( msb_o(k)) 的 MSB 传递给一位 DQ 触发器来获取msb_o(k-1)然后执行:

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

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

谢谢您的帮助!

可以在此处此处此处找到我用来将其放在一起的参考资料。

编辑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:通过进一步的更改更新了我的代码。还将这本免费书添加到参考列表中。

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

4

2 回答 2

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 用户指南

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

为了应用这些有用的 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 ,可用于小型设计。

于 2013-08-07T05:47:33.740 回答
2
  • 初始化信号没有意义,如果该信号将是一个寄存器,请将其重置为零(或任何其他所需值)并确保您的设计从重置状态开始。
  • 您的时钟进程对CLEAR在进程中读取的 不敏感。我假设你想要一个异步清除。
  • std_logic_vectors 不能直接使用 添加IEEE.numeric_std.all,建议使用 ,以便跨不同工具兼容。
  • 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;
于 2013-08-07T06:02:00.343 回答