VHDL状态机有几个延迟 - 最好的方法?

时间:2015-06-30 12:19:25

标签: vhdl

这是一个通用的问题,因为我能够理解有限状态机的基础知识。假设我有四个状态s0-s3,其中 FSM将自动从' s0开始。通电后。经过一段确定的延迟后,FSM应进入“s1' - 其他州也一样。 不同状态之间的延迟是不一样的。

例如:

加电 - > ' S0' - > 100毫秒 - > ' S1' - > 50我们 - > ' S2' - > 360 us - > ' S3' - > ' S3'

在C语言的过程语言中,我只是调用一个延迟例程,其中一个参数是所需的延迟并且用它来完成。

如何优雅地实现这种FSM?

最好的, 克里斯

4 个答案:

答案 0 :(得分:3)

我的模式:一个延迟计数器,每个状态转换可以在需要时编程,即在每个新延迟开始时编程。

尽管有些工具(特别是Synplicity)在准确的时间计算方面存在问题,除非你的时钟周期是整数个纳秒,否则这一切都是可以合成的。有关此错误的更多信息,请参阅this Q&A。如果你遇到这种情况,那么神奇的数字(32000而不是Synplicity在该问题中计算的32258)可能是最简单的解决方法。

将它作为(简单)练习留在实体/架构中。

-- first, some declarations for readability instead of magic numbers
constant clock_period : time := 10 ns; 
--WARNING : Synplicity has a bug : by default it rounds to nanoseconds!
constant longest_delay : time := 100 ms;
subtype delay_type is natural range 0 to longest_delay / clock_period;

constant reset_delay : delay_type := 100 ms / clock_period - 1;
constant s1_delay  : delay_type := 50 us / clock_period - 1;
constant s2_delay  : delay_type := 360 us / clock_period - 1;
-- NB take care to avoid off-by-1 error!

type state_type is (s0, s1, s2, s3);

-- now the state machine declarations:

signal state : state_type;
signal delay : delay_type;

-- now the state machine itself:

process(clock, reset) is

begin
   if reset = '1' then
      state <= s0;
      delay <= reset_delay;
   elsif rising_edge(clock) then
      -- default actions such as default outputs first
      -- operate the delay counter
      if delay > 0 then 
         delay <= delay - 1;
      end if;
      -- state machine proper
      case state is
      when s0 =>
         -- do nothing while delay counts down
         if delay = 0 then
            --start 50us delay when entering S1
            delay <= s1_delay;
            state <= s1;
         end if;
      when s1 =>
         if delay = 0 then
            delay <= s2_delay;
            state <= s2;
         end if;
      when s2 =>
         if delay = 0 then
            state <= s3;
         end if;
      when others =>
         null;
      end case;       
   end if;
end process;

答案 1 :(得分:1)

您可以使用时钟分频器和计数器的组合。了解设备的时钟速度。你提到的所有延迟都是10us的因素,所以我将使用时钟分频器来达到这个速度。我们假设您设备的原始时钟速度为50MHz。你需要找出你需要计算到10us的循环次数。以下计算是这样的:

# of cycles = 10ms * 50MHz = 5000 cycles

所以你需要一个计数到5000的计数器。一个粗略的例子如下:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity new_clk is
    Port (
        clk_in : in  STD_LOGIC; -- your 50MHZ device clock
        reset  : in  STD_LOGIC;
        clk_out: out STD_LOGIC -- your new clock with a 10us period
    );
end clk200Hz;

architecture Behavioral of new_clk is
    signal temporal: STD_LOGIC;
    signal counter : integer range 0 to 4999 := 0;
begin
    clk_div: process (reset, clk_in) begin
        if (reset = '1') then
            temporal <= '0';
            counter <= 0;
        elsif rising_edge(clk_in) then
            if (counter = 4999) then
                temporal <= NOT(temporal);
                counter <= 0;
            else
                counter <= counter + 1;
            end if;
        end if;
    end process;

    clk_out <= temporal;
end Behavioral;

注意计数器如何从​​0到4999.信号clk_out现在的周期为10us。您现在可以使用它来生成延迟。

例如,对于360us延迟,计算clk_out信号的36个周期。代码将与上面的代码大致相似,但这次你计算的是clk_out而你的计数器只是从0到35。

(我可以稍后再添加,但这应该让你开始。)

答案 2 :(得分:0)

检查“硬件中的有限状态机:理论与设计(使用VHDL和SystemVerilog)”的第8-9章麻省理工学院出版社,2013年,详细讨论了任何案例和许多完整的例子。

答案 3 :(得分:-1)

布莱恩德拉蒙德的精彩答案:感谢布赖恩! :)

主要区别是将固定上限移除到延迟长度:它现在仅受“延迟”SIGNAL类型的长度限制 - 通常可以根据需要进行。

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY Test123 IS

    PORT (
        clk_in1 : IN std_logic := '0';
        rst1, en1 : IN std_logic;
        );

END ENTITY Test123;

ARCHITECTURE Test123_Arch OF Test123 IS

    -- first, some declarations for readability instead of magic numbers
    CONSTANT clock_period : TIME := 20 ns; -- 50 MHz
    --WARNING : Synplicity has a bug : by default it rounds to nanoseconds!
    CONSTANT reset_delay : TIME := 100 ms - clock_period;
    CONSTANT s1_delay : TIME := 50 us - clock_period;
    CONSTANT s2_delay : TIME := 360 us - clock_period;
    -- NB take care to avoid off-by-1 error!

    -- now the state machine declarations:
    TYPE state_type IS (s0, s1, s2, s3);
    SIGNAL state : state_type;
    --
    --signal delay : unsigned(47 downto 0) := (others => '0'); -- a 48-Bit 'unsigned' Type, Along a 50-MHz Clock, Evaluates To an Upper-Limit of ~90,071,992.5474 Seconds.
    SIGNAL delay : NATURAL := 0; -- a 'natural' Type, Along a 50-MHz Clock, Evaluates To an Upper-Limit of ~85.8993459 Seconds.
    --

    FUNCTION time_to_cycles(time_value : TIME; clk_period : TIME) RETURN NATURAL IS
    BEGIN
        -- RETURN TO_UNSIGNED((time_value / clk_period), 48); -- Return a 48-Bit 'unsigned'
        RETURN (time_value / clk_period); -- Return a 32-Bit 'natural'
    END time_to_cycles;
    --

    BEGIN
        -- now the state machine itself:

        sm0 : PROCESS (clk_in1, rst1)
        BEGIN
            IF (rst1 = '1') THEN
                state <= s0;
                delay <= time_to_cycles(reset_delay, clock_period);

            ELSIF rising_edge(clk_in1) THEN
                -- default actions such as default outputs first
                -- operate the delay counter
                IF (delay > 0) THEN
                    delay <= delay - 1;
                END IF;
                -- state machine proper
                CASE state IS
                    WHEN s0 =>
                        -- do nothing while delay counts down
                        IF (delay = 0) THEN
                            --start 50us delay when entering S1
                            delay <= time_to_cycles(s1_delay, clock_period);
                            state <= s1;
                        END IF;
                    WHEN s1 =>
                        IF (delay = 0) THEN
                            delay <= time_to_cycles(s2_delay, clock_period);
                            state <= s2;
                        END IF;
                    WHEN s2 =>
                        IF (delay = 0) THEN
                            state <= s3;
                        END IF;
                    WHEN OTHERS =>
                        NULL;
                END CASE;
            END IF;
        END PROCESS;

END ARCHITECTURE Test123_Arch;