Mostrando entradas con la etiqueta VHDL. Mostrar todas las entradas
Mostrando entradas con la etiqueta VHDL. Mostrar todas las entradas

domingo, 17 de agosto de 2014

Digital Snake Wing (Part 1) - PLL Test

As you may or may not know, I'm currently working on a Papilio Wing that streams and receives multiple channels of audio over Ethernet using the 5 layer TCP/IP model. The wing includes as an ADC a PCM1807 with a companion PLL1705 to generate the sampling clock frequencies. As a DAC it uses a MAX5556 and as the ethernet controller the ENC28J60.

Here is a render of the PCB and the actual PCB

 

By the way... I manufactured my PCBs with Elecrow and I have to say I am impressed with their quality. They are really cheap and really good :D.

 

Anyway... I've just received my Papilio and I'll be posting stuff as I progress.

The first thing I did was to be shure that the PLL was working, so I made a little test module in VHDL that turned on and off a couple of LEDs synchronously with the PLL output clock. Here is the code. Note tha it uses an IP module from Xilinx called DCM. This module is like a programmable PLL and is the one that converts the input 32MHz clock to the 27MHz clock for the PLL1805. You can get more info here http://papilio.cc/index.php?n=Papilio.DigitalClockManager

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Test_PLL is
    port(
        CK32 : in STD_LOGIC; -- Main Papilio Clock (32MHz)
        CK27 : out STD_LOGIC; -- Clock from the Papilio to the PLL
        CK384fs : in STD_LOGIC; -- Clock from the PLL to the Papilio
        LED1 : out STD_LOGIC;
        LED2 : out STD_LOGIC;
        BTN1 : in STD_LOGIC;
        BTN2 : in STD_LOGIC
        );
end Test_PLL;

architecture Behavioral of Test_PLL is

    COMPONENT DCM32to27
    PORT(
        CLKIN_IN : IN std_logic;          
        CLKFX_OUT : OUT std_logic;
        CLKIN_IBUFG_OUT : OUT std_logic;
        CLK0_OUT : OUT std_logic
        );
    END COMPONENT;
    
signal led1_signal : STD_LOGIC := '0';
signal led2_signal : STD_LOGIC := '1';
begin

    Inst_DCM32to27: DCM32to27 PORT MAP(
        CLKIN_IN => CK32,
        CLKFX_OUT => CK27,
        CLKIN_IBUFG_OUT => open,
        CLK0_OUT => open
    );
    
    -- This process reacts to one of the output clocks of the PLL
    blink: PROCESS(CK384fs)
        variable counter : INTEGER := 0;
    BEGIN
        IF(rising_edge(CK384fs)) THEN
            IF(BTN1 = '1' and BTN2 = '0') THEN -- Button 1 pressed
                counter := counter + 1;
                IF(counter >= 1700000) THEN
                    led1_signal <= not(led1_signal);
                    led2_signal <= not(led2_signal);
                    counter := 0;
                END IF;
            ELSIF(BTN1 = '0' and BTN2 = '1') THEN -- Button 2 pressed
                counter := counter + 1;
                IF(counter >= 17000000) THEN
                    led1_signal <= not(led1_signal);
                    led2_signal <= not(led2_signal);
                    counter := 0;
                END IF;        
            END IF;
        END IF;
    END PROCESS;

    LED1 <= led1_signal;
    LED2 <= led2_signal;    

end Behavioral;

You can also download the Xilinx project from my Github https://github.com/DiegoRosales/VHDL_Modules.git.

 

lunes, 7 de julio de 2014

DAC Wing for the Papilio Platform

Hello again! This time I decided I would start to share my designs over here as well. This time I'll be sharing a Papilio Wing.
As you may or may not know, the Papilio platform is an awesome barebones FPGA platform with Arduino-style headers to plug what they call "Wings" (instead of shields). Since an FPGA usually has a ton of I/O, you can plug a huge ammount of wings to it (or one Mega Wing) like this.


