Vous êtes sur la page 1sur 10

MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 1

Implementación de Simon Says por Medio de


Máquinas de Estados en FPGA Spartan 3
Utilizando el Controlador VGA (Noviembre
2009)
Nataly Medina, Francisco J. Díaz, Alejandro Jiménez, CITEDI-IPN, Sistemas Digitales
controlar cómo los destellos de los electrones se dispersarán
Resumen—El siguiente documento presenta la implementación a través de la pantalla; actualmente en los monitores, los
de un juego clásico llamado en inglés Simon Says, mismo que electrones se dispersan mediante un patrón determinado, de
muestra en pantalla los colores del juego por medio del puerto izquierda a derecha, de arriba hacia abajo.
VGA. Por otra parte, se llevó a cabo el proyecto utilizando FPGA
de XILINX Spartan 3 mediante el uso del lenguaje VHDL para
La siguiente figura muestra el diagrama básico de un
su estructura.
monitor CRT y el patrón de escaneo de electrones en
Índice de Términos— FPGA, SPARTAN, VGA, VHDL pantalla.

I. INTRODUCCIÓN

S IMON Says es un juego electrónico creado en la década


de los 80’s por Milton Bradley, el cual, su objetivo
principal es recordar secuencias de colores y originalmente
sonidos que el computador presenta. Después de esperar, el
usuario debe ir introduciendo la secuencia mostrada en el
orden correcto, ayudándose de su memoria visual y sonora. Si
lo consigue, éste responderá con una secuencia más larga, y
así sucesivamente. Si falla, el usuario debe volver a empezar.
Los distintos niveles de dificultad van aumentando la
velocidad de la secuencia a repetir.

II.INTRODUCCIÓN AL CONTROLADOR VGA DE SPARTAN 3

Para implementar un controlador VGA, es necesario tomar


en cuenta las siguientes consideraciones técnicas:

a) Operación básica de un monitor CRT

Para operar, la parte denominada como electron gun


genera un destello de electrones y eventualmente se topan
contra una pantalla fosforescente. La luz es emitida en el
instante en el que los electrones despliegan un punto en la
pantalla fosforescente. La intensidad del destello del
electrón y el brillo del punto son determinados por el nivel
de voltaje de la señal externa de entrada de video, llamada
como mono, la cual es una señal analógica en el que su
Los osciladores internos del monitor y amplificadores
voltaje se encuentra entre 0 - 0.7V.
generan forma de ondas del tipo diente de sierra, para
controlar las dos bobinas de deflexión. Se tienen dos señales
externas de sincronización hsync y vsync, que controlan las
señales diente de sierra, estas señales son digitales.
Una bobina de deflexión vertical y una de deflexión
horizontal fuera del tubo, producen campos magnéticos para
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 2

La operación básica de un monitor CRT es similar, excepto sincronización y un circuito generador de pixeles, como se
en el que los destellos de electrones son proyectados como muestra a continuación:
puntos fosforescentes rojo, verde y azul (RGB) en pantalla.

Los tres puntos se combinan para formar un pixel; se puede


ajustar los niveles de voltaje de las tres señales de entrada de
video para obtener el color de pixel deseado.

b) Puerto VGA en la tarjeta Spartan 3

El puerto VGA tiene cinco señales activas, incluyendo las


señales de sincronización horizontal y vertical hsync y vsync,
más tres señales de video para los destellos rojo, verde, y azul
como se muestran a continuación, además de su
representación por cada terminal:

Las señales de hsync y vsync son decodificadas por


contadores internos, los cuales sus salidas son señales
pixel_x y pixel_y, que indican la posición relativa del
escaneo y esencialmente la ubicación del pixel actual. El
circuito vga_sync genera la señal de video_on para indicar
si se habilita o deshabilita el display.

El circuito generador de pixeles genera las señales de


video relacionadas con las señales RGB.

d) Sincronización del VGA

El circuito de sincronización de video genera la señal


