Entrada única para transiciones de estado consecutivas en un FSM: prevención de fallas

Considere el siguiente diagrama de estado donde las entradas son cy v. El sistema también está recibiendo un reloj de alta frecuencia clk, alrededor de 50 MHz.

Diagrama de estado

Como se muestra en el diagrama, la primera entrada se usa para avanzar los estados hacia la derecha y la segunda entrada es para avanzar los estados hacia la izquierda. En la implementación hardware (Altera DE1) estas entradas son botones.

El problema es que, dado que la frecuencia del reloj es muy alta (en relación con la duración de la presión del botón), cuando cse presiona el botón, cae al último estado S3. Luego, si vse presiona el botón, vuelve a subir por el estado inicial S0. Los estados intermedios S1y S2sólo se visitan muy brevemente. La siguiente figura ilustra la situación.

Caer a través

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

Primer código. Funciona pero el estado se cae.

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 a 2 Hz. Funciona como se pretendía 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 traté de 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 el resultado resultante no está definido.

Mi pregunta.

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

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

Como señaló Jonathan, necesita una detección de bordes. Esto se hace mediante un D-FF y una puerta and sig_re <= not sig_d and sig;(re = flanco ascendente). Puede incluirlo en el FSM solicitando esa condición completa o puede calcularlo fuera de su proceso de FSM, lo que brinda una solución más limpia. Ahora puede usar c_rey v_recomo una entrada directa de FSM sin preocuparse por fallas. Si agrega un circuito de sincronización de pines y antirrebote a su diseño, puede decidir emitir solo señales de botón detectadas en el borde que se pueden usar directamente en sus FSM.

Respuestas (2)

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

Una segunda solución, que soluciona ese problema, es agregar 2 entradas, c_dy v_d, que sería una versión retrasada (en 1 ciclo de reloj) de la entrada correspondiente. La transición de estado ocurriría en c = '1' and c_d = '0' 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;

Agregaré, dado que parece un principiante en FPGA, que debe considerar la metaestabilidad y el rebote de botones. La metaestabilidad es un riesgo cada vez que usa una señal asíncrona (como la entrada de un botón) en un diseño síncrono. Se elimina poniendo 2 flip-flop consecutivos en la entrada. Altera tiene más documentación al respecto .

El otro problema es el rebote. Al igual que con cualquier interruptor mecánico, el contacto que se hace cuando presiona el botón no es de encendido y apagado, sino más bien una larga serie de transiciones de encendido-apagado-encendido-apagado a medida que el interruptor mecánico alcanza su posición final. En un circuito digital, dará como resultado la lectura de varias presiones y liberaciones para la misma carrera. Se soluciona con un circuito antirrebote, que generalmente se basa en esperar algunos milisegundos cuando el interruptor cambia antes de volver a leerlo.

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

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

kevin