Se necesita ayuda para explicar las señales que vienen con una frecuencia más alta que el reloj y cómo manejarlas

Estoy poniendo mis manos en la programación de Verilog y FPGA. Así que escribí un módulo simple que maneja dos entradas: señal de botón y reloj. Inicialmente, enciende dos LED y cuando el usuario presiona y suelta el botón, apaga esos dos y enciende otros dos. Aquí está mi código hasta el momento (las críticas son muy bienvenidas):

`timescale 1ns / 1ps

module led_flip_flop(input wire clk,
                     input wire button,
                     output wire [3:0] led);

   parameter state_on_idle = 3'b000;
   parameter state_on_push = 3'b001;
   parameter state_on_pop = 3'b010;
   parameter state_off_idle = 3'b011;
   parameter state_off_push = 3'b100;
   parameter state_off_pop = 3'b101;

   reg                                 led_sig;
   reg [2:0]                           state;
   reg [2:0]                           next_state;

   initial
     begin
        led_sig = 1'b1;
        state = state_on_idle;
        next_state = state_on_idle;
     end

   always @ (posedge clk)
     begin
        // Clock-synchronized state change feed-back loop.
        // No reset is implemented yet.
        state <= next_state;
     end

   // Button press/release & led on/off flip FSM.
   always @ (state or button)
     case (state)
       state_on_idle:
         // LED is on, button was untouched.
         // If the button is pressed now, switch to next state
         // to wait for release.
         begin
            led_sig = 1'b1;
            next_state = button ? state_on_push : state_on_idle;
         end

       state_on_push:
         // LED is on, button was pressed.
         // If the button is release now, switch to next state
         // that will turn off the LED and go IDLE with LEDs off.
         begin
            led_sig = 1'b1;
            next_state = button ? state_on_push : state_on_pop;
         end

       state_on_pop:
         begin
            // LED was on, button got pressed and released.
            // Switch the LED off, go into IDLE state.
            led_sig = 1'b0;
            next_state = state_off_idle;
         end

       state_off_idle:
         begin
            // IDLE state with LEDs off. Button was untouched.
            // If button is pressed then go to the next state
            // that waits for the button release in order to
            // turn on LEDs.
            led_sig = 1'b0;
            next_state = button ? state_off_push : state_off_idle;
         end

       state_off_push:
         begin
            // LEDs are off. Button was pressed. Wait for the button
            // release in order to enable LED(s).
            led_sig = 1'b0;
            next_state = button ? state_off_push : state_off_pop;
         end

       state_off_pop:
         begin
            // LEDs were off, button clicked. Enable LED(s) and
            // go into IDLE state with high beams.
            led_sig = 1'b1;
            next_state = state_on_idle;
         end

       default:
         // Some foobar state... Recover.
         begin
            led_sig = 1'b1;
            next_state = state_on_idle;
         end
     endcase

   assign led[0] = led_sig;
   assign led[1] = ~led_sig;
   assign led[2] = led_sig;
   assign led[3] = ~led_sig;

endmodule

Fue sintetizado para el Spartan-6 LX9 FPGA. Aquí está el esquema:

Esquemas generados por Xilinx ISE

Lo probé manualmente en un dispositivo real y parece funcionar. Así que hoy estaba practicando simulación de banco de pruebas y escribí el siguiente banco:

`timescale 1ns / 1ps

module test_bench();

   reg clk;
   reg button;
   wire [3:0] led;

   led_flip_flop prog(clk, button, led);

   initial begin
      #20000 $finish;
   end

   initial
     begin
       clk = 0;
       forever #5 clk = ~clk;
     end

   initial
     begin
       button = 0;
       forever #({$random} % 11) button = ~button;
     end

endmodule

Antes tenía un retraso fijo para el button = ~buttoncomunicado y las señales en simulación se veían bien. Sin embargo, con el retraso aleatorio, parece que las señales de presionar y soltar el botón podrían aparecer entre las luces estroboscópicas del reloj, por lo que las señales se ven así:

ondas

Unas ondas que me parecen mal marcadas en rojo.

Según tengo entendido, hay un problema si la señal del botón es corta y se produce entre ciclos de reloj. Por supuesto, en la vida real, solo Chuck Norris puede presionar y soltar un botón lo suficientemente rápido como para pasar entre un reloj de 66 MHz.

