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, 24 de octubre de 2013

Dimmer controlado con aplausos (clap controlled dimmer)

Este es un proyecto que hice con unos compañeros para la materia de electrónica industrial. Consiste en realizar el control de la intensidad de la luz de un foco incandecente de 100W únicamente aplaudiendo. Les voy a compartir el reporte que le entregamos al profesor, pero como la materia es impartida en inglés, el reporte también está en inglés y me da mucha flojera traducirlo. Sólo les pondré lo básico. Lo que utilizamos fue un SCR (era requisito del proyecto) para controlar la cantidad de energía que es transferida al foco. El diagrama a bloques básico es este.


El chiste es sincronizar la señal de activación del SCR con el voltaje de la linea eléctrica. Esto es necesario ya que si no se hace, la señal que se le manda al SCR no coincidirá siempre con el semiciclo positivo de la línea, y si llegase a coincidir, ésta no siempre se mandaría en la misma parte del semiciclo positivo de la señal. Es decir, el foco estaría parpadeando todo el tiempo. Es por esto que fue necesario el detector de cruce por cero.

Hay un montón de circuitos en internet para realizar la detección del cruce por cero, ya que para muchas aplicaciones es muy importante (como ésta jaja), pero la mayoría de ellas requieren ya sea transistores (que a mi me cuesta mucho trabajo usarlos) o amplificadores operacionales con entrada bipolar (que no quería usar, ya que queríamos utilizar únicamente los 5V que tiene el Arduino) o cosas medio bizarras. Es por esto que nosotros "inventamos" nuestro propio sistema de detección utilizando las bondades del Arduino Duemilanove. Nuestra solución fue bajar el voltaje de la línea a algo razonable (3V aprox), rectificarlo con un rectificador de media onda (para no causar problemas con los voltajes negativos) y meterlo al ADC del Arduino con una resistencia limitadora de corriente. Entonces el Arduino analiza la señal y determina cuándo está en la parte positiva de la señal y cuándo en la parte negativa. Ojo que para esto, necesitamos muestrear la señal de la línea lo más rápido posible que es 5kHz (en realidad lo más rápido son 10kHz, pero ahorita les cuento qué pasa). A pesar de que el teorema de Nyquist nos dice que necesitamos una frecuencia de muestreo del doble de la frecuencia más grande de nuestra señal para evitar el aliasing (que en este caso sería 2x60=120Hz), necesitamos sobremuestrear la señal para saber con precisión y en todo momento en qué parte de la señal nos encontramos, para poder mandar una señal precisa al SCR que no ande variando. Esto implica que para depurar y optimizar el programa, necesitamos una velocidad de comunicación serial muy grande con la computadora (de 115200 baud/seg, en vez de los típicos 9600).

Para la detección del aplauso, íbamos a usar uno de esos micrófonos electret de condensador, pero resultaron ser basura para lo que queríamos. Por eso usamos un micrófono de computadora que nos sirvió de maravilla. Curiosamente estos micrófonos requieren un circuito de polarización y acoplamiento, mismo que obtuvimos de esta página http://www.hobby-hour.com/electronics/computer_microphone.php y pues nos sirvió a la primera. Por supuesto que de la salida del circuito lo mandamos a un buffer (que quién sabe si era necesario) y a un amplificador de ganancia como de 3, y de ahí a otro ADC del Arduino para que éste determine cuando hubo aplauso o no.

Finalmente, con la detección de los aplausos y la detección del cruce por cero de la línea, el Arduino genera un pulso cuya duración que va a depender del número de aplausos detectados hasta el momento y de la detección del cruce por cero (los detalles están en el reporte ;D). El caso es que este pulso va a un optoacoplador con salida SCR, que va a permitir que el segundo SCR (de potencia) se active con la misma señal de la línea, como es común para este tipo de circuitos.

El resultado final fue este


En la parte de arriba está el voltaje en el SCR y en la parte de abajo está la corriente en el foco. Nuestro circuito (que se ve un poco desastroso fue este)


Aquí les dejo el link del reporte y del código para el Arduino

Reporte


Código del Arduino


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!!