Una señal de video es una señal analógica y el controlador hsync, la cual especifica el tiempo requerido para atravesar
de video utiliza un controlador analógico-digital. Si una señal (escanear) una fila, y la señal vsync que especifica el tiempo
de video es representada por una palabra con N-bits, puede ser requerido para recorrer la pantalla entera. El proyecto se ha
basado en un tamaño de pantalla de 640x480 pixeles a
convertida a 2 N niveles analógicos . Las tres señales de 25MHz, lo que significa que 25M pixeles son procesados en
video pueden generar 23 N combinaciones de colores, por lo un segundo.
que los posibles colores a generar se muestran en la siguiente
tabla: - Sincronización horizontal

Un periodo de la señal hsync contiene 800 pixeles y


pueden ser divididos en cuatro regiones:

Display: Región en donde los pixeles actualmente se


despliegan en pantalla. El tamaño de esta región es de 640
px.
Retrace: Región en el que los destellos de los electrones
regresan al lado izquierdo para volver a trazar la fila.
Margen Derecho e Izquierdo: La señal de video se
deshabilita en esta región, el tamaño de la misma es de
16px.

c) Controlador de Video

El controlador de video genera las señales de


sincronización y da salida a los datos de los pixeles de
manera seriada. El controlador VGA contiene un circuito de
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 3

green_color : out bit;


red_color : out bit;
yellow_color : out bit;
blue_color :out bit;

sec_sel1 : in bit;
sec_sel2 : in bit;

start : in bit);

end SimonSays;

clk50_in es el reloj principal, mantiene el flujo del


programa constante. Las definiciones para utilizar VGA están
relacionadas con las variables red_out hasta vs_out, definen el
RGB y las frecuencias de deflexión horizontal y vertical para
los destellos de los electrones.

mode es una variable externa que decide qué tan rápido corre
el programa; a su vez tenemos botones de entrada que permite
al usuario mantener el juego, los botones son green_in hasta
blue_in. Se tiene además un botón de inicio start.
- Sincronización Vertical
La arquitectura de modo comportamiento es como sigue:
Un periodo de la señal vsync contiene 525 pixeles y
architecture Behavioral of SimonSays is
pueden ser divididos en cuatro regiones:
signal clk25 : std_logic;
Display: Región en donde los pixeles actualmente se
signal hcounter : integer range 0 to
despliegan en pantalla. El tamaño de esta región es de 480 800;
px. signal vcounter : integer range 0 to
Retrace: Región en el que los destellos de los electrones 521;
regresan a la parte superior de la pantalla para volver a
trazar la columna. -- Color actual
Margen Inferior y Superior: La señal de video se signal color: std_logic_vector(2
deshabilita en esta región, el tamaño de la misma es de 10px downto 0);
y 33px respectivamente.
-- Tipo para las secuencias
type secuence is array(0 to 31) of
III. IMPLEMENTACIÓN EN VHDL character;

Definiendo la entidad, se compone de lo siguiente: -- Tipo de estados

