Clock a diferentes frecuencias en VHDL

lunes, 27 de diciembre de 2010

Clock a diferentes frecuencias en VHDL


En los proyectos Finales de la materia de ETN601 Electronica Digital 1, nos pidieron una serie de proyectos, a realizar en fpga, utilizando las tarjetas de la facu las Cyclone2 de Altera.
Bueno pues, la gran mayoria de los estudiantes solo utilizo el Quartus en modo de captura esquematica y jalando componentes prediseñados (7490, 7483,7408,etc etc) realizaron sus proyectos, PEROOOOOOO no utilizaron lenguaje VHDL que era el objetivo de los proyectos, segun yo los proyectos no calificaban en vhdl, salvo algunos.

Bueno, los estudiantes, aun tienen mucha dificultad con el lenguaje vhdl, y esto se noto en los proyectos finales, uno de los grandes inconvenientes de los estudiantes fue el CLOCK que no supieron como "programar" en vhdl, unos se idearon y utilizaron la idea de reloj externo, para poder obtener 1hz (1segundo para reloj) y otros simplemente utilizaron los Pushbutton dela fpga.

Bueno en esta ocasion quiero compartir con ustedes 2 divisores de frecuencia de distintas sentencias que realizan algo semejante.

Ejemplo 17:
Diseñar en VHDL, un reloj de 1hz (1 segundo), que luego utilizaremos para realizar un reloj digital.

Solucion:
La DE2 board incluye 2 osciladores que producen señales de reloj de 27 MHz  y 50 MHz . La tarjeta tambien incluye un conector SMA que se utiliza para conectar un reloj externo a la tarjeta

Utilizaremos el clock interno de 50Mhz de la tarjeta para poder obtener mediante VHDL una frecuencia a la salida de 1Hz


---------------------------------------------------
--             electronico-etn.blogspot.com
---------------------------------------------------
-- Autor:        Americo Alvarez S.
-- Descripcion:    Reloj de 1Hz, utilizando reloj in-
--                     terno de 50Mhz del fpga Cyclone2.
---------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY delay_clock IS
PORT (
        Clk50Mhz: IN STD_LOGIC;
        Clk: OUT STD_LOGIC
        );
END delay_clock;

ARCHITECTURE rtl OF delay_clock IS
    CONSTANT max: INTEGER := 50000000;
    CONSTANT half: INTEGER := max/2;
    SIGNAL count: INTEGER RANGE 0 TO max;
  
BEGIN
    PROCESS
    BEGIN
        WAIT UNTIL Clk50Mhz'EVENT and Clk50Mhz = '1';
        IF
            count < max THEN count <= count + 1;
            ELSE count <= 0;
        END IF;
      
        IF
            count < half THEN Clk <= '0';
            ELSE Clk <= '1';
        END IF;
    END PROCESS;
END rtl;



Ejemplo 18:
Diseñar en VHDL, un reloj de 10hz, Que tenga un reset, que reinicie el clock.

Solucion:
Utilizando en esta ocasion el reloj interno de la fpga de 27Mhz, sacaremos una frecuencia a la salida de 10Hz, utilizaremos la sentencia rising edge que como vimos anteriormente, es lo mismo que clock'event, osea flanco.

---------------------------------------------------
--             electronico-etn.blogspot.com
---------------------------------------------------
-- Autor:        Americo Alvarez S.
-- Descripcion:    Reloj de 10Hz, utilizando reloj in-
--                interno de 27Mhz del fpga Cyclone2.
---------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

ENTITY ck_10hz IS
    PORT ( reset : IN STD_LOGIC;
           clock_in : IN STD_LOGIC;
           clock_out : OUT STD_LOGIC);
END ck_10hz;

ARCHITECTURE rtl OF ck_10hz IS
    signal ck_cnt : unsigned(20 downto 0);
    signal ck_bit : std_logic;

begin
    gen_clock: process (clock_in, reset) is
    begin
    if (reset = '0') then
        ck_cnt <= "000000000000000000000";
        ck_bit <= '0';
    elsif rising_edge(clock_in) then
        if (ck_cnt = 1349999) then
        ck_cnt <= "000000000000000000000";
        ck_bit <= not ck_bit;
        else
        ck_cnt <= ck_cnt + 1;
        end if;
    end if;
    end process;
clock_out <= ck_bit;
end rtl;

vemos en los anteriores ejemplos 2 maneras de realizar el divisor de frecuencias, utilizando tanto el clock interno de 50 Mhz y el de 27Mhz.  Tambien se añadio un reset, para detener el clock cuando nos apetesca.
La idea que se utilizo para los codigos de arriba, fue el de contar paquetes de ciclos de reloj, por ejemplo para 50Mhz se conto los "half" osea 25Mhz osea que cuando pasan los primeros 25 000 000 ciclos de reloj esta en estado '0' la salida, para los siguientes 25 000 000 esta en estado 1 la salida. asi que tenemos 1 segundo exacto.
Para realizar el divisor a 10 Hz se utilizo la misma idea contar paquetes de ciclos de  reloj, teniendo como limite el 27Mhz. osea que en 27 Mhz se tendria que dividir entre 20, 10 ciclos '0' y 10 ciclos '1', que darian los 10 hz.

4 comentarios :

Maximo Tovar dijo...

Amigo tu blog es excelente me sirve muchísimo para la materia de lógica digital. muchas gracias saludos desde Venezuela.

norberto Ramírez dijo...

Que excelente post... El codigo me va a servir demasiado solo que necesito entender.. principalmente el de 50MHz a 1 hz podrias explicar en palabras como es que funciona de antemano gracias!

AméricoAlvarez dijo...

el primer IF del process realiza un conteo.. osea un contador (count)que va incrementando cada flanco de subida (del Cl50Mhz) mientras count no supere 50 000 000 (50 Mhz)...

el segundo IF divide esta cuenta de 50Mhz en 2 estados, osea de 1 a 25M es cero y de 25 000 001 a 50M es cero, lo que equivaldria a un reloj de 1 Hz...

El concepto general es sencillo 50Mhz del reloj lo dividimos entre 50M cuentas, osea tendremos un pulso de 0.5 Hz que dividimos entre 2 para tener un reloj de 1 Hz

MARTIN RODRIGO GEREZ dijo...

Estimado, estuve reutilizando su código, y en la simulación me arroja el estado indeterminado para el clock_out, este inconveniente lo solucioné inicializando en '0' los signals ck_cnt y ck_bit.
De esta manera:

signal ck_cnt: unsigned (20 downto 0):= (OTHERS =>'0');
signal ck_bit: std_logic := '0';

Desde ya gracias x el tiempo.

Saludos!