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

Comment utiliser une procédure dans un processus en VHDL

Il est possible de piloter des signaux externes à partir d'une procédure. Tant que le signal est dans le périmètre de la procédure, il est accessible en lecture ou en écriture, même s'il n'est pas listé dans la liste des paramètres.

Les procédures déclarées dans la région déclarative de l'architecture ne peuvent pas piloter de signaux externes. C'est simplement parce qu'il n'y a pas de signaux dans sa portée au moment de la compilation. Une procédure déclarée dans un processus, en revanche, aura accès à tous les signaux que le processus peut voir.

Cet article de blog fait partie de la série de didacticiels VHDL de base.

De telles procédures peuvent être utilisées pour désencombrer des algorithmes dans des processus où les mêmes opérations se produisent plusieurs fois. Nous pourrions utiliser une procédure normale où toutes les entrées et sorties sont affectées à des signaux locaux lorsque vous l'appelez, mais ce n'est pas le but. En omettant les signaux d'entrée et de sortie de l'appel de procédure, nous devons taper moins et, plus important encore, nous rendons le code plus lisible.

Imaginez un processus mettant en œuvre un protocole de communication complexe. Il serait beaucoup plus facile de comprendre le flux d'exécution de l'algorithme principal si certaines opérations étaient remplacées par des appels de procédure comme RequestToSend() ou SendAutorizationHeader() . Vous sauriez ce que faisaient ces lignes rien qu'en regardant les noms des procédures.

Exercice

Dans le tutoriel précédent, nous avons simplifié notre code de machine à états finis (FSM) en utilisant une fonction impure. Nous conduisions le Counter signal de la fonction impure, et nous avons utilisé la valeur de retour pour déterminer quand changer d'état. Mais que se passe-t-il si nous voulons déplacer l'affectation du State signal dans la fonction également et ignorer la valeur de retour ?

Il n'est pas possible d'appeler une fonction sans affecter la valeur de retour à quelque chose en VHDL. Si nous essayons de le faire, ModelSim produira l'erreur de compilation : Aucune entrée possible pour le sous-programme "CounterExpired".

Au lieu de cela, nous pouvons utiliser une procédure pour cela. Une procédure déclarée dans un processus peut accéder à n'importe quel signal dans le cadre de ce processus. Ceci est similaire à la fonction impure, mais comme il s'agit d'une procédure, il n'y a pas de valeur de retour.

Dans ce tutoriel vidéo nous allons simplifier le code FSM en utilisant une procédure déclarée dans un process :

Le code final pour la procédure en cours 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

    -- We are using a low clock frequency to speed up the simulation
    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

    -- The Device Under Test (DUT)
    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);


    -- Process for generating clock
    Clk <= not Clk after ClockPeriod / 2;

    -- Testbench sequence
    process is
    begin
        wait until rising_edge(Clk);
        wait until rising_edge(Clk);
    
        -- Take the DUT out of reset
        nRst <= '1';
    
        wait;
    end process;
    
end architecture;

Le code final pour le module des feux de circulation :

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; -- Negative reset
    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

    -- Enumerated type declaration and state signal declaration
    type t_State is (NorthNext, StartNorth, North, StopNorth,
                        WestNext, StartWest, West, StopWest);
    signal State : t_State;

    -- Counter for counting clock periods, 1 minute max
    signal Counter : integer range 0 to ClockFrequencyHz * 60;

begin

    process(Clk) is

        -- Procedure for changing state after a given time
        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
                -- Reset values
                State   <= NorthNext;
                Counter <= 0;
                NorthRed    <= '1';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '1';
                WestYellow  <= '0';
                WestGreen   <= '0';

            else
                -- Default values
                NorthRed    <= '0';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '0';
                WestYellow  <= '0';
                WestGreen   <= '0';

                Counter <= Counter + 1;

                case State is

                    -- Red in all directions
                    when NorthNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        ChangeState(StartNorth, Seconds => 5);

                    -- Red and yellow in north/south direction
                    when StartNorth =>
                        NorthRed    <= '1';
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(North, Seconds => 5);

                    -- Green in north/south direction
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        ChangeState(StopNorth, Minutes => 1);

                    -- Yellow in north/south direction
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(WestNext, Seconds => 5);

                    -- Red in all directions
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        ChangeState(StartWest, Seconds => 5);

                    -- Red and yellow in west/east direction
                    when StartWest =>
                        NorthRed   <= '1';
                        WestRed    <= '1';
                        WestYellow <= '1';
                        ChangeState(West, Seconds => 5);

                    -- Green in west/east direction
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        ChangeState(StopWest, Minutes => 1);

                    -- Yellow in west/east direction
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        ChangeState(NorthNext, Seconds => 5);

                end case;

            end if;
        end if;
    end process;

end architecture;

La forme d'onde après avoir entré le run 5 min commande dans la console ModelSim :

Analyse

Nous n'avons pas changé le comportement du module, et nous pouvons voir que la forme d'onde est inchangée.

Comparé au code du tutoriel où nous avons initialement créé le module feux de circulation, le code FSM est beaucoup plus lisible maintenant. Vous pouvez facilement suivre l'algorithme qu'il implémente en lisant le code. Avoir le temporisateur et la logique de changement d'état dans une seule procédure est avantageux car cela garantit qu'elle est implémentée de la même manière partout où elle est utilisée.

À emporter


VHDL

  1. Tutoriel - Introduction au VHDL
  2. Instruction de procédure - Exemple VHDL
  3. Comment utilisons-nous le molybdène?
  4. Comment créer une liste de chaînes en VHDL
  5. Comment utiliser une fonction impure en VHDL
  6. Comment utiliser une fonction en VHDL
  7. Comment utiliser une procédure en VHDL
  8. Comment créer une minuterie en VHDL
  9. Comment utiliser une meuleuse de coupe