Государственный аппарат; почему работает только последнее состояние?

У меня есть конечный автомат с 6 состояниями (3 основных состояния). Работает только последнее состояние, а первые 2 нет (из 3). Работает только последнее состояние. Я обнаружил проблему, когда я удаляю схему устранения дребезга, она работает, но мне нужна схема устранения дребезга. Я получил схему устранения дребезга из Интернета. Буду рад, если кто-то сможет помочь.

 type SM_STATES is (state_column_1, scan_col_1, state_column_2, scan_col_2,
                          state_column_3, scan_col_3);
 signal my_state     : SM_STATES                   := state_column_1;

Ниже приведена машина состояний:

scanner_sm : process (clk)
begin  -- process key_scanner
  if clk'event and clk = '1' then

  if state_inc = '1' then -- clock divider finished counting down 100000

    -- reset scan_complete
    scan_complete <= '0';

case my_state is

  when state_column_1 =>
    scanned_val  <= (others => '0');
    original_col   <= "110";
    my_state <= scan_col_1;

  when scan_col_1 =>
    case bcd_val is
      when "1110" => scanned_val <= "1100100";  -- 1 wrong
      when "1101" => scanned_val <= "1100010";  -- 2 wrong
      when others => scanned_val <= "0010000";
    end case;
    my_state <= state_column_2;

  when state_column_2 =>
    original_col   <= "011";
    my_state <= scan_col_2;

  when scan_col_2 =>
    case bcd_val is
      when "1110" => scanned_val <= "1011011";  -- 5 wrong
      when "1101" => scanned_val <= "1011111";  -- 6 wrong
      when others => scanned_val <= "0000000";
    end case;
    my_state <= state_column_3;

  when state_column_3 =>
    original_col   <= "101";
    my_state <= scan_col_3;

  when scan_col_3 => -- Reading S1 // The only working state
    case bcd_val is
      when "1110" => scanned_val <= "1100000";  -- 9/ 1
      when "1101" => scanned_val <= "0111110";  -- X/ 2
      when others => scanned_val <= "0000000";
    end case;
    my_state <= state_column_1; -- ************ Error might be here
    scan_complete <= '1'; -- ********** Error might be here

  when others => scanned_val <= "0000000";
end case;

      end if;
  end if;
end process scanner_sm;