Sin embargo, eso planteó algunas preguntas en mi cabeza...

  1. Si las señales externas vienen con una frecuencia más alta que la frecuencia del reloj (o si el procesamiento de una señal toma varios ciclos de reloj), ¿cuáles son los enfoques genéricos para procesar tales señales?
  2. ¿Debe el reloj estar siempre involucrado? Por ejemplo, ¿puedo lograr lo mismo sin usar el reloj?
  3. ¿Es esto lo que se llama "cruzar un dominio de reloj"?

¿O tal vez estoy haciendo algo totalmente incorrecto y tonto?

Cualquier ayuda es apreciada. ¡Gracias!

Por lo general, se considera una mala práctica usar cables para alimentar su salida, generalmente se considera que tiene características deficientes de abanico.

Respuestas (3)

Si las señales externas vienen con una frecuencia más alta que la frecuencia del reloj (o si el procesamiento de una señal toma varios ciclos de reloj), ¿cuáles son los enfoques genéricos para procesar tales señales?

Un enfoque es utilizar un reloj más rápido. La mayoría de los FPGA (incluido su Spartan 6) tienen una lógica dedicada para generar diferentes relojes a partir de un reloj fuente. Xilinx los ha llamado DCM (Digital Clock Managers) en el pasado, aunque creo que Spartan 6 tiene un PLL real y bloques similares a DCM (pueden llamarse de otra manera en estos días).

Estos son agradables. Puede colocar un cristal de 12 MHz en su PCB para minimizar las emisiones, y luego dentro del FPGA puede multiplicar el reloj hasta, por ejemplo, 96 MHz (una multiplicación de 8x)

También puede probar la lógica de reloj en el flanco descendente y el flanco ascendente. Esto le daría la apariencia efectiva de un reloj 2x (también llamado DDR), pero su lógica se complica porque debe dividir el diseño entre lógica descendente y ascendente.

Los DCM también pueden generar relojes que están desfasados ​​90, 180 o 270 grados con respecto al reloj entrante. Entonces, si realmente necesita muestrear una señal más rápido de lo que puede manejar el FPGA, puede usar el reloj de 90 grados y hacer el mismo truco DDR. Esto le daría cuatro oportunidades para muestrear una señal entrante con el reloj FPGA más rápido posible, pero nuevamente esto se vuelve complicado porque ahora está negociando la lógica entre dos conjuntos de flancos ascendentes y descendentes.

.

¿Debe el reloj estar siempre involucrado? Por ejemplo, ¿puedo lograr lo mismo sin usar el reloj?

Podrías darle una oportunidad a la lógica combinatoria pura. Pero en general representa una pesadilla temporal. Los FPGA tienen un mar de chanclas y son muy importantes para lograr el cierre de tiempo. Realmente es una buena práctica cronometrar todo lo que pueda permitirse cronometrar. Los IOB de FPGA (los búferes de entrada y salida, que envían o reciben señales al mundo exterior) tienen flip flops integrados con el propósito expreso de hacer que el cierre de tiempo sea más fácil de lograr.

Ni siquiera estoy muy seguro de cómo harías esto sin fichar.

.

¿Es esto lo que se llama "cruzar un dominio de reloj"?

Casi. Cruzar un dominio de reloj, como se mencionó anteriormente, ocurre cuando la salida y la entrada no comparten un reloj común. La razón por la que esto es malo es que esos relojes suelen ser asincrónicos. Como ingeniero, siempre debe considerar que la E/S asíncrona hará todo lo posible para cambiar en el peor momento posible.

Las entradas de botón son asíncronas, por lo que sufren los mismos problemas que los dominios de reloj cruzados. El problema con una señal asíncrona es que los flip flops tienen parámetros conocidos como tiempos de configuración y espera. El tiempo de configuración es el tiempo que la señal debe permanecer estable antes del borde del reloj. El tiempo de espera es el tiempo que la señal debe permanecer estable después del borde del reloj. Si tiene una infracción de configuración o retención, el flip flop puede volverse metaestable. Esto significa que no tienes idea de cuál será la salida. En el siguiente borde del reloj, generalmente se arregla solo. (los flip flops también pueden volverse metaestables si tienen un voltaje entre Vih y Vil aplicado durante el borde del reloj, pero eso no es un problema en el FPGA) Creo que también leí una vez en alguna parte que el tiempo de espera en los FPGA generalmente se considera que es 0, y la razón principal por la que no obtiene el cierre de tiempo es un tiempo de configuración insuficiente.

