Entrada única para transiciones de estado consecutivas en un FSM: evitando caídas

2

Considere el siguiente diagrama de estado donde las entradas son c y v . El sistema también recibe un reloj de alta frecuencia clk , aproximadamente 50 MHz.

Comosemuestraeneldiagrama,laprimeraentradaseusaparaavanzaraladerechaenlosestadosylasegundaentradaesparaavanzaralaizquierdaenlosestados.Enlaimplementacióndehardware(AlteraDE1)estasentradassonbotones.

Elproblemaesque,comolafrecuenciadelrelojesmuyalta(enrelaciónconladuracióndelapulsacióndelbotón),cuandosepresionaelbotónc,caehastaelúltimoestadoS3.Luego,sisepresionaelbotónv,nuevamentepasaporelestadoinicialS0.LosestadosintermediosS1yS2solosevisitanbrevemente.Lasiguientefigurailustralasituación.

Aquí está el código de mi VHDL para implementar la máquina de estado.

Primer código. Funciona pero el estado fracasa.

Library IEEE;
Use IEEE.std_logic_1164.all;

Entity state_machine is
    port (
        clk, c, v : in  std_logic; 
        outp      : out std_logic_vector(1 downto 0)
    );
end state_machine;

Architecture beh of state_machine is
   type state_type is (S0, S1, S2, S3); -- there are four states
    signal current_state : state_type := S0 ;
Begin
   Process(clk)
    Begin
       if (clk'event and clk = '1' ) then
            case current_state is
                when S0 =>
                    if c = '1' then
                        current_state <= S1;
                    end if;
            when S1 =>
                   if c = '1' then
                       current_state <= S2;
                    elsif v = '1' then
                       current_state <= S0;
                   end if;
                when S2 =>
                   if c = '1' then
                       current_state <= S3;
                    elsif v = '1' then
                       current_state <= S1;
                   end if;
                when S3 =>
               if v = '1' then
                       current_state <= S2;
                   end if;
            End case;
        End if;
    End Process;

    With current_state select
       outp <= "00" when S0,
               "01" when S1,
               "10" when S2,
               "11" when S3;
End beh;

En un experimento, reduje el reloj hacia abajo a 2 Hz. Funciona como se pretende en el diagrama de estado anterior, pero no es muy confiable. A veces avanza un estado, a veces "pierde" el reloj, a veces avanza dos estados. Seguramente esto no es aceptable.

También intenté separar el reloj y la lógica de la máquina de estado, en el siguiente código.

Segundo código. Se compila, pero la salida no está definida.

Library IEEE;
Use IEEE.std_logic_1164.all;

Entity state_machine_2 is
    port (
        clk, c, v : in  std_logic; 
        outp      : out std_logic_vector(1 downto 0)
    );
end state_machine_2;

Architecture beh of state_machine_2 is
   type state_type is (S0, S1, S2, S3); -- there are four states
    signal current_state : state_type := S0 ;
    signal next_state    : state_type := S0 ;
Begin

   Process(clk)
    Begin
       if (clk'event and clk = '1' ) then
           current_state <= next_state ;
        end if;
    End Process;

   Process(c, v)
    Begin
        Case current_state is
            when S0 =>
                if c = '1' then
                    next_state <= S1;
                end if;
            when S1 =>
                if c = '1' then
                    next_state <= S2;
                elsif v = '1' then
                    next_state <= S0;
                end if;
            when S2 =>
                if c = '1' then
                    next_state <= S3;
                elsif v = '1' then
                    next_state <= S1;
                end if;
            when S3 =>
                if v = '1' then
                    next_state <= S2;
                end if;
        End case;
   End Process;

    With current_state select
       outp <= "00" when S0,
                "01" when S1,
                "10" when S2,
                "11" when S3;
End beh;

El código anterior se compila, pero la salida resultante no está definida.

Mi pregunta.

¿Cómo implementar el diagrama de estado anterior en VHDL y funcionaría como uno esperaría? Es decir, uno presiona c una vez y simplemente avanzaría un estado solamente.

¿Quizás no debería estar usando el reloj en el FSM por completo? ¿O hay una mejor estrategia?

    
pregunta fajar

2 respuestas

2

Veo dos opciones. El primero, como sugiere Kevin White, es agregar estados intermedios que esperan c = 0 y v = 0 entre todos los estados. Sin embargo, no se comportaría como se espera si presiona c, luego presiona v, suelta c, presiona c, suelta vy repite el ciclo. En ese caso, permanecería en el mismo estado en lugar de moverse hacia adelante y hacia atrás (a menos que agregue un estado de transición aún mayor).

Una segunda solución, que soluciona ese problema, es agregar 2 entradas, c_d y v_d , que serían versiones demoradas (en 1 ciclos de reloj) de la entrada correspondiente. La transición de estado ocurriría en c = '1' and c_d = '0' en su lugar. Es fácil hacerlo:

architecture beh of state_machine_2 is
    signal c_d, v_d : std_logic;
    -- other declarations
begin
    DELAY_INPUTS: process(clk)
    begin
        if rising_edge(clk) then
            c_d <= c;
            v_d <= v;
        end if;
     end process DELAY_INPUTS;

Añadiré, ya que pareces un principiante en FPGA, que debes considerar la metastabilidad y el desmonte de botones. La metastabilidad es un riesgo siempre que use una señal asíncrona (como la entrada de un botón) en un diseño síncrono. Se elimina colocando 2 flip-flop consecutivos en la entrada. Altera tiene más documentación en ella .

El otro problema es el debouncing. Al igual que con cualquier interruptor mecánico, el contacto que se hace cuando se presiona el botón no está encendido o apagado, sino una larga serie de transiciones encendido-apagado-encendido-apagado-encendido cuando el interruptor mecánico llega a su posición final. En un circuito digital, resultará en la lectura de varias pulsaciones de liberación para el mismo golpe. Se soluciona con un circuito de rebote, que generalmente se basa en esperar algunos milisegundos cuando el conmutador realiza la transición antes de volver a leerlo.

    
respondido por el Jonathan Drolet
0

Necesita estados adicionales después de S0, S1 ... donde espera que c se reduzca antes de continuar.

Puedes usar los mismos estados para esperar a que V disminuya. Deberá definir qué sucede cuando C y V están activos simultáneamente.

kevin

    
respondido por el Kevin White

Lea otras preguntas en las etiquetas