En los sistemas digitales el reloj es el elemento que marca el sincronismo entre todos los elementos del circuito. Cada vez que hay un cambio, normalmente de 0 a 1, del reloj, los elementos de memoria, llamados biestables o flip-flops se cargan con los nuevos datos calculados durante el periodo transcurrido entre el cambio anterior y el actual.

Podemos describir por tanto el reloj del sistema como su corazón, donde cada palpitación hace fluir las señales desde unos biestables hasta su destino, que será otro biestable. El tiempo que tarde la señal en llegar de su origen a su destino entre dos pulsaciones de este corazón eléctrico, lo denominamos el camino crítico del circuito, y es la velocidad máxima a la que puede latir el reloj, ya que si fuera más rápido las señales no serían estables a las entradas de los flips-flops y el circuito comenzaría a dar resultados erroneos.

Cada FPGA necesita tener conectada a alguno de sus pines de entrada una señal de reloj. El reloj desde ese pin se propagará a través de líneas internas a los recursos de la FPGA utilizados para implementar el diseño.

Esta entrada vendrá habitualmente de un componente externo llamado oscilador, que genera una señal cuadrada de una frecuencia fija, por ejemplo 100Mhz o 250Mhz. En muchísimas ocasiones a partir de un reloj de esa frecuencia deberemos generar uno o varios relojes a otras frecuencias. Y es en este punto donde comienzan las dudas y los errores.

Cuando tenemos que generar un reloj de, digamos, la mitad de frecuencia 0 10 veces menos frecuencia que el original, la opción más utilizada es crear un contador, en VHDL, Verilog o el lenguaje RTL que utilicemos que cada vez que se llegue al valor deseado invierta la señal del reloj, generando una señal cuadrada de la frecuencia que deseamos.

En este código que os presentamos a continuación tenéis este ejemplo de un divisor parametrizable para dividir el reloj, junto a su testbench. Pero antes de lanzaros a Vivado o Quartus, seguid leyendo, porque esto no deberíais usarlo nunca o muy pocas veces.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity clk_div is
    generic (divider : integer range 0 to 1023);
    port (
        clk_i : in  std_logic;
        clk_o : out std_logic
    );
end clk_div;
 
architecture Behavioral of clk_div is
  signal clk_s: std_logic:='0';
  signal contador: integer range 0 to divider;
begin
  clk_o <= clk_s;

  process (clk_i) begin
    if rising_edge(clk_i) then
      if (contador = divider) then
        clk_s <= not(clk_s);
        contador <= 0;
      else
        contador <= contador+1;
      end if;
    end if;
  end process;

end Behavioral;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity test is
end test;
 
architecture Behavioral of test is

  signal clk_i : std_logic :='0';
  signal clk_o : std_logic;

begin

clk_i <= not(clk_i) after 10 ns;

divisor: entity work.clk_div generic map(4) port map(clk_i, clk_o);

end Behavioral;

LA salida que genera este código se muestra en la siguiente imagen donde se puede ver como el contador va de 0 a 4 y cuando llega a 4 el reloj de salida cambia.

divisor de reloj
Divisor reloj en VHDL

Cuando generamos un reloj dividido mediante lógica, como es este caso, el reloj se propaga por lineas internas de la FPGA no dedicadas. El reloj es una señal muy importante y es por eso que debe llegar lo mas simultaneamente posible a todos los puntos del diseño (a esto se le llama skew) y con la menor distorsión. Un reloj generado de esta manera, no se enrutará por las líneas habilitadas para el reloj y además puede sufrir oscilaciones (denominados glitches), que arruinen el funcionamiento del circuito. Como normal general este tipo de divisores solo deben utilizarse cuando la frecuencia de los relojes sea muy baja, del orden de Khz o menos.

Para diseñar correctamente un divisor de reloj debemos utilizar los bloques que nos proporcionan los fabricantes de las FPGA, en este artículo utilizaremos FPGA de Xilinx, en concreto una FPGA Artix-7 con la placa Nexys4.

En familias mas antiguas se utilizaba un módulo denominado DCM, (Digital Clock Manager), con ñel a partir de un reloj de entrada podíamos generar relojes divididos por el factor deseado, desfasados o multiplicados x2. Este módulo solo puede usarse en las familias Virtex-II, Virtex-II Pro, Virtex-II Pro X, Virtex-4, Virtex-5, Spartan-3, Spartan-3E y Spartan-3A.

Generador DCM, solo valido para familias antiguas de FPGA Xilinx

En las FPGA de las últimas series este modulo ha sido sustituido por el Clock Wizard, un componente que nos permite generar multiples relojes mediante un asistente que genera una plantilla en el lenguaje (VHDL o Verilog) deseado, así como ficheros de simulación y componentes para instanciar en nuestros diseños.

Para utilizar el Clock Wizard en Vivado, iremos al catalogo de IP y buscaremos el Clocking Wizard. Una vez seleccionado podremos configurar nuestro generador de reloj, que nos dará a la salida un reloj estable, y enrutado por las líneas correctas de la FPGA.

Clocking Wizard general
Pantalla principal Clocking Wizard

En el Clocking Wizard deberemos elegir si nuestro generador utiliza el MMCM o el PLL. A niveles básicos nos da igual elegir uno u otro, nosotros escogeremos el MMCM que es más completo. También debemos especificar la frecuencia del reloj de entrada que vamos a utilizar en este caso 100MHz.

En la siguiente pantalla ya podremos escoger qué relojes vamos a tener en la salida y el factor de división. En este caso vamos a generar dos relojes, uno igual que la entrada y el segundo dividido entre 10, es decir a 10Mhz. Podemos generar hasta 8 relojes diferentes. También deberemos elegir si el reset es activo alto o bajo.

Clocking Wizard relojes salida
Seleccionar los relojes a generar

Una vez hecha la configuración, podemos generar los ficheros necesarios para utilizar el componente en simulación o síntesis. Vivado nos habrá creado un componente para que podamos instanciarlo en nuestro código y asi utilizarlo, e incluso un proyecto completo para que podamos simular y probar el componente. Para acceder a él debemos hacer click con el botón derecho encima del componente generado y pulsar en Open IP Example Design. Esto nos abrirá una ventana nueva de Vivavo donde podremos simular el generador de reloj.

Simulacion con Vivado del Clocking Wizard
Simulación con Vivado

Cómo se ve en la simulación obtenida, a la salida obtenemos un reloj igual que la entrada y otro dividido entre 10.

En nuestro caso cuando vayamos a utilizar el componente en VHDL deberemos instanciar el componente siguiente, que ha sido generado por el asistente.

  component clk_wiz_0
  port
   (-- Clock in ports
    -- Clock out ports
    clk_out1          : out    std_logic;
    clk_out2          : out    std_logic;
    -- Status and control signals
    reset             : in     std_logic;
    locked            : out    std_logic;
    clk_in1           : in     std_logic
   );
  end component;