debounce: process (CLK) is 
begin 
 if (CLK'event and CLK = '1') then  
  Q0 <= scannel_val; 

  Q1 <= Q0; 

  Q2 <= Q1; 

 end if; 

end process; 

Final_val <= Q0 and Q1 and (not Q2);

end Behavioral; 

person Anarkie    schedule 02.05.2014    source источник
comment
Почему вы публикуете это как на Stackoverlow, так и на Stackexchange? Недостаточно исходного кода для ответа, продемонстрируйте, как работает Только последнее состояние, но не первые 2 (из 3). Либо включите рабочий испытательный стенд, либо покажите изображение сигнала (надеюсь, в высоком разрешении).   -  person    schedule 03.05.2014
comment
Я добавил свой полный процесс. У меня есть только top_level и я написал его с примерами из интернета самым первым, что я написал. Я не могу написать полный исходный код. Я знаю, что тогда это не имеет смысла, но я не могу...   -  person Anarkie    schedule 03.05.2014


Ответы (2)


Ваш код пока неполный - вы напрямую назначаете в своем операторе case сигнал my_state, который оценивается конечным автоматом. Чтобы понять проблему с этим, нам нужно знать, как работает симулятор:

По сравнению с реальным оборудованием симулятор должен последовательно обрабатывать код с помощью последовательного процессора. Это работает, повторяя код снова и снова за бесконечно малые промежутки времени — так называемая Дельта-задержка - пока все зависимости не разрешится, т.е. больше ничего не изменится.

Обратите внимание, что фактическое время не прошло во время этих итераций. В правильно написанном дизайне симулятор теперь ждет, пока не произойдет следующее событие, обычно вызванное тиком часов, который снова перезапускает последовательные итерации.

Ваш пример в основном напоминает бесконечный цикл: изменение my_state всегда вызывает следующее изменение my_state, и, таким образом, симулятор никогда не устанавливает значение, пока не достигнет жестко запрограммированного предела итерации, который случайно в вашем случае это третье состояние.

Итак, как это исправить? Нам нужно ввести часы и сделать переход состояния в зависимости от фактического времени симуляции, обычно ожидая события часов. Лучшей практикой является разделение комбинаторной и последовательной частей на два разных процесса, как показано в этом минимальном примере вашего конечного автомата:

library ieee;
use ieee.std_logic_1164.all;

entity foo is

end entity foo;

architecture bar of foo is
  type SM_STATES is (state_column_1, scan_col_1, state_column_2, scan_col_2, state_column_3, scan_col_3);
  signal my_state, my_state_next : SM_STATES;
  signal bcd_val                 : std_logic_vector(3 downto 0) := "1110";
  signal clk                     : std_logic                    := '1';
  signal nRST                    : std_logic                    := '0';
  signal scanned_val             : std_logic_vector(6 downto 0);
  signal original_col            : std_logic_vector(2 downto 0);
  signal scan_complete           : std_logic;
begin  -- architecture bar

  comb : process (my_state, bcd_val) is
  begin  -- process baz
    case my_state is

      when state_column_1 =>
        scanned_val   <= (others => '0');
        original_col  <= "110";
        my_state_next <= scan_col_1;

      when scan_col_1 =>
        case bcd_val is
          when "1110" => scanned_val <= "1100100";  -- 1 wrong
          when "1101" => scanned_val <= "1100010";  -- 2 wrong
          when others => scanned_val <= "0010000";
        end case;
        my_state_next <= state_column_2;

      when state_column_2 =>
        original_col  <= "011";
        my_state_next <= scan_col_2;

      when scan_col_2 =>
        case bcd_val is
          when "1110" => scanned_val <= "1011011";  -- 5 wrong
          when "1101" => scanned_val <= "1011111";  -- 6 wrong
          when others => scanned_val <= "0000000";
        end case;
        my_state_next <= state_column_3;

      when state_column_3 =>
        original_col  <= "101";
        my_state_next <= scan_col_3;

      when scan_col_3 =>                -- Reading S1 // The only working state
        case bcd_val is
          when "1110" => scanned_val <= "1100000";  -- 9/ 1
          when "1101" => scanned_val <= "0111110";  -- X/ 2
          when others => scanned_val <= "0000000";
        end case;
        my_state_next <= state_column_1;  -- ************ Error might be here
        scan_complete <= '1';           -- ********** Error might be here

      when others => scanned_val <= "0000000";
    end case;
  end process comb;

  process (clk, nRST) is
  begin  -- process
    if nRST = '0' then                  -- asynchronous reset (active low)
      my_state <= state_column_1;
    elsif clk'event and clk = '1' then  -- rising clock edge
      my_state <= my_state_next;
    end if;
  end process;

  -- this clock and reset signal would usually be supplied from the outside
  clk  <= not clk after 10 ns;
  nRST <= '1'     after 101 ns;
end architecture bar;

Если мы запустим этот файл сейчас в симуляторе, мы увидим, как состояния меняются с каждым тактовым циклом:

Моделирование фиксированного кода.

person iterationbound    schedule 02.05.2014
comment
На самом деле у меня на схеме нет кнопки сброса... могу ли я обойтись без нее? Я добавил к вопросу свой полный исходный код процесса, у меня есть часы и делитель часов, поэтому я думаю, что мои часы должны обрабатывать переключатель состояния, который вы имели в виду, но мне не хватает my_next_state. Я сосредоточусь на реализации my_next_state. У меня нет ПЛИС на выходных, в понедельник постараюсь дать отзыв на ответ, большое спасибо за подсказки! - person Anarkie; 03.05.2014
comment
Также не могли бы вы поделиться своим test_bench? - person Anarkie; 03.05.2014
comment
После секундного размышления я думаю, что могу использовать одну из кнопок FPGA для сброса, но если есть способ решить эту проблему без сброса, я бы хотел пойти по этому пути. - person Anarkie; 03.05.2014

Вы можете думать об этом как о построении ответа iterationbound.

Я реализовал ваш полный процесс конечного автомата:

library ieee;
use ieee.std_logic_1164.all;

entity foo is

end entity foo;

architecture fum of foo is

    type SM_STATES is ( 
        state_column_1, scan_col_1, 
        state_column_2, scan_col_2, 
        state_column_3, scan_col_3
    );

    signal my_state:        SM_STATES;  -- defaults to SM_STATES'LEFT

    signal state_inc:       std_logic := '0';

    signal bcd_val:         std_logic_vector(3 downto 0) := "1110";
    signal clk:             std_logic := '0';

    signal scanned_val:     std_logic_vector(6 downto 0);
    signal original_col:    std_logic_vector(2 downto 0);
    signal scan_complete:   std_logic;

begin

scanner_sm: 
    process (clk)
    begin
        if clk'event and clk = '1' then

            if state_inc = '1' then

                scan_complete <= '0';

                case my_state is

                    when state_column_1 =>
                        scanned_val  <= (others => '0');
                        original_col   <= "110";
                        my_state <= scan_col_1;

                    when scan_col_1 =>
                        case bcd_val is
                            when "1110" => scanned_val <= "1100100";  -- 1 wrong
                            when "1101" => scanned_val <= "1100010";  -- 2 wrong
                            when others => scanned_val <= "0010000";
                        end case;
                        my_state <= state_column_2;

                    when state_column_2 =>
                        original_col   <= "011";
                        my_state <= scan_col_2;

                    when scan_col_2 =>
                        case bcd_val is
                            when "1110" => scanned_val <= "1011011";  -- 5 wrong
                            when "1101" => scanned_val <= "1011111";  -- 6 wrong
                            when others => scanned_val <= "0000000";
                        end case;
                        my_state <= state_column_3;

                    when state_column_3 =>
                        original_col   <= "101";
                        my_state <= scan_col_3;

                    when scan_col_3 => -- Reading S1 // The only working state
                        case bcd_val is
                            when "1110" => scanned_val <= "1100000";  -- 9/ 1
                            when "1101" => scanned_val <= "0111110";  -- X/ 2
                            when others => scanned_val <= "0000000";
                        end case;
                        my_state <= state_column_1; -- ************ Error might be here
                        scan_complete <= '1'; -- ********** Error might be here

                    when others => scanned_val <= "0000000";
                end case;

          end if;
      end if;
    end process scanner_sm;

CLOCK:
    process 
    begin
       wait for 10 ns;
       clk <= not clk;
       if Now > 200 ns then
           wait;
       end if;
    end process;

STIMULUS:
    process
    begin
        wait for 30 ns;
        state_inc <= '1';
        wait;
    end process;

end architecture;

Вы можете видеть, что следующего состояния нет. Угадайте, что это работает.

Я задержал state_inc на один такт, прежде чем утверждать, чтобы показать, почему вы должны выполнить сброс:

сигнал foo_tb

Вы можете видеть, что состояние scan_complete, scanned_val и original_col изначально неизвестно, пока они не будут записаны. Вы также можете сбросить my_state.

Вы можете видеть как из приведенного выше моделирования, так и из итерации, что ваш конечный автомат проходит через все шесть состояний. Если он где-то застрял, вы ожидаете, что state_inc не будет действительным (и также не очевидно, что делает его недействительным из вашего процесса).

Помимо отсутствия сбросов, с вашим конечным автоматом все в порядке. Похоже, проблема лежит в другом месте или связана с операцией на границе состояния, останавливающей появление state_inc.

Я бы предположил, что вам может понадобиться дополнительное состояние для сигнализации о завершении сканирования и начала следующего сканирования, иначе любое все еще действительное состояние state_inc вызовет следующий раунд переходов состояний. (Между scan_col3 и state_column_1, в соответствии с вашим комментарием «************ Здесь может быть ошибка»).

Добавление сбросов и дополнительного состояния (имя - завершено?), которое длится только один такт, может быть выполнено:

 if state_inc = '1' or my_state = complete then

где настоящее

  if state_inc = '1' then

is.

Это дало бы возможность отреагировать на scan_complete перед переходом к state_column_1. Вы можете проверить, должно ли завершение называться start_or_complete и быть первым состоянием.

Единственное, что я сделал с вашим процессом, это изменил отступ, чтобы было легче увидеть, где в операторах if все находится.

(И мы предупреждали вас, что хотели бы увидеть больше вашей модели)

person Community    schedule 03.05.2014
comment
Не могли бы вы поделиться своим файлом test_bench? - person Anarkie; 04.05.2014
comment
Скопируйте и вставьте приведенный выше исходный код VHDL в файл, проанализируйте, доработайте и смоделируйте. Есть одна общеизвестная характеристика испытательного стенда VHDL — отсутствие интерфейса порта в объявлении сущности. Испытательный стенд также будет содержать источник тактового сигнала, если это необходимо, а также стимул для проверки спецификации проекта VHDL. Что уникально в этом, так это то, что вы предоставили только процесс, поэтому нет создания экземпляра компонента, скорее, ваш процесс был включен напрямую. - person ; 04.05.2014
comment
Наконец-то я понял, почему переключение не работало из-за моей схемы подавления дребезга. Когда я удаляю схему устранения дребезга, она работает. Я скопировал этот дебаунс из интернета. Логика мне понятна, но почему она не работает, я не знаю. Я добавил к вопросу свою схему устранения дребезга. - person Anarkie; 06.05.2014