Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> VHDL

Exploiter les procédures in-process pour un design FSM VHDL plus propre

En VHDL, une procédure peut piloter des signaux externes tant que le signal reste dans sa portée. Bien qu'une procédure déclarée dans une architecture n'ait pas accès aux signaux externes - car ces signaux ne sont pas visibles au moment de la compilation - une procédure définie à l'intérieur d'un processus peut librement lire et écrire n'importe quel signal que le processus peut voir.

L'utilisation de procédures in-process est un moyen efficace de désencombrer la logique répétitive dans les machines d'état ou les protocoles complexes. En encapsulant des actions communes - comme une transition d'état chronométrée - dans une procédure, vous réduisez le code boilerplate, améliorez la lisibilité, et rendez l'intention de chaque étape limpide.

Par exemple, dans un contrôleur de feu tricolore, renommer les opérations en ChangeState(ToState, Minutes, Seconds) dit au lecteur exactement ce que fait le code sans plonger dans les affectations de variables sous-jacentes.

Exercice pratique

Dans un tutoriel précédent, nous avons utilisé une fonction impure pour piloter un signal Counter et déterminer les changements d'état. Cependant, nous n'avons pas pu déplacer l'affectation State dans cette fonction car VHDL exige une valeur de retour pour chaque appel de fonction. Au lieu de cela, une procédure - dépourvue de valeur de retour - convient parfaitement à ce cas d'usage.

Ci-dessous se trouve le testbench et le module complets qui démontrent une FSM de feu tricolore pilotée par une procédure in-process.

Testbench

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

entity T23_ProcedureInProcessTb is
end entity;

architecture sim of T23_ProcedureInProcessTb is
  constant ClockFrequencyHz : integer := 100; -- 100 Hz
  constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;
  signal Clk : std_logic := '1';
  signal nRst : std_logic := '0';
  signal NorthRed : std_logic;
  signal NorthYellow : std_logic;
  signal NorthGreen : std_logic;
  signal WestRed : std_logic;
  signal WestYellow : std_logic;
  signal WestGreen : std_logic;
begin
  i_TrafficLights : entity work.T23_TrafficLights(rtl)
    generic map(ClockFrequencyHz => ClockFrequencyHz)
    port map (
      Clk => Clk,
      nRst => nRst,
      NorthRed => NorthRed,
      NorthYellow => NorthYellow,
      NorthGreen => NorthGreen,
      WestRed => WestRed,
      WestYellow => WestYellow,
      WestGreen => WestGreen
    );
    
  Clk <= not Clk after ClockPeriod / 2;
  
  process is
  begin
    wait until rising_edge(Clk);
    wait until rising_edge(Clk);
    nRst <= '1';
    wait;
  end process;
end architecture;

Module Feu Tricolore

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

entity T23_TrafficLights is
  generic(ClockFrequencyHz : integer);
  port(
    Clk : in std_logic;
    nRst : in std_logic;
    NorthRed : out std_logic;
    NorthYellow : out std_logic;
    NorthGreen : out std_logic;
    WestRed : out std_logic;
    WestYellow : out std_logic;
    WestGreen : out std_logic
  );
end entity;

architecture rtl of T23_TrafficLights is
  type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
  signal State : t_State;
  signal Counter : integer range 0 to ClockFrequencyHz * 60;
  
begin
  process(Clk) is
    procedure ChangeState(
      ToState : t_State;
      Minutes : integer := 0;
      Seconds : integer := 0
    ) is
      variable TotalSeconds : integer;
      variable ClockCycles : integer;
    begin
      TotalSeconds := Seconds + Minutes * 60;
      ClockCycles := TotalSeconds * ClockFrequencyHz - 1;
      if Counter = ClockCycles then
        Counter <= 0;
        State <= ToState;
      end if;
    end procedure;
    
  begin
    if rising_edge(Clk) then
      if nRst = '0' then
        State <= NorthNext;
        Counter <= 0;
        NorthRed <= '1';
        NorthYellow <= '0';
        NorthGreen <= '0';
        WestRed <= '1';
        WestYellow <= '0';
        WestGreen <= '0';
      else
        NorthRed <= '0';
        NorthYellow <= '0';
        NorthGreen <= '0';
        WestRed <= '0';
        WestYellow <= '0';
        WestGreen <= '0';
        Counter <= Counter + 1;
        
        case State is
          when NorthNext =>
            NorthRed <= '1';
            WestRed <= '1';
            ChangeState(StartNorth, Seconds => 5);
          when StartNorth =>
            NorthRed <= '1';
            NorthYellow <= '1';
            WestRed <= '1';
            ChangeState(North, Seconds => 5);
          when North =>
            NorthGreen <= '1';
            WestRed <= '1';
            ChangeState(StopNorth, Minutes => 1);
          when StopNorth =>
            NorthYellow <= '1';
            WestRed <= '1';
            ChangeState(WestNext, Seconds => 5);
          when WestNext =>
            NorthRed <= '1';
            WestRed <= '1';
            ChangeState(StartWest, Seconds => 5);
          when StartWest =>
            NorthRed <= '1';
            WestRed <= '1';
            WestYellow <= '1';
            ChangeState(West, Seconds => 5);
          when West =>
            NorthRed <= '1';
            WestGreen <= '1';
            ChangeState(StopWest, Minutes => 1);
          when StopWest =>
            NorthRed <= '1';
            WestYellow <= '1';
            ChangeState(NorthNext, Seconds => 5);
        end case;
      end if;
    end if;
  end process;
end architecture;

Forme d'onde

La simulation reste identique à la FSM originale - seul le code est devenu plus maintenable et plus facile à comprendre.

Analyse

En déplaçant la logique de chronométrage et de changement d'état dans une seule procédure, nous avons préservé le comportement du module tout en améliorant considérablement la lisibilité. La procédure assure une implémentation cohérente partout où elle est appelée.

Points clés à retenir

VHDL

  1. Introduction à VHDL : construire votre première porte ET
  2. Exemple de procédure VHDL : incrémenter un std_logic_vector
  3. Comment le molybdène façonne l'industrie moderne : usages, avantages et dynamiques d'approvisionnement
  4. Créer des listes de chaînes en VHDL : Bonnes pratiques et exemple
  5. Utilisation des fonctions impures en VHDL : Améliorer la lisibilité et la maintenabilité des FSM
  6. Maîtriser les fonctions VHDL : Guide pratique pour un design efficace
  7. Utilisation des procédures en VHDL : Simplifiez votre design avec du code réutilisable
  8. Construire un minuteur fiable en VHDL : Compter les cycles d'horloge jusqu'aux heures
  9. Maîtriser les techniques de la rectifieuse d'outils : guide pratique