Digamos que, por alguna razón, necesitas incluir dos relojes en tu módulo en VHDL.
¿Cómo le haces?
Puedes ver el siguiente video o continuar leyendo la entrada:
En el listado 1 tenemos un fragmento de código con lo que queremos hacer: modificar una salida en base a dos frecuencias distintas, el reloj 1 o el reloj 2.
salida_p: process (clk_1, clk_2, reset) begin if reset = '1' then salida_tmp <= '0'; elsif rising_edge(clk_1) then salida_tmp <= NOT salida_tmp; elsif rising_edge(clk_2) then salida_tmp <= NOT salida_tmp; end if; end process;
Al querer sintetizar en Vivado, obtenemos un error:

Figura 1: Error de síntesis en Vivado.
Resulta que no puede haber un else
, o elsif
, después de la cláusula donde revisamos un flanco de subida.
¡Bah!
Entonces, si queremos hacer lo mismo pero en dos frecuencias distintas, debemos crear un nuevo proceso para seleccionar el reloj.
Esto quiere decir que necesitaremos una entrada adicional para seleccionar el reloj y una señal interna para almacenar la frecuencia deseada.
Y en el nuevo proceso utilizamos nuestra entrada de selección, sel
, para mandar uno de los dos relojes a la señal interna.
Finalmente, se modifica el proceso original, eliminando el elsif
del segundo reloj y tomando como reloj a nuestra señal interna.
El resultado de estos cambios, que producen código que sí sintetiza, se muestra en el listado 2:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity dos_relojes is Port ( clk_1 : in STD_LOGIC; -- Primer frecuencia clk_2 : in STD_LOGIC; -- Segunda frecuencia sel : in STD_LOGIC; -- Selector de frecuencia reset : in STD_LOGIC; -- Reset de señal de salida salida: out STD_LOGIC -- Salida para demostración ); end dos_relojes; architecture Behavioral of dos_relojes is signal salida_tmp: STD_LOGIC := '0'; signal clk_tmp: STD_LOGIC := '0'; begin clk_select_p: process (clk_1, clk_2, sel) begin if sel = '0' then clk_tmp <= clk_1; else clk_tmp <= clk_2; end if; end process; salida_p: process (clk_tmp, reset) begin if reset = '1' then salida_tmp <= '0'; elsif rising_edge(clk_tmp) then salida_tmp <= NOT salida_tmp; end if; end process; salida <= salida_tmp; end Behavioral;
Realizamos un banco de pruebas, mostrado completamente en el listado 3:
library IEEE; use IEEE.Std_logic_1164.all; use IEEE.Numeric_Std.all; entity dos_relojes_tb is end; architecture bench of dos_relojes_tb is component dos_relojes Port ( clk_1 : in STD_LOGIC; clk_2 : in STD_LOGIC; sel : in STD_LOGIC; reset : in STD_LOGIC; salida: out STD_LOGIC ); end component; signal clk_1: STD_LOGIC; signal clk_2: STD_LOGIC; signal sel: STD_LOGIC; signal reset: STD_LOGIC; signal salida: STD_LOGIC ; constant clock_1_period: time := 10 ns; constant clock_2_period: time := 50 ns; signal stop_the_clock: boolean; begin uut: dos_relojes port map ( clk_1 => clk_1, clk_2 => clk_2, sel => sel, reset => reset, salida => salida ); stimulus: process begin -- Inicialización reset <= '1'; wait for 5 ns; reset <= '0'; wait for 5 ns; -- Los primeros 1500 ns, tras reset, será clk_1 sel <= '0'; wait for 1500 ns; -- Los siguientes 1500 ns, será clk_2 sel <= '1'; wait for 1500 ns; stop_the_clock <= true; wait; end process; clocking_1: process begin while not stop_the_clock loop clk_1 <= '0', '1' after clock_1_period / 2; wait for clock_1_period; end loop; wait; end process; clocking_2: process begin while not stop_the_clock loop clk_2 <= '0', '1' after clock_2_period / 2; wait for clock_2_period; end loop; wait; end process; end;
Seleccionamos inicialmente el primer reloj durante 1,500 nanosegundos (líneas 46 y 47), lo que da una señal de salida de 20 ns (nuestra constante de clock_1_period
es de 10 ns).
El resultado de esta primera parte se muestra en la figura 2:

Figura 2: Resultado de la simulación al utilizar el reloj 1.
La segunda mitad de la simulación utiliza el segundo reloj (líneas 49 y 50), por lo que la señal de salida es de 100 nanos (clock_2_period
es de 50 ns). Ésto se refleja en la figura 3:

Figura 3: Resultado de la simulación al utilizar el reloj 2.
Muy bien. Ahora sabemos que no podemos tener dos relojes en un mismo proceso.
Pero nada nos impide hacer un proceso que asigne uno de los dos relojes a otra señal que funja como reloj único.
Ah, cierto, el enlace de descarga:
Si te quedan dudas, no dudes en comentar, ya sea aquí o en el video.
2 Comentarios
andres felipe
marzo 28, 2018 at 8:56 amhola necesito hacer un cronometro en vhdl y tengo el boton de inicio y para detenerse bien pero cuando quiero agregarle un boton que mantenga el ultimo valor del cronometro por 10 seg el programa aunque compila la fpga no hace nada y no tengo idea por que si podrias ayudarme muchas gracias
Jaime
febrero 5, 2019 at 3:48 amHola,
Te falta el multiplexor de reloj. Como metas eso en un diseño de verdad va a reventar Vivado por 7 sitios 🙂