Para manejar entradas asíncronas, usamos sincronizadores. Esencialmente, colocamos varios flip flops entre la entrada asíncrona y la lógica a la que está conectado. Si el primer flip flop se vuelve metaestable, no estropeará el segundo flip flop... con suerte. Sin embargo, todavía puede hacerlo, pero el tiempo medio entre fallas podría ser de años. Si eso no es suficiente, coloca aún más chanclas para reducir el MTBF a niveles aceptables.

Ahora, en términos de "dominios de relojes cruzados", solo necesita el sincronizador si sus relojes están sincronizados entre sí. Uno de los beneficios del DCM es que puede generar múltiples frecuencias de reloj perfectamente sincronizadas. Entonces, si tiene un cálculo "grande" que lleva mucho tiempo completar, puede usar un reloj de 12 MHz, mientras que el reloj de 96 MHz muestrea las entradas. Dado que ambos provienen del DCM, cada borde de 12 MHz se alinea perfectamente con un borde de 96 MHz, por lo que no es necesario usar un sincronizador.

EDITAR: respuesta al comentario

Entonces, los relojes no pueden pasar mi flip-flop de forma asíncrona, obviamente porque solo puede haber una señal a la vez (física pura). Por lo tanto, la sincronización es necesaria para manejar un reloj que "hace tictac" entre los otros ciclos de reloj. Si eso es correcto, ¿qué sucede si mi lógica (retardo de puerta combinado) es mayor que el reloj de entrada? ¿Me joden en silencio, la señal simplemente "desaparece" en su camino a través de las puertas, o el reloj de entrada se pierde?

Voy a ser un poco quisquilloso con el lenguaje aquí porque a veces es importante hacer distinciones. Los relojes están sincronizados entre sí, pero cada flip-flop está sincronizado con su propio reloj. La señal asíncrona es la salida del reloj en un dominio y la entrada de un reloj en el otro dominio.

Digamos que tiene dos cristales en un tablero a 48 MHz. No son ambos precisamente48 MHz. Entonces, si cronometra dos flip flops en serie con los dos cristales y un inversor al final para que cambien cada ciclo, eventualmente hará que el primer flip flop emita una señal que viole el tiempo de configuración de la entrada del segundo flip flop en relación con el reloj de la segunda chancleta; pero en cuanto al reloj de la primera chancleta, todo va según lo planeado. El segundo reloj fallará durante un ciclo; puede subir, puede bajar, puede ir en algún punto intermedio, puede comenzar a ir en una dirección y luego cambiar abruptamente a otra a la mitad del ciclo del reloj, etc. Después del siguiente segundo tic del reloj, probablemente muestree correctamente su entrada y actualizar su salida... probablemente. Es por eso que para una confiabilidad realmente alta, colocan más flip flops en el sincronizador,

Eso es algo artificial para un ejemplo, pero es fácil ver cómo esos relojes tendrían un incidente metaestable periódico que es una función de la diferencia en las velocidades de los cristales. Para cosas como botones, sucede básicamente de forma totalmente aleatoria. Esta es también la razón por la que algunos protocolos llevan su propio reloj de alguna manera (por ejemplo, RS232, USB tiene un reloj implícito en los datos; I2C, SPI tienen un seguimiento de reloj explícito), para evitar cruzar los dominios del reloj.

.

Cuando su diseño sea sintetizado/mapeado/colocado/enrutado, las herramientas le indicarán el retardo de propagación máximo para cualquier lógica que toque un flip flop en su diseño. Si supera esta frecuencia, infringió las reglas y la FPGA no es responsable. De hecho, generalmente querrás ir un poco más lento. Entonces, lo que debe hacer es decirle a las herramientas de diseño (para Xilinx, esto usa un archivo de restricción) "Cuando esté colocando y enrutando, intente mantener todo a una distancia máxima de 19 ns" (~ 52 MHz), entonces realmente usa un 48 Cristal de MHz (20,8 ns), lo que le proporciona 1,8 ns de holgura (alrededor del 9%).

Hacer que su diseño se encamine a la velocidad deseada se llama "lograr el cierre de tiempo". Para diseños más complejos, debe considerar dónde colocar chanclas adicionales para ayudar a canalizar el proceso y mantener la velocidad del reloj. El Pentium 4 es un ejemplo extremo; Las etapas de tubería 5 y 20 existían con el único propósito de permitir que las señales se propagaran a través del chip, permitiéndoles hacer que la velocidad del reloj fuera muy alta. Dado que el FPGA tiene un DCM, si necesita sincronizar una pieza lógica muy grande en una etapa (por ejemplo, un decodificador o mux muy grande), puede hacer que el DCM haga un reloj de "lógica lenta" para manejar esa parte, y luego tener un reloj de "lógica rápida" para las otras partes. Esto también ayuda un poco con el consumo de energía, para cualquier etapa que se ejecute con el reloj lógico lento.