entity SimonSays is type state_type is (s0, s1, s2, s3,


s4, s5, s6);
port (
clk50_in : in std_logic; -- Estados
red_out : out std_logic;
green_out : out std_logic; signal next_state, curr_state:
blue_out : out std_logic; state_type;
hs_out : out std_logic;
vs_out : out std_logic; -- Asignacion de los colores para VGA --
RGB
mode : in bit;
constant black : std_logic_vector(2
green_in : in bit; downto 0) := "000";
red_in : in bit; constant blue: std_logic_vector(2 downto
yellow_in : in bit; 0) := "001";
blue_in : in bit;
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 4

constant green: std_logic_vector(2 begin


downto 0) := "010"; if clk25'event and clk25='1' then
constant red: std_logic_vector(2 downto case curr_state is
0) := "100";
constant yellow: std_logic_vector(2
downto 0) := "110"; when s0 =>
constant white: std_logic_vector(2 -- Loop hasta "start" switch
downto 0) := "111"; if start = '1' then
level_cnt := 0;
signal sec0: secuence := global_cnt := 0;
"yrgybrygrygrbryrbyrybgrbrgbrgbgy"; aux_cnt := 0;
input := "000";
Se declara la señal de color, que es el color a desplegarse en curr_state <= s1;
el momento actual, las secuencias que son de un nuevo tipo, else
con un arreglo de treinta y dos espacios, definen la secuencia color <= white;
de caracteres del juego; además, se declaran las variables que curr_state <= s0;
definen los estados en el que se encuentra el juego, y los end if;
sucesivos estados. Se definen los colores de forma constante,
los mismos se asignan a la señal de control. global_cnt es una variable global encargada de contar
desde 0 hasta los 32 colores del arreglo de caracteres, misma
Por otra parte, la siguiente función requiere como parámetro que comienza a contar hasta un tope, llamado level_cnt, el
de entrada un char que identifica al color, y a su vez regresa el mismo indica hasta el nivel en el cual se encuentra el jugador.
color correspondiente:
input es la variable donde guarda las entradas de los
function char_to_color(c: character) botones, y curr_state almacena el estado de la máquina
return std_logic_vector is de estados.
begin
case c is Por cada ciclo de clk25 se recorre la máquina de estados.
when 'g' => return green;
when 'r' => return red; Esperando
START
when 'y' => return yellow; start := '1'

when 'b' => return blue; Despliega pantalla blanca y


luego pantalla negra
when others => return black; s5 s0
o
end case; ion
res cto
ad

n p corre
end char_to_color; Botón correcto pero
no se ha completado

Bo s in
e
START
start = '1'
secuencia

Los siguientes, son los procesos de los estados y el Comprobar


botón s4 Botón secuencia y s6 s1
proceso de visualización por medio del VGA: secuencia se ha
completado
Desplegando patrón de colores
global_cnt /= level_cnt

-- Generar clock de 25Mhz Botón presionado


input /= "000"
Se desplegó patrón completo
global_cnt >= level_cnt

process (clk50_in) s3 s2

Despliega pantalla blanca y


Esperando luego pantalla negra
begin lectura de botón
input := "000"

if clk50_in'event and clk50_in='1' then


clk25 <= not clk25;
end if; El estado s0 se encuentra dentro del ciclo hasta que el botón
end process; de inicio start tenga el valor de 1, de lo contrario, decimos
que curr_state es él mismo, y se manda a pantalla el
-- Clock de 1 Hz (modo normal) o 3 Hz color blanco por medio del VGA. Cuanto start se
(modo rapido) encuentra en 1, se inicializan todas las variables en 0, y
p1: process (clk25, curr_state) hacemos curr_state igual al estado 1(s1).

variable global_cnt: integer;


variable level_cnt: integer; when s1 =>
variable aux_cnt: integer;
variable cnt: integer; if mode = '0' then
variable fail: boolean := false; cnt := cnt + 1;
variable input: std_logic_vector(2 elsif mode = '1' then
downto 0); cnt := cnt + 3;
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 5

end if; color <= black;


aux_cnt := 0;
if cnt >= 25000000 then curr_state <= s3;
end if;
cnt := 0; end if;

color <= El estado s2 realiza la lógica para que la pantalla cambie de


char_to_color(sec0(global_cnt)); color blanco al negro, misma que sirve para tener condición
visual de que es turno del usuario para jugar.
if global_cnt >= level_cnt then
global_cnt := 0; El contador auxiliar permite saber si es la primera o
input := "000"; segunda vez que se iteró ese estado, y de esta manera
curr_state <= s2; despliega diferente color.
else
global_cnt := global_cnt + 1; when s3 =>
end if;
if green_in = '1' then
end if; input := green;
elsif red_in = '1' then
El estado s1 es el encargado de desplegar el patrón de input := red;
colores, el mismo cuenta con dos modos para desplegar: un elsif yellow_in = '1' then
color por segundo o tres colores por segundo, mismo que se input := yellow;
denota con la variable mode que a su vez es un botón de elsif blue_in = '1' then
entrada en la tarjeta Spartan; el modo decide si a la variable input := blue;
contador cnt se le suma +1 o +3. Cuando esta variable llega else
a 25000000 (que sería equivalente a un Segundo si la suma input := "000"; -- Nothing
corresponde a +1), se despliega el primer color por medio de end if;
la siguiente línea de código:
if input /= "000" then
color <= char_to_color(sec0(global_cnt)); curr_state <= s4;
end if;
en donde sec0 es la secuencia declarada anteriormente
correspondiente a los colores. El contador global se encarga de
realizar las iteraciones de ellos mismos, y la función El estado s3 es encargado de leer las entradas realizadas por
char_to_color regresa el color en forma de señal, y a su los botones. Este estado va a ciclar en sí mismo hasta que
vez se asigna al color por desplegar. alguno de los botones sea seleccionado, en caso contrario, si
ninguno de los botones es seleccionado se tendrá que
Cuando global_cnt >= level_cnt, se define que se input := "000";, en el momento que input /=
ha llegado al límite máximo correspondiente al nivel actual del "000", es decir, que la entrada sea diferente a cero, se
juego, lo cual significa que las variables contadoras se procede a seguir con el estado s4.
reinician en 0, ya que no deben desplegar más allá de los
when s4 =>
colores del arreglo.

when s2 => cnt := cnt + 1;


if cnt >= 10000000 then
if mode = '0' then cnt := 0;
cnt := cnt + 1;
elsif mode = '1' then if input =
cnt := cnt + 3; char_to_color(sec0(aux_cnt)) then
end if;
color <= input;
if cnt >= 6000000 then
if aux_cnt >= level_cnt then
cnt := 0; aux_cnt := 0;
level_cnt := level_cnt + 1;
if aux_cnt = 0 then
color <= white; curr_state <= s5;
aux_cnt := 1; elsif aux_cnt < level_cnt then
else aux_cnt := aux_cnt + 1;
curr_state <= s3;
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 6

elsif aux_cnt >= 31 then


curr_state <= s6; Otra de las consideraciones está relacionada con la
end if; condición del estado s4, si el contador auxiliar continúa siendo
else menor que el contador de nivel, se debe de seguir aumentando
curr_state <= s0; el contador para que así el jugador trate de recordar toda la
end if; secuencia.
end if;
Por otra parte, se considera la última condición relacionada
El estado s4 cuenta con un determinado retraso, esto evita el con la comparación del contador auxiliar, si es mayor a 31
rebote que se pueda presentar entre los botones, además de significa que el jugador ha logrado recordar los 32 colores y se
que es necesario un momento para que el usuario deje de manda al estado s6, el mismo genera un patrón de colores que
presionar el botón, sino se leen múltiples entradas. hace que se repita indefinidamente para expresar que el
jugador ha ganado el juego.
Cuando el retraso ha finalizado, el siguiente paso es
comprobar si el jugador ha seleccionado el botón correcto, when s6 => -- Jugador gana
para ello se hace la comparación entre la entrada y el contador
auxiliar, encargado de ciclar cada posición de la secuencia; si if mode = '0' then
el jugador se ha equivocado, el programa se reinicia al estado cnt := cnt + 1;
s0, lo cual significa que el usuario ha perdido el juego y deberá elsif mode = '1' then
comenzar de nuevo; en caso contrario, si ha acertado, se cnt := cnt + 3;
asigna el color de la entrada del usuario para que el mismo end if;
tenga retroalimentación visual.
if cnt >= 12000000 then
Para ello, se requiere comprobar algunas consideraciones,
primeramente verificando que el si el contador auxiliar ha cnt := 0;
llegado a ser equivalente al contador de nivel, significa que el
jugador ha terminado satisfactoriamente esta ronda de juego, if aux_cnt = 0 then
por lo que se incrementa en +1 el contador de nivel, es decir, color <= green;
se tiene un color más que ciclar en todo el programa; se aux_cnt := 1;
reinicia el contador auxiliar y se procede al estado siguiente s5. elsif aux_cnt = 1 then
color <= blue;
El estado s5 realiza la misma tarea que el estado s2, el aux_cnt := 2;
mismo tiene la tarea de realizar una transición para que el elsif aux_cnt = 2 then
usuario pueda presenciar un destello en pantalla, finalmente, color <= red;
este estado regresa al estado s1. aux_cnt := 3;
elsif aux_cnt = 3 then
when s5 => color <= yellow;
aux_cnt := 4;
if mode = '0' then elsif aux_cnt = 4 then
cnt := cnt + 1; color <= white;
elsif mode = '1' then aux_cnt := 5;
cnt := cnt + 3; elsif aux_cnt = 5 then
end if; color <= yellow;
aux_cnt := 6;
if cnt >= 6000000 then elsif aux_cnt = 6 then
color <= red;
cnt := 0; aux_cnt := 7;
elsif aux_cnt = 7 then
if aux_cnt = 0 then color <= blue;
color <= black; aux_cnt := 8;
aux_cnt := 1; elsif aux_cnt = 8 then
elsif aux_cnt = 1 then color <= green;
color <= white; aux_cnt := 9;
aux_cnt := 2; else
else color <= black;
color <= black; aux_cnt := 0;
aux_cnt := 0; curr_state <= s0;
curr_state <= s1; end if;
end if; end if;
end if; end case;
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 7

red_out <= black(2);


end if; green_out <= black(1);
end process; blue_out <= black(0);
end if;

El siguiente proceso denominado como p2 realiza la tarea green_color <= '0';


para desplegar en pantalla y hace uso del controlador de video red_color <= '0';
del FPGA. yellow_color <= '1';
blue_color <= '0';
p2: process (clk25, hcounter, vcounter)
elsif color = blue then
variable x: integer range 0 to 639; if (x > 640/2 and x < 640)and (y
variable y: integer range 0 to 479; > 480/2 and y < 480 )then
red_out <= color(2);
begin green_out <= color(1);
blue_out <= color(0);
x := hcounter - 144; else
y := vcounter - 31; red_out <= black(2);
green_out <= black(1);
if clk25'event and clk25 = '1' then blue_out <= black(0);
if color = green then end if;
if x < 640/2 and y < 480/2 then
red_out <= color(2); green_color <= '0';
green_out <= color(1); red_color <= '0';
blue_out <= color(0); yellow_color <= '0';
else blue_color <= '1';
red_out <= black(2); else
green_out <= black(1); if x < 640 and y < 480 then
blue_out <= black(0); red_out <= color(2);
end if; green_out <= color(1);
blue_out <= color(0);
green_color <= '1'; else
red_color <= '0'; red_out <= black(2);
yellow_color <= '0'; green_out <= black(1);
blue_color <= '0'; blue_out <= black(0);
end if;
elsif color = red then end if;
if (x > 640/2 and x < 640) and y
< 480/2 then Las variables hcounter y vcounter se encuentran
red_out <= color(2); relacionadas con la definición antes mencionada hsync y
green_out <= color(1); vsync respectivamente. (Ver inciso d)
blue_out <= color(0);
else El proceso permite la división de la pantalla en cuatro, para
red_out <= black(2); desplegar los colores del juego. Esto se hace haciendo las
green_out <= black(1); siguientes comparaciones, para verde, se ubica en la esquina
blue_out <= black(0); superior izquierda con la siguiente comparación: x < 640/2
end if; and y < 480/2, para los demás colores, se realizan las
comparaciones similares a esta.
green_color <= '0';
red_color <= '1'; Además de posicionar el color correspondiente, a su vez
yellow_color <= '0'; trae consigo mismo su representación digital en tres bits, la
blue_color <= '0'; cual representa el color en la posición adecuada, y a su vez se
asigna dicho bit a la señal de color correspondiente, tomando
elsif color = yellow then en cuenta que cada bit representa un color dentro del rango del
if x < 640/2 and (y > 480/2 and y RGB de tres bits.
< 480 )then
red_out <= color(2);
Cuando se hacen las siguientes asignaciones
green_out <= color(1); green_color <= '0';
blue_out <= color(0); red_color <= '1';
else yellow_color <= '0';
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 8

blue_color <= '0';

se asigna el valor digital para ser interpretados en los leds


correspondientes al botón de cada color en específico. end Behavioral;

Para obtener la sincronización tanto vertical como Los tiempos requeridos para la sincronización vertical son
horizontal con el VGA, tenemos lo siguiente: las siguientes:

if hcounter > 0 and hcounter < 97 then -- Pulse width: Tpw = 1600 cycles (2 lines) @ 25 MHz
hs_out <= '0'; -- Back porch: Tbp = 23200 cycles (29 lines)
else -- Display time: Tdisp = 38400 cycles (480 lines)
hs_out <= '1'; -- Front porch: Tfp = 8000 cycles (10 lines)
end if; -- Sync pulse time (total cycles) Ts = 416800 cycles (521
lines)
Los tiempos requeridos para ambas sincronizaciones se
muestran en la siguiente tabla (Ver p.24, Xilinx, Spartan-3
Starter Kit Board User Guide) IV. CONCLUSIONES

Simon Says es un juego que requiere de múltiples


retroalimentaciones sensoriales para estimular la memoria del
jugador. En nuestro caso fueron implementadas
retroalimentación visual y de posición.

Este juego sirvió como un buen ejercicio para el desarrollo de


habilidades en el lenguaje VHDL, debido a sus múltiples
consideraciones al momento de recrear su funcionamiento:
 lectura de señales de entrada
Siendo los
tiempos  implementación de arreglos en memoria
 manipulación de cadenas de caracteres
 manipulación de señales para el desarrollo de
controlador VGA
 implementación de maquinas de estados
requeridos
para la sincronización En nuestro caso, se decidió implementar la lógica básica por
horizontal los siguientes: medio de una maquina de estados finitos que se encargaba de
realizar cada una de los diferentes pasos en la dinámica del
-- Pulse width: Tpw = 96 cycles @ 25 MHz juego, ya que en la práctica resulto ser lo más adecuado
-- Back porch: Tbp = 48 cycles debido a la estructura del juego.
-- Display time: Tdisp = 640 cycles
-- Front porch: Tfp = 16 cycles Gracias a la implementación de este proyecto se han aprendido
-- Sync pulse time (total cycles) Ts = 800 cycles numerosas técnicas de implementación y desarrollo en el
lenguaje VHDL para FPGAs que será de gran ayuda en
if vcounter > 0 and vcounter < 3 then proyectos futuros.
vs_out <= '0';
else V. REFERENCIAS
vs_out <= '1'; [1] Pong. P. Chu, FPGA Prototyping by VHDL Examples. Cleveland State
end if; University.Wiley Insterscience 2008.
-- horizontal counts from 0 to 799
[2] http://cse.spsu.edu/clo/research/DigilentSpartan3/VGATest.htm
hcounter <= hcounter+1;
if hcounter = 800 then [3] Douglas L. Perry, VHDL.Programming by Example 4th Ed, McGraw.Hill.
vcounter <= vcounter+1;
hcounter <= 0; [4] VHDL Handbook, Hardi Electronics LAB
end if;
-- vertical counts from 0 to 519
if vcounter = 521 then
vcounter <= 0;
end if;
end if;
end process;
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 9

VI. APÉNDICE A
MÁQUINAS DE ESTADOS, VGA, SPARTAN 3, XILINX 10

VII. APÉNDICE B
Esperando
START
start := '1'

Despliega pantalla blanca y


luego pantalla negra
s5 s0
o
ad
sion to
pre rec
Botón correcto pero tón cor START
B o s in
no se ha completado e start = '1'
secuencia

Comprobar
botón s4 Botón secuencia y s6 s1
secuencia se ha Desplegando patrón de colores
completado global_cnt /= level_cnt

Se desplegó patrón completo


Botón presionado
global_cnt >= level_cnt
input /= "000"
s3 s2

Despliega pantalla blanca y


Esperando luego pantalla negra
lectura de botón
input := "000"

Vous aimerez peut-être aussi