Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> VHDL

Cómo usar un procedimiento en un proceso en VHDL

Es posible conducir señales externas desde un procedimiento. Siempre que la señal esté dentro del alcance del procedimiento, se puede acceder a ella para lectura o escritura, incluso si no figura en la lista de parámetros.

Los procedimientos que se declaran en la región declarativa de la arquitectura no pueden controlar ninguna señal externa. Esto se debe simplemente a que no hay señales en su alcance en tiempo de compilación. Un procedimiento declarado dentro de un proceso, por otro lado, tendrá acceso a todas las señales que el proceso puede ver.

Esta publicación de blog es parte de la serie Tutoriales básicos de VHDL.

Dichos procedimientos se pueden utilizar para ordenar algoritmos en procesos en los que las mismas operaciones ocurren varias veces. Podríamos usar un procedimiento normal en el que todas las entradas y salidas se asignen a señales locales cuando lo llame, pero ese no es el punto. Al omitir las señales de entrada y salida de la llamada al procedimiento, debemos escribir menos y, lo que es más importante, hacemos que el código sea más legible.

Imagine un proceso que implemente un protocolo de comunicación complejo. Sería mucho más fácil entender el flujo de ejecución del algoritmo principal si algunas operaciones fueran reemplazadas por llamadas a procedimientos como RequestToSend() o SendAutorizationHeader() . Sabría lo que hicieron esas líneas con solo mirar los nombres de los procedimientos.

Ejercicio

En el tutorial anterior, simplificamos nuestro código de máquina de estado finito (FSM) mediante el uso de una función impura. Conducíamos el Counter señal de la función impura, y usamos el valor de retorno para determinar cuándo cambiar de estado. Pero, ¿y si queremos mover la asignación del State señal en la función también e ignorar el valor devuelto?

No es posible llamar a una función sin asignar el valor devuelto a algo en VHDL. Si intentamos hacerlo, ModelSim producirá el error de compilación: No hay entradas factibles para el subprograma "CounterExpired".

En cambio, podemos usar un procedimiento para esto. Un procedimiento declarado dentro de un proceso puede acceder a cualquier señal dentro del alcance de ese proceso. Esto es similar a la función impura, pero dado que es un procedimiento, no hay valor de retorno.

En este video tutorial simplificaremos el código FSM usando un procedimiento declarado en un proceso:

El código final para el Procedimiento en Proceso 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;

El código final para el módulo de Semáforos :

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 forma de onda después de que ingresamos el run 5 min comando en la consola de ModelSim:

Análisis

No hemos cambiado el comportamiento del módulo y podemos ver que la forma de onda no ha cambiado.

En comparación con el código del tutorial en el que inicialmente creamos el módulo de semáforos, el código FSM ahora es mucho más legible. Puede seguir fácilmente el algoritmo que implementa leyendo el código. Tener el temporizador y la lógica de cambio de estado en un solo procedimiento es beneficioso porque garantiza que se implemente por igual en todos los lugares donde se use.

Para llevar


VHDL

  1. Tutorial - Introducción a VHDL
  2. Declaración de procedimiento:ejemplo de VHDL
  3. ¿Cómo utilizamos el molibdeno?
  4. Cómo crear una lista de cadenas en VHDL
  5. Cómo usar una función impura en VHDL
  6. Cómo usar una función en VHDL
  7. Cómo usar un procedimiento en VHDL
  8. Cómo crear un temporizador en VHDL
  9. Cómo crear un proceso sincronizado en VHDL
  10. Cómo usar la creación de instancias de mapas de puertos en VHDL
  11. Cómo usar una amoladora cortadora