Since the papilio platform is relatively new, there are not a lot of wings for it. This is why I decided to make a proper audio DAC Wing (they have one, but it's based on PWM and a low-pass filter). The wing I made is EXTREMELY simplistic. It's based on the MAX5556 DAC which barely requires anything. It has only a couple of passives and a 3.5mm stereo jack. This is the render of the board.

kJt2oOE.png

The link for the design files (it is open source, obviously) are here (GitHub)
And here is the link to order the board from OSHPark (It is the prototype version).

domingo, 27 de octubre de 2013

Bloques lógicos útiles en VHDL #4 RAM basada en LUTs (asíncrona)

Como ustedes sabrán (o no), hace como 10 minutos aprendí que practicamente todos los FPGAs tienen unos módulos especiales para almacenar datos y leerlos. A estos módulos en inglés se les llama "Look Up Table" o LUT. Esto en cristiano significa algo así como "Ve a ver si ya puso la marrana", pero pues a pesar de que esto lo decimos con el fin de que se vayan a dejar de "molestar", ya que muy probablemente la marrana no ha puesto nada, en el mundo de los FPGAs, la marrana muy probablemente ya puso algo que necesitamos. El caso es que estos módulos almacenan datos y los podemos usar y ordenar como queramos. Un dato importante es que a este tipo de memoria, también se le llama RAM distribuida (Distributed RAM). Para el caso del Spartan 3E, que es el que usa el Basys2, esta memoria varía entre 15 y 38Kbytes, dependiendo cuánto quieras pagar.

Usar esta RAM es algo realmente fácil, y lo hacemos todo el tiempo cuando almacenamos constantes y cosas así, pero ahora la vamos a usar como se debe (más o menos). En estos ejemplos vamos a construir un bloquecito de RAM de 8x8 (8 registros de 8 bits). Este ejemplo es cuando queremos leer la RAM de manera asíncrona. Más adelánte postearé un tutorial de RAM con lectura síncrona

RAM Asíncrona

Primero comenzamos con la declaración de librerías y de puertos.
























Necesitamos declarar ciertas constantes para que nuestro código se pueda adaptar fácilmente. Los puertos que necesitamos son la dirección de la memoria, el dato a enviar, una señal que nos indique cuándo podemos escribir y por último la lectura de la memoria en la dirección deseada.

Ahora nos vamos a la parte de la arquitectura. El truco aquí es crear una matriz de datos (8x8), por lo que necesitamos declarar un nuevo tipo. Llamémosle "tipo_ram". También hay que declarar una señal con este tipo









Por último hay que declarar la manera en la que se va escribir y accesar la memoria.














Nótese que la escritura es síncrona y está controlada por la entrada "escribir". Si esta entrada esta en '0', no escribe y nada más lee. Hay que realizar cambios de tipos, ya que la entrada "dir" esta en "std_logic_vector", pero el índice de la variable "ram" que es "tipo_ram" debe ser "integer".


Como pordán ver la simulación funciona de maravilla. El dato se escribe cuando tenemos un flanco positivo en el reloj y cuando "escribir" es '1'.

Este ejemplo lo saqué de un libro titulado "FPGA Prototyping by VHDL Examples - Xilinx Spartan 3 Version", aunque le modifiqué algunas cosas, como el tamaño de el bloque de la RAM.

Ahora les dejo el código .vhd y los archivos de la simulación

Código .vhd


Simulación usando ActiveHDL


My Github
https://github.com/DiegoRosales

sábado, 26 de octubre de 2013

Bloques lógicos útiles en VHDL #3 Control de sincronización para VGA

Ok, ahora les voy a enseñar como hacer un controlador VGA usando un FPGA para que con base en eso puedan mandarle cualquier imagen a un monitor. Lo primero es entender las señales. Los monitores VGA trabajan con 5 señales básicas: la señal de sincronía vertical, la señal de sincronía horizontal, la señal del color rojo, la señal del color verde y la señal del color azul (RGB). 

Las señales de los colores son analógicas y varían entre 0 y 0.7V. Entre más voltaje, más brillante es el color. Haciendo combinaciones con los tres colores, se puede representar cualquier imagen.

Por otro lado, las señales de sincronía funcionan de la siguiente manera. El monitor va "imprimiendo" cada pixel de izquierda a derecha y de arriba hacia abajo, como se ve en la siguiente imagen



Por lo tanto, tiene que haber alguien que le diga cuándo empieza y cuándo termina. Este alguien son las señales de sincronización vertical y horizontal, y funcionan así.


Tanto la señal horizontal como la señal vertical tienen este formato. La señal comienza con un pulso de sincronización (Sync Pulse). Luego pasa a un "tiempo de espera" llamado Back Porch. Durante el Sync Pulse y el Front Porch, no se despliega ninguna imagen, y es recomendable no mandar a desplegar nada en ese momento. Después de que el pasó el Sync Pulse y el Back Porch, comienza el área visible. Aquí es el momento de comenzar a mandar la imagen. Una vez que termina de mandarse la imagen, se llega a un segundo tiempo de espera llamado Front Porch. Terminando este tiempo, la señal vuelve a comenzar.

Si tenemos un monitor de X pixeles de ancho por Y pixeles de alto, la señal de sincronización horizontal se debe mandar Y veces por cada vez que se refresca la pantalla (una por cada línea). Es decir, si tenemos un monitor de 640x480 pixeles, la señal de sincronización vertical se debe mandar 480 veces por cada señal de sincronización horizontal.

Ahora se estarán preguntando ¿cuánto deben durar estas señales?
Pues la respuesta varía según dos factores: la resolución que deseamos lograr y la frecuencia de actualización de nuestro monitor. La mayoría de los monitores utilizan una frecuencia de 50 o 60Hz, pero las resoluciones pueden variar mucho.

El motivo de estas señales que pueden llegar a ser hasta cierto punto ambiguas, es debido a la tecnología que usaban los monitores CRT. Ahora ya casi nadie usa estos monitores, pero el protocolo VGA sigue siendo bastante popular y prácticamente no ha cambiado.

Aquí es va el ejemplo. Vamos a utilizar una resolución de 640x480 pixeles a una frecuencia de 60Hz. Si se meten a este link (http://tinyvga.com/vga-timing/640x480@60Hz) encontrarán una tabla muy útil que es esta


Se darán cuenta que el Sync Pulse, el Front Porch y todas las partes de la señal se miden en pixeles. Esto facilitará impresionantemente nuestro código. Cabe destacar que aunque dice que necesitamos una frecuencia de pixeles de 25.175MHz, no es necesario generar esa frecuencia exacta, ya que los monitores modernos se pueden acoplar a tan sólo 25MHz. Sin embargo, si se va a usar un monitor viejo, pues sí hay que generar esa frecuencia exacta.

Pues bien, comencemos con el código. Este código está planeado para una tarjeta de desarrollo Basys2 con un FPGA de Xilinx modelo Spartan 3E y un reloj de 50MHz. Esta tarjeta cuenta con un puerto VGA, que internamente tiene un convertidor digital a analógico de 3 bits para el color rojo y el color verde y de 2 bits para el color azul, teniendo un total de 256 posibles colores.

Primero los puertos y las librerías

La única entrada es la señal de reloj de 50MHz.
Las salidas son las señales de sincronización horizontal y vertical, una señal que nos indique en qué momento comienza el área visible, una cuenta de pixeles en X y en Y, y el reloj de 25MHz para que esté todo bien sincronizado.

Ahora siguen las constantes que vamos a usar

Estas constantes son los datos de la tabla de hace un momento

Ahora siguen las señales internas


Ahora comenzamos con el divisor de frecuencia (de 50 a 25 MHz)

Luego, con esta nueva frecuencia, pasamos a hacer un contador horizontal y un contador vertical. Cada vez que el contador horizontal llegue a su límite, el contador vertical aumenta 1

Ahora viene la parte que manda el pulso de sincronización y la parte donde detecta cuándo comienza la parte visible de la señal

Finalmente viene la parte donde la cuenta horizontal y vertical del área visible comienza (aquí es donde se cuenta en qué pixel del área visible nos encontramos), y las asignaciones de las señales.

Como podrán ver, si lo implementamos en el FPGA, obtenemos estas señales (arriba es la horizontal y abajo es la vertical)


Señal horizontal completa


Pulso de sincronización vertical


Pulso de sincronización horizontal

Y pues si hacemos un código de prueba que despliegue 3 colores verticales, obtenemos el siguiente resultado



Y pues bueno, aquí les dejo los códigos de la simulación en Active HDL y del proyecto completo del Xilinx ISE Design Suite. Incluyen la imagen de prueba.

Simulación


Proyecto


Puro código de sincronización


My Github
https://github.com/DiegoRosales

jueves, 10 de octubre de 2013

Bloques lógicos útiles en VHDL #2 - Contador de 1 bit (divisor de frecuencia)

Bueno, ahora les mostraré cómo se puede hacer un contador de 1 bit por si quieren dividir su señal de reloj entre 2 o cualquier cosa que necesiten. Este es un contador utilizando los muy útiles FlipFlops tipo D con Clear y Chip Enable (FDCE). Les enseño el circuito


El código para implementar este circuito es muy sencillo. Se los muestro

library IEEE;
use IEEE.std_logic_1164.all;

library UNISIM;
use UNISIM.vcomponents.all;

entity contador_1bit is
port(
CK1: in std_logic; -- Reloj de entrada(50MHz)
CK2: out std_logic -- Reloj de salida (25MHz)
);
end contador_1bit;

architecture contador_1bit of contador_1bit is

signal notQ, temp_Q: std_logic; -- Crea las señales a utilizar
begin
bit0: FDCE generic map ('0') -- Comienza en 0
port map (C=>CK1, D=>notQ, Q=>temp_Q, CE=>'1', CLR=>'0');         -- Asigna los pines  
notQ<=not temp_Q; 
      -- Niega la salida del FDCE y la regresa a la entrada
CK2<=temp_Q; -- Asigna la salida
end architecture;

Como podrán ver, hice uso del FDCE que vimos la vez anterior. Con esto ya no tenemos que construir nuestros Flip Flops, pues ya vienen hechos. Para que vean que sí funciona, les enseño la simulación.


Les dejo los archivos que utilicé en mi cuenta de MediaFire.

domingo, 6 de octubre de 2013

Bloques lógicos útiles en VHDL #1 - Flip Flop tipo D con Clear y Chip Enable (FDCE)

Como ahora ando metido en esto de los FPGAs, he decidido comprartirles unos cuantos códigos útiles que pueden utilizar en sus diseños a bloques. Este primer código es un Flip Flop tipo D con habilitador (Chip Enable), Reset (Clear) asíncrono y entrada de reloj.
Si se dan cuenta (y con mucha imaginación), el nombre de este Flip Flop se puede simplificar como FDCE. Recuerden esto, pues les será muy útil después. El circuito es este:



Como podrán ver, tiene una entrada "D", una salida "Q", un habilitador "CE", un reset asíncrono "CLR" y una entrada de reloj (el triangulito). Es bastante básico, pero muy útil.

Este es el código.



library IEEE;
use IEEE.STD_LOGIC_1164.all;  

entity FDCE is
generic (INIT :std_logic:='0'); -- El Flip Flop inicia en 0
port(CE, CLR, C, D: in std_logic;
Q: out std_logic);
end FDCE;

architecture FDCE of FDCE is
signal temp: std_logic :=INIT;
begin
process (CLR, C)
begin
if(CLR='1') then -- Clear asíncrono
temp <='0';
elsif(CE='1' and C' event and C='1') then -- Si hay una señal de reloj con flanco positivo, Q obtiene el valor de D
temp <=D;
end if;
end process;
Q<= temp;
end FDCE;


Aquí les dejo una captura de la simulación en Active-HDL para que vean que sí funciona


Ahora lo padre de este Flip Flop es que en prácticamente todos los FPGAs viene ya construido y es muy fácil hacerlo funcionar sin necesidad de escribir este código. Lo único que tienen que hacer es instanciarlo y ya. Ni siquiera lo tienen que declarar como componente. Aquí les va un ejemplo usando las librerías de Xilinx para un Spartan 3E.

library IEEE;
use IEEE.STD_LOGIC_1164.all; 

library UNISIM;
use UNISIM.vcomponents.all;

entity FDCE_Xilinx is
port(
CK, D, CE, CLR: in std_logic;
Q: out std_logic
);
end FDCE_Xilinx;


architecture FDCE_Xilinx of FDCE_Xilinx is
begin

FlipFlop: FDCE generic map('0') -- Comienza en 0
port map (C=>CK, D=>D, CE=>CE, CLR=>CLR, Q=>Q);

end FDCE_Xilinx;

Como podrán ver, estoy utilizando una librería adicional que es la UNISIM. Esta librería es de Xilinx y está hecha para instanciar un montón de cosas en sus FPGAs, entre ellas este FlipFlop llamado FDCE (como el nombre que convenientemente le puse al otro código!!). Existe una muy buena documentación sobre todo lo que trae esta librería. Les dejo el link de la info para el Spartan 3.

Los archivos del Active-HDL también los pueden bajar de mi cuenta de MediaFire. Les dejo el link.

My Github
https://github.com/DiegoRosales

Saludos!!