Por pura lógica combinatoria, las herramientas le indicarán el retraso máximo de pad a pad; es decir, cuánto tiempo tarda una señal en llegar desde el pad de entrada, a través de toda la lógica y de regreso al pad de salida. El problema con tal lógica es que no tiene concepto del pasado. No recuerda si la luz estaba encendida o apagada. Probablemente podría diseñar sus propios elementos de retroalimentación (por ejemplo, el pestillo SR), tal vez incluso usando los ajustes/reinicios de los flip flops integrados, pero en este punto está comenzando a convertirse en lógica secuencial, por lo que también podría dar el paso y obtener todo cronometrado de forma fiable.

Eso es en profundidad, ¡muchas gracias! Tengo una pregunta tonta más si se me permite. Entonces, los relojes no pueden pasar mi flip-flop de forma asíncrona, obviamente porque solo puede haber una señal a la vez (física pura). Por lo tanto, la sincronización es necesaria para manejar un reloj que "hace tictac" entre los otros ciclos de reloj. Si eso es correcto, ¿qué sucede si mi lógica (retardo de puerta combinado) es mayor que el reloj de entrada? ¿Me joden en silencio, la señal simplemente "desaparece" en su camino a través de las puertas, o el reloj de entrada se pierde? No tengo claro qué significa exactamente "pesadilla del tiempo". ¡Gracias!
Edité mi respuesta con una respuesta a su comentario, ya que no encajaría en un comentario.

Si las señales externas vienen con una frecuencia más alta que la frecuencia del reloj (o si el procesamiento de una señal toma varios ciclos de reloj), ¿cuáles son los enfoques genéricos para procesar tales señales?

Si necesita detectar todos esos eventos, necesita un reloj más rápido. Posiblemente, puede usar un reloj extrarrápido para alimentar la señal de entrada a un registro de desplazamiento, luego usar el reloj más lento para leer varias muestras de la entrada y procesarlas en paralelo.

Si es más inteligente, probablemente pueda pensar en una forma de hacer una lógica sin reloj usando señales de protocolo de enlace, etc., o conecte la entrada al pin del reloj de un contador para contar la cantidad de eventos de entrada. Pero este tipo de lógica no funciona bien con las herramientas de diseño de FPGA.

¿Debe el reloj estar siempre involucrado? Por ejemplo, ¿puedo lograr lo mismo sin usar el reloj?

Para un caso en el que no necesita ver todos los eventos entrantes, pero necesita saber si uno o más eventos ocurrieron desde el último flanco del reloj, puede intentar algo como conectar la señal entrante al conjunto o restablecimiento (asíncrono) entrada de un flip-flop; luego use otra señal para borrar el flip-flop a un estado predeterminado después de que haya detectado su cambio en su otra lógica.

¿Es esto lo que se llama "cruzar un dominio de reloj"?

"Cruzar un dominio de reloj" cubre los casos en los que las señales generadas en sincronización con un reloj necesitan ser leídas por la lógica controlada por otro reloj. En este caso, su entrada es totalmente asincrónica y no tiene ningún reloj de control, por lo que no creo que sea estrictamente un ejemplo, pero es un problema muy similar.

la transición del botón tiene muchos rebotes. Por lo tanto, se necesita un pestillo o filtro de "cambio de rebote".

Gracias. ¡No sabía eso de los botones! ¡Maldita electricidad arruinando las cosas! Busqué una buena explicación con algunos ejemplos de código aquí: fpga4fun.com/Debouncer.html
en realidad <0,5 mS de rebote es excepcional. Solíamos lidiar con un rebote de 10 mS. Gracias a los mecánicos.
El rebote acordado de 10 ms generalmente se acepta por lo que he visto. No olvide que si bien su interruptor solo rebota durante 4 o 5 ms en la actualidad, es muy posible que rebote durante mucho más tiempo a medida que comienza a envejecer. Además, dependiendo de las tolerancias de fabricación, diferentes interruptores pueden rebotar en diferentes cantidades.