Divisor de frecuencia para reloj de 1Hz en VHDL

reloj 1hz

Los circuitos digitales, a no ser que sean asíncronos, van comandados por un reloj cuya frecuencia puede variar según el tipo de sistema digital del que se trate. Desde microprocesador 6502 que funcionaba con un reloj de 1Mhz hasta los actuales, que funcionan en el orden de los gigahercios, no han pasado ni cuatro décadas. En un sistema digital complejo es habitual que necesitemos obtener diferentes frecuencia de reloj para diferentes subsistemas. Un ejemplo muy claro puede ser el de un reloj digital que tiene que contar los segundos, por lo tanto, necesita un reloj de 1Hz (un pulso por segundo). En este artículo vamos a ver un ejemplo práctico de cómo obtener un reloj de 1Hz a partir de otro de 50Mhz en VHDL, y vamos a probarlo un una FPGA.

La técnica usada para dividir la frecuencia de un reloj es usar biestables conectados en cascada. En la siguiente esquema se detalla el funcionamiento.

Divisor de frecuencia

Cada biestable divide la frecuencia a la mitad, así que la idea es ir acoplando biestables hasta obtener la frecuencia deseada. En la práctica pueden usarse contadores integrados como el 7493. En una FPGA podemos conseguir el mismo efecto usando un contador, aunque la mayoría ya trae circuitos especializados para ello, vamos a ver cómo se hace en VHDL.

Para este ejemplo voy a usar una placa basada en una FPGA Altera EP1C3T144 (de la familia Cyclone I). Esta placa tiene un reloj interno de 50Mhz, así que sin más preámbulo os muestro el código VHDL del divisor de frecuencia.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
entity digital_clock_top is
port (
	clk50mhz: 	in STD_LOGIC;
	clk:		out STD_LOGIC
);
end digital_clock_top;

architecture rtl of digital_clock_top is
	constant max_count: INTEGER := 50000000;
	signal count: INTEGER range 0 to max_count;
	signal clk_state: STD_LOGIC := '0';
	
begin
	gen_clock: process(clk50mhz, clk_state, count)
	begin
		if clk50mhz'event and clk50mhz='1' then
			if count < max_count then 
				count <= count+1;
			else
				clk_state <= not clk_state;
				count <= 0;
			end if;
		end if;
	end process;
	
	persecond: process (clk_state)
	begin
		clk <= clk_state;
	end process;
	
end rtl;

El módulo tiene una entrada, que es el reloj de 50Mhz, y una salida que cambiará de estado una vez por segundo (1Hz).

Un reloj de 50Mhz varía su estado cada 20ms, sin embargo, nosotros necesitamos que los haga cada segundo. Como 50Mhz son 50.000.000Hz, he usado un contador que lleva la cuenta del número de cambios de estado de la entrada de reloj. Cuando este contador llega a 50.000.000, se cambia el estado del reloj de salida (el de 1Hz). En realidad, si analizas el código, estoy usando una señal llamada clk_state para gestionar el estado del reloj de salida. Esto es debido a que en VHDL no es posible leer el estado de una señal de salida y, por lo tanto, la operación clk->not clk es ilegal. Se podría haber usado un buffer, pero me he llevado más de una desagradable sorpresa usándolos en circuitos más complejos, así que personalmente prefiero evitarlos.

También habrás observado que uso un segundo proceso para cambiar el estado del reloj de salida. Lo cierto es que no es necesario y podría haberse puesto la instrucción clk<=clk_state justo después de cerrar el el proceso principal, pero como normalmente querremos hacer algo útil con este reloj (por ejemplo, mostrar la hora en un display), lo he situado en un proceso aparte.
Os dejo el código de un techbench por si queréis simularlo.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity test is
end entity test;

architecture testbench of test is
    signal clk1 : STD_LOGIC := '0';
    signal clk_out : STD_LOGIC;
begin
    clk1 <= not clk1 after 20 ns;
    conec: entity work.digital_clock_top(rtl) port map (clk1, clk_out);
end architecture testbench;

El resultado de la simulación se puede ver en la imagen de la cabecera del artículo.

Ahora vamos a probarlo en la FPGA. En la placa que estoy usando, la entrada de reloj se encuentra en el pin 92 de la FPGA, así que es ahí donde asignaremos la señal clk50mzh del código VHDL. La salida clk vamos a asignarla al pin 57, que está conectado a un led.

Asignación de pines

Os dejo un vídeo con el resultado final en el que se observa como parpadea el led con una cadencia de 1 segundo.

5 Comentarios en "Divisor de frecuencia para reloj de 1Hz en VHDL"

  1. Andres | en | Responder

    Me podrias ayudar; ¿Como puedo cambiar el valor de la frecuencia de salida? por ejemplo aumentarle a que sea 10Hz o mas.
    gracias

    • Alberto García | en | Responder

      Hola Andrés,

      En este caso, el reloj externo es de 50 Mhz, es decir 50.000.000 Hz. Eso quiere decir que cambia de estado 50.000.000 veces por segundo. De esta forma, si queremos contar un segundo sólo hay que esperar a que el reloj cambie de estado 50.000.000 veces. Para conseguir un reloj de 10 Hz hay que dividir la frecuencia de reloj entre 10, es decir, la constante max_count debería tener el valor 5.000.000. En general, para calcular el valor de max_count usamos la formula max_count = freq. reloj externo (Hz) / freq. salida deseada (Hz)

  2. mario | en | Responder

    conque polaridad y nivel de tension se alimenta esta placa? no consigo el manual y tampoco veo que se mencione algun dato de esta fuente externa.

    gracias.

  3. Alex | en | Responder

    Excelente, funciona muy bien, lo metí a una FSM y jala al 100%
    Felicidades.

Deja un comentario.

Tu dirección de correo no será publicada.


*