TRABAJO DE FINAL DE CARRERA TÍTULO DEL TFC: Introducción al diseño de sistemas digitales reconfigurables en FPGA con VHDL y la tarjeta Spartan-3AN de Xilinx TITULACIÓN: Ingeniería Técnica de Telecomunicaciones, especialidad Sistemas de Telecomunicaciones. AUTOR: Sergio García López DIRECTOR: Francesc Josep Sánchez y Robert DATA: 29 de junio de 2010
141
Embed
TRABAJO DE FINAL DE CARRERA - digsys.upc.esdigsys.upc.es/ed/SED/projectes_aplicacio/TFC/S_Lopez/TextoTFC... · Control de Reloj o Digital Clock Manager ... Diagrama de estados Divisor
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
TRABAJO DE FINAL DE
CARRERA
TÍTULO DEL TFC: Introducción al diseño de sistemas digitales reconfigurables en FPGA
con VHDL y la tarjeta Spartan-3AN de Xilinx
TITULACIÓN: Ingeniería Técnica de Telecomunicaciones, especialidad Sistemas de
Telecomunicaciones.
AUTOR: Sergio García López
DIRECTOR: Francesc Josep Sánchez y Robert
DATA: 29 de junio de 2010
2
3
Resumen
Este trabajo pretende ser una guía para conocer el funcionamiento de la FPGA
Spartan-3AN de Xilinx y su software.
En el capítulo 2 se explicará cómo crear un proyecto simple, compilarlo,
simularlo y grabarlo en la placa para ver su funcionamiento de forma visual.
En el capítulo 3 se elaborará un doble contador síncrono de 4 bits. Uno de los
contadores vendrá gestionado por un divisor de frecuencia creado
manualmente y el otro por la herramienta de gestión de reloj que nos
proporciona el fabricante (Direct Clock Manager). Mediante estos contadores
analizaremos la eficiencia de los divisores de frecuencia utilizados, realizando
simulaciones a nivel de circuito (gate-level) del ModelSim para comparar
retardos de propagación.
La última parte de la explicación será la creación de una máquina de estados
para gobernar un conjunto de componentes compuestos. Los datos
provenientes de estos componentes serán convertidos al formato correcto
para ser visualizados mediante la pantalla LCD, que es un periférico de la
Spartan-3AN.
La explicación de esta última parte vendrá adscrita a la realización del
proyecto de este documento, que será la creación de un reloj en tiempo real
similar en prestaciones y funcionamiento al que se pueda llevar en la muñeca.
Titulo: Introducción al diseño de sistemas digitales reconfigurables en FPGA
con VHDL y la tarjeta Spartan-3AN de Xilinx
Autor: Sergio García López
Director: Francesc Josep Sánchez y Robert
Fecha: 29 Junio de 2010
4
Overview
This project is a guide to understand the operation process of the FPGA Spartan
3AN of Xilins and its programmation.
Chapter 2 explains how to create a simple project, compile, simulate it and record
it on the plate to see it working visually.
Chapter 3 will develop a dual 4-bit synchronous counter. The first counter is
controlled by a frequency divider created manually and the second is controlled by
a Xilinx management tool (Direct Clock Manager). Using these counters will
analyze the efficiency of crossovers used by circuit level simulations of ModelSim
to compare the propagation delays.
The last part of the explanation is the creation of a state machine to control
composite components. The information on these components will be converted
into the correct format for viewing through the LCD screen, the screen is a
peripheral of the Spartan-3AN.
The explanation for this latter part is the realization of the project, the project is the
creation of a real time clock similar in features and performance to a personal
wristwatch.
Title: Introduction to digital systems design with VHDL FPGA reconfigurable
En este proyecto se pretende hacer una pequeña guía para introducir al lector
en la programación de la Spartan-3AN. Se explicara el uso del software que
proporciona el fabricante para escribir, simular, compilar y grabar el código en
la placa.
La explicación intentará seguir el proceso lógico que haría un inexperto en la
materia, ofreciéndole paulatinamente las herramientas y las soluciones para ir
resolviendo los problemas que se le van planteando.
Se partirá de la base que el lector conoce las instrucciones básicas del
lenguaje VHDL, puesto que la finalidad del proyecto es que esta información
pueda ser útil para impartir clase en la escuela.
La estructura del trabajo empieza desde un código muy simple, que establece
una asignación directa entre entradas y salidas de la placa. A partir de este
primer diseño se hará una descripción del programa Project Navigator para su
familiarización. Se explicara como introducir un código de forma correcta en la
placa, como comprobar su funcionamiento mediante la simulación en
ModelSim, en sus diferente escalones de simulación, y finalmente como
asignar las entradas y salidas a ping físicos de la placa, a fin de grabar el
programa y ver su comportamiento de forma visual, siempre que esto sea
posible.
El segundo punto de interés es realizar un código dependiente de un reloj
interno o externo, puesto que la mayoría de tecnología que nos rodea está
plagada de procesos síncronos. En este nuevo diseño se implementara un
contador síncrono de 4 bits, el cual estará controlado por un divisor de
frecuencia que modificara la entrada de reloj de 50 MHz disponible en la placa,
a un valor predefinido por el usuario. Para el control del contador mediante este
componente, se explicara como declara el divisor y como definir entradas y
salidas del mismo dentro del archivo global contador. Este código permitirá la
declaración y el uso del reloj a la hora de simular diseños síncronos.
En este punto de la narración ya se dispondrán de las herramientas necesarias
para crear un componente, usar el reloj de la placa adecuando la frecuencia a
un valor predefinido y declarar un componente dentro de otro o en un archivo
global a fin de crear dependencias entre ellos.
Siguiendo la filosofía descrita, el siguiente paso a realizar es crear un bloque
capaz de hacer uso del reloj, compuesto por un conjunto de componentes que
establezca una relación de dependencia o sumisión unos de otros, a fin de ser
capaces de transmitir una cierta información a un periférico de la placa.
13
Para lograr este propósito, se diseñara un reloj en tiempo real igual al que se
puede llevar en la muñeca, en el cual se podrá elegir su método de
funcionamiento y puesta en hora.
Este dispositivo será la aplicación, propiamente dicho, del proyecto y dará pie a
la introducción de la última parte que se desea explicar en este documento. El
reloj estará controlado por una maquina de estados, la cual será descrita
cuidadosamente.
Finalmente los datos podrán ser visualizados mediante la pantalla LCD de la
placa. Esto evoca al último bloque del condigo que será la incorporación de un
periférico al diseño.
Al parecer del autor del proyecto, esto es todo lo necesario para programar la
FPGA, y pese a que los bloques y los periféricos pueden ser tan complicados
como la imaginación de su creador, deja al lector con las instrucciones básicas
para este nivel de programación, situándolo así en la antesala del siguiente
nivel, que es la compilación del código utilizando el micro controlador.
14
2. Sistemas combinacionales.
Son aquellos códigos en que las salidas dependen exclusivamente de las
entradas y su respuesta es constante y deducible matemáticamente.
Circuito
Combinacional.
X( n-1 ...0 ) Y( m-1 ...0 )
Figura 1 Circuito combinacional.
2.1. Flujo de diseño.
La metodología de trabajo a seguir para el diseño de cualquier proyecto es la
mostrada en la figura siguiente ( Figura 2 Flujo de diseño. ) y se ha de seguir
escrupulosamente para realizar cualquier recurso.
Especificaciones
Crear RTL
Y Código de la aplicación
Simulaciones funcionales
Simulación a nivel de
puertas lógicas.
Configuración de pines para
una FPGA concreta.
Grabar el codigo en la
FPGA
Prototipo de la aplicación.
No correcto.
Flu
jo d
e d
ise
ño
.
Síntesis del código
Correcto
Correcto
Correcto
No correcto.
No correcto.
Correcto.
Correcto.
Correcto.
Figura 2 Flujo de diseño.
15
2.2. Uso de los Leeds y los pulsadores.
Se desea establecer una asignación entre los 4 selectores de entrada y 4 leeds
de salida.
2.2.1. RTL y Código de la aplicación.
El código estará escrito en VHDL y el esquema de conexiones mostrara el
encapsulado del componente.
2.2.1.1. RTL
4 Entradas
4 Salidas
LDR[0]SW[0]
SW[1]
SW[2]
SW[3]
LDR[1]
LDR[2]
LDR[3]
Figura 3 RTL 4 Entradas 4 Salidas.
2.2.1.2. Código de la aplicación.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity Prub1 is
Port ( SW : in STD_LOGIC_VECTOR (3 downto 0);
LDR : out STD_LOGIC_VECTOR (3 downto 0));
end Prub1;
architecture Behavioral of Prub1 is
begin
LDR <= NOT(SW);
end Behavioral;
Código 1 Prub1.
16
2.2.2. Simulación del código.
La simulación del código se realizara mediante ModelSim.
El programa muestra el aspecto siguiente:
Figura 4 Ventana principal ModelSim.
-En la ventada señalada con el número 1 aparecen todas las bibliotecas
utilizadas por el programa y el código seleccionado para su simulación.
-La siguiente ventana contiene las señales activas para simular, en esta
ventana se pueden añadir o eliminar las señales que se desee mostrar.
-En la tercera muestra el seguimiento grafico de la simulación.
-Finalmente en la última ventana señalada con el numero 4, se podrán ver
todas las incidencias en la simulación y acceder al los archivos .DO que
contendrán las directrices de la simulación, siempre que no se implemente el
TestBench desde el mismo programa de diseño.
17
2.2.2.1. Archivo DO para simulaciones en ModelSim.
Dentro del archivo .DO se definen las señales que se utilizarán para las
simulaciones, el periodo de reloj y el paso a paso en la simulación. Este último
vendrá dividido temporalmente según los tiempos de espera definidos por el
usuario y las condiciones para cada espera.
restart
add wave SW
add wave LDR
force SW 1011
run 100
force SW 0011
run 100
force SW 1100
run 100
force SW 1001
run 100
force SW 0101
run 100
run 200
Código 2 Archivo .DO.
Se reinician los registros.
Se definen las variables a utilizar.
Add wave” nombre señal”.
Se fuerza un valor de entrada y se espera un tiempo prudencial de ejecución
para observar los resultados.
Forcé “nombre entrada” “valor deseado”
Run “Tiempo deseado”
El archivo .DO se debe introducir en la raíz de la carpeta que contenga el código a simular. La forma de ejecutar el archivo es desde la ventana señalada con el número 4, dentro de la presentación de la página principal del ModelSim.
En esta ventana ( Figura 4 Ventana principal ModelSim. ) se puede introducir texto. La forma de introducir el comando de ejecución es la siguiente:
Do “nombre_archivo”.do
Una vez hecho lo anterior aparecerá una tabla de opciones, tras restaurar, en la ventana de representación grafica aparecerá la simulación efectuada.
18
Figura 5 1era Simulación paso 4.
La simulación funcional es correcta y como se puede observar en el código y en las especificaciones de los leeds, éstos son activos a nivel bajo. Es por esa razón que en el código las salidas están negadas, y en la simulación las señales va a la inversa entradas respecto salidas.
19
2.3. Spartan-3AN Non-Volatile FPGA Starter Kit.
La placa en la cual se implementarán los diseños es la Spartan-3AN de Xilinx.
Figura 6 Spartan-3AN.
La FPGA tiene prácticamente la misma conectividad que una placa base de un ordenador convencional a diferencia, claro, que es totalmente programable.
2.3.1. Arquitectura interna.
La arquitectura de la FPGA Spartan-3AN es compatible con el de la FPGA
Spartan-3ª. La arquitectura se compone de cinco elementos fundamentales,
funcionales y programables.
2.3.1.1. Lógica de bloques configurable o Configurable Logic Blocks
(CLBs) .
Contiene tablas de consulta flexibles o Look-Up Tables (LUTs) que
implementan la lógica de los circuitos y configuran la estructura básica de los
flip-flops internos.
20
2.3.1.2. Entradas y salidas de los bloques o Input/Output Blocks
(IOBs).
Controla el flujo de datos entre los pines y la lógica interna del dispositivo,
gestionan la prioridad de señales y estados de los registros
2.3.1.3. RAM.
Este bloque es el encargado del almacenamiento de datos del circuito, en
forma de bloques de dos puertos de 18K-bits cada uno de ellos.
2.3.1.4. Multiplicador de bloques.
Multiplica dos números binarios de 18 bits como sumas de ellos para calcular el
producto.
2.3.1.5. Control de Reloj o Digital Clock Manager (DCM).
Ofrece una auto calibración del reloj de entrada y diferentes operaciones sobre
el mismo, como pueden ser multiplicaciones y divisiones de frecuencia o
cambios de fase.
Figura 7 Arquitectura interna Spartan-3AN ( Spartan-3AN FPGA Family Data Sheet).
21
Estos elementos están organizados como se muestra en la Figura 7
Arquitectura interna Spartan-3AN ( Spartan-3AN FPGA Family Data Sheet). en
una doble disposición de salidas que rodea el conjunto.
Cada dispositivo tiene dos columnas de RAM a excepción XC3S50AN que
dispone únicamente de una. Los bloques de memoria están asociados
mediante un multiplicador dedicado.
La Spartan-3AN dispone de una amplia red de conexiones en forma matricial
para conectar cada uno de los dispositivos, con la finalidad de ofrecer una
buena calidad de señales internas.
2.4. ISE Project Navigator.
Siguiendo la metodología de trabajo, ahora es el momento de realizar la
asignación de pines, y es en este punto donde se explicará el funcionamiento
de la herramienta utilizada para llevar esto a cavo.
Ilustración 1 Marca corporativa.
El programa que se utilizará para programar es ISE Project Navigator de Xilinx
que proporciona la pagina web (http://www.xilinx.com/) en su versión ISE
WebPACK™ edición.
La ventana principal muestra el aspecto siguiente:
La ventana es similar a la que puede proporcionar cualquier programa de
Windows, en su parte superior izquierda aparece el menú de opciones y
accesos directos a diferentes herramientas de diseño.
En la parte media de la ventana a la izquierda presenta los archivos que están
cargados en el diseño, y en la parte derecha actualmente está cargado Design
Summary, que muestra un resumen detallado de las configuraciones del
diseño.
Por último, en la parte inferior presenta un gran espacio en blanco que está
destinado a mostrar los posibles errores de programación es sus diferentes
etapas, ya sea de compilación, en sus diferentes niveles, como de simulación.
2.4.1. Creación de un proyecto.
El proceso a seguir a la hora de crear nuestro proyecto es File->New Project y
aparecerá la ventana siguiente:
23
Figura 9 Paso 1 Creación proyecto.
En esta ventana se definirá el nombre del proyecto y la localización, en cuanto
a la localización es recomendable no utilizar direcciones muy largas para evitar
errores a la hora de cargar ficheros. El nombre podrá ser modificado
posteriormente.
En el siguiente paso se prestara atención a 3 puntos, pero hay que tener en
cuenta que es necesario conocer en qué placa se implementara el código y las
características de la misma a la hora de rellenar correctamente la totalidad de
los campos de este formulario.
24
Figura 10 Paso 2 Creación proyecto.
En el primer punto marcado en rojo en la (Figura 10 Paso 2 Creación proyecto.)
corresponde al los lenguajes de programación que soporta la placa que se ha
descrito en el resto del formulario.
El segundo punto muestra los diferentes programas de simulación que se
pueden utilizar a la hora de comprobar el correcto funcionamiento del proyecto.
Se seleccionara Modelsim-SE VHDL puesto que es el recurso de simulación
utilizado por la escuela en asignaturas como ED (Electrónica digital) o SED
(Sistemas electrónicos digitales).
Por último el lenguaje utilizado para describir el funcionamiento del proyecto
será VHDL.
25
Figura 11 Paso 3 Creación proyecto.
En el tercer paso se agruparan los dos siguientes saltos en la creación, puesto
que estas dos ventanas son muy similares. ( Figura 11 Paso 3 Creación
proyecto. )
La primera está destinada a añadir un nuevo fichero al proyecto y definir si se
desea las entradas y salidas desde un principio. Entre las opciones de fichero a
elegir se utilizara de momento VHDL Module y progresivamente a lo largo de la
explicación se verán el resto.
La ventana de la derecha sirve para añadir al proyecto un fichero ya existente
en el ordenador y ser implementado junto al diseño.
El último paso es un resumen de lo seleccionado anteriormente y da pie a
comenzar a redactar el código.
Figura 12 Paso 4 Creación proyecto.
26
2.4.2. Escritura del código.
Se creará un proyecto nuevo, con nombre “Prub1” y a la hora de añadir un
fichero se nombrara de igual modo y no se definirán por el momento entradas
ni salidas.
Si se ha realizado todo correctamente a la izquierda de la ventana principal
aparecerá lo siguiente:
Figura 13 1er Código paso 1.
En la parte derecha aparecerá una ventana de texto que contendrá las
directivas básicas de cualquier diseño, es en esta ventana en donde se
introducirá el primer código.
En este primer código, como se ha comentado se hace una asignación directa entre los selectores de entrada de la placa (SW) y los Leeds situados encima (LDR).
Como se puede ver este primer código está compuesto de la declaración del componente con sus entradas y la arquitectura del mismo, en la cual solo consta la asignación directa, que sería comparable a unir físicamente los interruptores con los Leeds mediante un cable.
27
El siguiente paso es comprobar que el código compila correctamente, para esto se utilizara el menú desplegable situado en la ventana inferior a la que contiene la declaración de archivos ( Figura 14 1er Código paso 2. ).
Figura 14 1er Código paso 2.
Después de hacer clic en Run, si todo ha sido correcto en la ventana de texto
de la parte inferior de la ventana aparecerá el mensaje siguiente:
Process "Synthesis" completed successfully
Si se despliega la pestaña sintetizar, emergerán más opciones, de la cuales
cabe destacar por ahora View RTL, que muestra el esquema del componente.
Figura 15 1er Código paso 3.
El siguiente paso para grabar el diseño es asignar las entradas y salidas con
los pines correspondientes de la placa. La página Web proporciona para
descargar un archivo .UCF, que contiene toda la información de pines de la
Spartan-3AN, nombrando cada pin de cada componente con la nomenclatura
que viene inscrita físicamente en la placa.
28
2.4.3. Asignación de pines.
El programa nos permite introducir los datos de forma manual en el archivo
.UCF de configuración, o de forma automática mediante una aplicación que
será descrita posteriormente.
2.4.3.1. Editar el archivo .UCF de forma manual.
El modelo de archivo UCF que contiene toda la información de la localización
Otro método para introducir las asignaciones de pines, es mediante la
herramienta PlanAhead que nos proporciona Xilinx.
Figura 16 1er Código paso 4.
Esta aplicación permite introducir uno a uno los números de los puertos
necesarios.
Figura 17 1er Código paso 5.
30
En el formulario número 1 se puede ver si el puerto es de entrada o salida, el
nombre y la situación. Es en este último campo donde se introducirá el número
del puerto a utilizar siguiendo el archivo .UCF que proporciona el fabricante.
El formulario numero 2 presenta una lista de todas las entradas y salida del
código. Para poder modificar alguna de ellas mediante el formulario número 1,
ésta tendrá que estar seleccionada.
Cuando se termine de rellenar todos los campos se tendrá que grabar el
proceso desde la misma aplicación, cerrar la ventana y volver a sintetizar el
código.
Un método para comprobar que la asignación ha sido correcta, es mediante
Design Summary, que como se ha comentado al principio, da un amplio
informe de todos los eventos del proyecto.
Figura 18 1er Código paso 6.
A partir de este punto ya se dispone de todo lo necesario para introducir el
código en la placa y hacerlo funcionar. Para esto se ejecutará toda la
secuencia de sintetizado y compilación.
31
Figura 19 1er Código paso 7.
Si todo ha sido correcto la ventana de notificaciones mostrara el mensaje
siguiente:
Generating Report ...
Number of warnings: 0
Total time: 2 secs
Process "Generate Post-Place & Route Static Timing" completed successfully
Started : "Generate Programming File".
Process "Generate Programming File" completed successfully
Código 5 Información sucesos.
32
2.5. Síntesis y Simulación temporal de circuito.
Cuando se ha definido el proyecto se ha elegido un programa de simulación,
este queda totalmente integrado en Xilinx, de modo que al pasar de uno a otro
se envía toda la configuración. Esto supone que a la hora de hacer
simulaciones temporales el programa de simulación tiene en cuenta los
retardos propios de cada placa utilizada en el diseño.
A la hora de realizar la simulación es muy simple. El primer paso es pasar del
método implementación a simulación, esto se hace seleccionando la casilla
situada encima de la ventana que contiene los archivos del programa.
Figura 20 Simulación paso 1
Desde la nueva ventana que aparece, se ha de tener en cuenta básicamente
tres cosas a la hora de simular.
Figura 21 Simulación paso 2.
33
El primer punto es nivel de simulaciones que se quiere realizar, de los cuales
se utilizaran 2.
-Behavioral es el nivel de simulación más primario, sólo tiene en cuenta la
estructura del código y su funcionamiento teórico. Generalmente si el código
compila correctamente podrá ser simulado. Este método sirve para comprobar
que el diseño cumple las especificaciones iniciales previstas.
-Post-Route es el paso siguiente al método anterior. En este método sí que se
tiene en cuenta los retardos entre puertas. Es en este punto donde no sólo es
importante que el código funcione a nivel teórico, puesto que si el sistema no
es capaz de conmutar con suficiente velocidad no será capaz de realizar las
operaciones programadas.
El segundo punto de la simulación, es elegir que código se desea simular. En
este primer diseño no es muy relevante porque sólo aparece un archivo que
hace las funciones de Main y proceso de datos o funciones conjuntamente,
pero a medida que aumente la complejidad en el diseño, se dará cuenta que es
mucho más útil simular un bloque por separado a la hora de extraer
conclusiones.
Por último, el tercer punto marcado en rojo en la Figura 21 Simulación paso 2.,
muestra el programa que actualmente esta seleccionado y junto a él, el método
de simulación elegido. Haciendo doble clic sobre esta última opción se accede
al programa de simulación.
ModelSim Simulator es el programa por defecto que utiliza la EPSC (Escuela
Politécnica Superior de Castelldefels) para simular, la versión Xilinx de este
programa se puede descargar en el apartado de soporte de la página Web.
Esta simulación se realizara mediante TestBench, que es una herramienta
mucho más cómoda e inmediata de realizar simulaciones.
2.5.1. TestBench para simulaciones en ModelSim.
Este archivo da la posibilidad de integrar aun más la simulación dentro del Project Navigator, ya que éste aparecerá dentro de la lista de archivos del código, siendo uno más a programar y modificar al gusto. Como contendrá la información que anteriormente se definía en el archivo .DO, cuando se ejecute ModelSim automáticamente aparecerá la simulación programada, agilizando considerablemente el proceso.
34
El proceso de creación del archivo TestBench es el siguiente:
Figura 22 Simulación paso 3.
El primer paso es añadir un nuevo archivo al proyecto (1), acto seguido se abrirá una ventana con los archivos disponibles para seleccionar (2), de los cuales interesa VHDL Test Bench. Por último sólo queda nombrar el archivo (3) y pulsar siguiente hasta cerrar la ventana actual.
Ahora aparece el archivo Test Bench dentro de la lista, siempre que la casilla de simulación esta seleccionada.
Automáticamente se abrirá en la ventana de código. Dentro del modo de simulación este hace las funciones de archivo principal gobernando sobre los demás. Como se puede ver el propio programa te guía en la utilización del código con comentarios en cada punto relevante del mismo. Otro aspecto interesante es que en la creación del código viene implementado un clock automáticamente. Gracias a este factor, en códigos dependientes de un reloj externo se podrá hacer funcionar.
Por la simplicidad de este primer diseño, las modificaciones del código modelo de origen serán pocas, pero servirán para entender cómo funciona este archivo de simulación.
Tomando como modelo el archivo .DO de apartados anteriores y teniendo en cuenta que ahora éste ya está identificado como componente, y no hará falta inicializar las variables, se introducirán los estados y las separaciones temporales únicamente en donde nos indica el código mediante un comentario de ayuda (insert stimulus here).
35
2.5.1.1. Código TestBench
El código queda de la forma siguiente:
-Primero es necesario comentar la parte del clock para que no de errores y porque no se hará uso de ella.
-- constant <clock>_period := 10 ns;
-- <clock>_process :process
-- begin
-- <clock> <= '0';
-- wait for <clock>_period/2;
-- <clock> <= '1';
-- wait for <clock>_period/2;
-- end process;
Código 6 Código Reloj Test Bench.
-Se ha de añadir la información del archivo .DO con las modificaciones adecuadas al VHDL.
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ms.
SW<="1111";
wait for 100 ns;
--wait for <clock>_period*10;
-- insert stimulus here
SW<="1011";
wait for 100 ns;
SW<="0011";
wait for 100 ns;
SW<="1100";
wait for 100 ns;
SW<="1001";
wait for 100 ns;
SW<="0101";
wait for 100 ns;
wait for 200 ns;
wait;
end process;
Código 7 Pautas de la simulación.
Tras realizar estas modificaciones se puede ejecutar la simulación y ver como ésta, si no se ha producido ningún error, aparece automáticamente.
Para ejecutar la simulación se ha de hacer doble clic sobre el nombre del
simulador seleccionado.
36
2.5.2. Simulación temporal.
Figura 23 Simulación paso 4.
Si se realiza el proceso usando la opción de Post-Route para simular el código, se verá en la representación grafica, haciendo el zoom necesario, los retardos entre las señales.
Recordar que si no se ven las señales adecuadamente, un error muy común es
poner una base de tiempo muy pequeña a simular o que las opciones de zoom
de la ventana no sean las correctas.
Figura 24 Simulación paso 5.
Más adelante cuando se simulen bloques mas grandes se verá como el retardo es una constante que va de entre 6 ns a 8ns, por esa razón es un parámetro a tener en cuenta a la hora de exigir cierta velocidad de computo a un proceso.
37
2.6. Grabado del código.
El siguiente paso es grabar el código en la memoria interna de la placa, para su
posterior ejecución. Esto se realiza mediante la aplicación ISE iMPACT, que se
nos abrirá automáticamente al ejecutar el paso siguiente al seleccionado
anteriormente, Configure Target Device.
Figura 25 ISE iMPACT
2.6.1. Alimentación y comunicación con la placa.
En esta aplicación el primer paso es identificar nuestra placa, para ello ésta
tendrá que estar conectada al PC mediante el cable USB, enchufada a la
corriente y encendida.
Figura 26 Conexiones.
38
2.6.2. Identificación de la Spartan-3AN.
Figura 27 Identificación Spartan-3AN.
El siguiente paso es hacer que el programa identifique la placa y establezca
comunicación con ella. Para conseguir este propósito se utilizara la opción de
detección automática.
2.6.3. Introducir un código.
Cuando la placa sea identificada, automáticamente se abrirán los formularios
para introducir los programas a ejecutar, y acto seguido una ventana que
contendrá los parámetros de configuración. La configuración utilizada será la
que viene por defecto y los programas tendrán que ser localizados en la raíz de
la carpeta donde se halla guardado el código en su creación.
39
Figura 28 Introducción del programa a ejecutar.
2.6.4. Configuración de los Jumpers a la hora de grabar un
código en la memoria de la Spartan-3AN.
La Spartan-3AN dispone de diferentes métodos para grabar un código en la
placa. El utilizado en este tutorial permite introducir un código y ser guardado
de forma sencilla y sin establecer ninguna configuración adicional, para que
éste permanezca de forma permanente.
La configuración de los Jumpers es la siguiente:
Figura 29 Configuraciones posibles en los Jumpers.
40
Figura 30 Configuración Jumpers.
En esta configuración, el método de entrada a la memoria es Master Internal
SPI (Serial Peripheral Interface). Quiere decir que un periférico de memorial
residente en la placa establece las pautas y el contenido de carga para el
programa a ejecutar. Cuando se grabe el programa en este periférico el
proceso será el inverso que el de la carga del código en la FPGA.
Es en este periférico externo donde permanece el código cuando se elige la
opción de programa y grabar la memoria flash de la FPGA.
2.6.5. Grabar el código.
El código se puede grabar para que quede de forma permanente o para que se
pierda una vez se apague o se pierda la alimentación del sistema.
2.6.5.1. Programar la memoria Flash y cargar la FPGA.
Clicando con el botón secundario sobre el componente al cual se desea
insertar el código, aparece un menú de opciones.
En este apartado se seleccionara la primera opción que hará permanecer el
código en la placa, sobre reinicios y pérdidas de energía, en el periférico de
memoria descrito anteriormente.
Figura 32 Configuración permanente.
42
2.6.5.2. Programas FPGA únicamente.
Dentro de este menú, en este caso interesa la segunda opción.
Figura 33 Configuración eventual.
De este modo se podrán hacer escrituras más rápidas de código para pruebas
de funcionamiento puntuales.
43
2.7. Comprobación del funcionamiento.
Tras introducir el código se podrá comprobar de forma visual el
comportamiento del mismo.
La asignación de las salidas viene regida por la condición -> LDR <= NOT(SW);
Esta condición evoca el funcionamiento siguiente, ya que los Leeds son activos
a nivel bajo.
Figura 34 Entrada "0110" Salida "1001"
Figura 35 Entrada "0010" Salida "1101"
El comportamiento es correcto y satisfactorio.
44
3. Sistemas secuenciales.
Una vez comprendida la metodología para llevar un código desde el papel a la placa, el siguiente paso lógico es realizar un código dependiente de un reloj interno, puesto que la mayoría de sistemas electrónicos que nos rodean funcionan de este modo.
“A diferencia de los sistemas combinacionales, en los sistemas secuenciales,
los valores de las salidas, en un momento dado, no dependen exclusivamente
de los valores de las entradas en dicho momento, sino también dependen del
estado anterior o estado interno.
La mayoría de los sistemas secuenciales están gobernados por señales de
reloj. A éstos se los denomina "síncronos" o "sincrónicos", a diferencia de los
"asíncronos" o "asincrónicos" que son aquellos que no son controlados por
señales de reloj.”
Wikipedia.
Sistema
combinacional.
Sistema de
memoria.
ZX
Y
Figura 36 Sistemas secuenciales.
3.1. Metodología para dividir la frecuencia de entrada y
gestionar un contador binario síncrono de Modulo 11.
Se diseñara un doble contador de 4 bits, el cual incrementara su valor mediante un pulso a una determinada frecuencia proporcionada por un divisor de frecuencia, que será un componente de menor rango o sumiso al código principal.
La primera salida vendrá gestionada por un divisor de frecuencia creado
manualmente, y la segunda salida por el gestor de reloj interno (Digital Clock
La Spartan tiene un ping de clock a 50 MHz, que mediante el archivo UCF se puede identificar en la placa y el en pinout.
NET "CLK_50M" LOC = "E12"|IOSTANDARD=LVCMOS33|PERIOD = 20.000 ;
OFFSET = IN 10.000 VALID 20.000 BEFORE "CLK_50M" ;
OFFSET = OUT 20.000 AFTER "CLK_50M" ;
Código 8 Descripción Clock en .UCF.
3.1.1.1. Especificaciones.
Se pretende obtener una salida de reloj a 1 MHz mediante este componente de la forma más efectiva y sencilla posible.
Para obtener la frecuencia deseada a partir de los 50MHz de entrada, se realizará un divisor de frecuencia. Cada vez que el contador general llegue a un valor esperado, cumpliendo la condición predefinida, nos proporcionará una salida de reloj a la frecuencia deseada.
Condición: Cuando sea 5 reiniciamos el contador principal (50MHz) y aumentamos el contador secundario, de este modo se divide la frecuencia inicial por 5, obteniendo así una salida a 10MHz.
46
Para realizar el divisor de frecuencias se utilizará el modelo de máquina de estados que se imparte en la escuela.
Figura 38 Esquema maquina de estados.
En cada iteración se decide la configuración del estado siguiente, y el estado presente pasa a ser el estado futuro de forma síncrona con cada golpe de reloj. En caso de que no se produzca un cambio de estado, la metodología es no actualizar el estado futuro, para que no sea modificado cuando se produzca un el evento de reloj.
A partir de este punto, todos los códigos que contengan estados de funcionamiento seguirán este modelo.
3.1.1.2. Esquema divisor de frecuencia.
El componente tendrá 3 entradas y una salida.
Entradas CLK: Es la entrada de 50MHz disponible en la placa.
CD: Reiniciara el contador cuando se active.
CE: Habilitara el contador para que pueda incrementar en cada iteración.
Salida TC10: Esta salida proporcionara la nueva frecuencia resultante del divisor.
47
freq_divider_10
CD
CE
CLK
TC_10
Figura 39 Componente divisor de frecuencia.
3.1.1.3. Diagrama de estados Divisor de frecuencia.
Vistas las condiciones anteriores se pensará en un diagrama de estado que
proporcione dicho funcionamiento.
0
TC10 = ‘0’
4
TC10 = ‘0’
(Nº - 1)
TC10 = ‘1’
1
TC10 = ‘0’
3
TC10 = ‘0’
2
TC10 = ‘0’
Nota:
N es el valor por el cual se quiere
dividir la frecuencia de entrada.
While CE = „0‟
TC10 = ‘1’
While CE = „0‟
While CE = „0‟ While CE = „0‟
While CE = „0‟
While CE = „0‟
CE = „1‟
CE = „1‟
CE = „1‟
CE = „1‟
CE = „1‟CE = „1‟
Figura 40 Diagrama de Estados divisor de frecuencia.
48
3.1.1.4. Código divisor de frecuencia.
Se necesitan dos señales de longitud igual al número de bits necesario para representar el número por el cual queremos dividir la frecuencia de entrada.
SIGNAL present_state, future_state:std_logic_vector(6 DOWNTO 0);
Código 9 Vectores estados Divisor de frecuencia.
La frecuencia de entrada estará dividida por 50, y teniendo en cuenta que el contador empieza a contar en 0, el valor correcto será 49 y su equivalente binario es 110001, que tiene una longitud de 6 bits. Este valor de división ha sido elegido para facilitar la posterior simulación, si se desea implementar en la placa y comprobar visualmente que el divisor funciona correctamente, este tendrá que ser mucho mayor.
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY freq_div_10 IS
PORT(CD,CLK,CE : IN std_logic;
TC10 : OUT std_logic
);
END freq_div_10;
ARCHITECTURE FSM_style OF freq_div_10 IS
SIGNAL present_state, future_state:std_logic_vector(5 DOWNTO 0);
--signal senal : std_logic;
--signal control : std_logic_vector(1 DOWNTO 0);
BEGIN
-- State register, normally in FF-D
state_register: PROCESS (CD,CLK)
BEGIN
IF (CD='1') THEN
present_state <= "000000";
ELSIF (CLK='1' AND CLK'event) THEN
present_state <= future_state;
END IF;
END PROCESS state_register;
-- combinational logic for determining the next state
CS1: PROCESS (present_state,CE)
BEGIN
IF CE = '1' THEN
IF (present_state = "110001") THEN -- 0x18 == 0d24
future_state <= "000000";
ELSE
future_state <= present_state + 1;
END IF;
ELSE
future_state <= present_state;
END IF;
END PROCESS CS1;
TC10 <= '1' WHEN (present_state = "110001" AND CE = '1') ELSE '0';
END FSM_style ;
Código 10 Código Divisor de frecuencia.
49
Se puede ver como en cada evento de reloj se actualiza el estado y el funcionamiento de la entrada CD anteriormente descrita.
También el comportamiento de la entrada CE, que es la que habilita el contador, y como esta implementada la condición que fuerza la puesta a 0 del contador cuando llega al valor esperado. Este diseño forma parte de la teoría de la escuela, se puede encontrar dentro de la página web y su funcionamiento es sencillo y efectivo.
Por último y no menos importante, la salida TC10 y su puesta a uno en el
momento deseado.
3.1.1.5. Simulación divisor de frecuencia.
La simulación se realizará mediante TestBench. En este diseño si será necesario editar el reloj que nos genera el programa. El primer paso es comprobar que la nomenclatura con la que ha implementado el reloj es la misma que se ha utilizado.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
ENTITY diezMHz IS
END diezMHz;
ARCHITECTURE behavior OF diezMHz IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT freq_div_10
PORT(
CD : IN std_logic;
CLK : IN std_logic;
CE : IN std_logic;
TC10 : OUT std_logic
);
END COMPONENT;
--Inputs
signal CD : std_logic := '0';
signal CLK : std_logic := '0';
signal CE : std_logic := '0';
--Outputs
signal TC10 : std_logic;
-- Clock period definitions
constant CLK_period : time := 1 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: freq_div_10 PORT MAP (
CD => CD,
CLK => CLK,
CE => CE,
50
TC10 => TC10
);
-- Clock process definitions
CLK_process :process
begin
CLK <= '0';
wait for CLK_period/2;
CLK <= '1';
wait for CLK_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ms.
CD <= '1';
CE <= '0';
wait for 100 ns;
CD <= '0';
CE <= '1';
wait for CLK_period*500;
CD <= '0';
CE <= '0';
wait for CLK_period*500;
CD <= '1';
CE <= '0';
wait for CLK_period*500;
CD <= '0';
CE <= '1';
wait for CLK_period*500;
-- insert stimulus here
wait;
end process;
END;
Código 11 Código Simulación funcional Divisor de frecuencia.
Este componente divide 50 veces la entrada que se le introduzca, por esa razón, y para facilitar la grafica, si definimos un periodo de CLK de 1ns el resultado de la simulación es el siguiente.
Figura 41 Simulación del componente divisor de frecuencia.
51
En la grafica anterior se pude ver como la división es perfecta y como el periodo de clock resultante es 50 veces mayor que el de la entrada, recordad que la frecuencia es el inverso del periodo.
3.1.2. Contador síncrono binario de Modulo 11.
El contador tendrá las mismas entradas que el divisor de frecuencia, y para
facilitar el diseño funcionará de forma autónoma. Si en el futuro se desea
añadir alguna funcionalidad, solo se tendrán que declarar las entradas
pertinentes e implementar las condiciones o procesos necesarios.
Contador
CD
CE
CLK
contador_out
( 3 downto 0 )
TC_out
Figura 42 Esquema contador.
3.1.2.1. Especificaciones.
El contador funcionará a la misma frecuencia que el divisor de frecuencia al
que este asociado, y contará desde 0 a 10 mediante un vector de 4 bits.
Se añadirá una salida llamada contador_out y contador_out2 para su posterior
visualización, ya sea en la placa o mediante la simulación.
52
3.1.2.2. Esquema del Contador.
freq_divider_10 Bloque_DCM
CD
CE
CLK
TC_10
CLKIN_IN
RST_IN
CLKDV_OUT
CLKFX_OUT
CLKIN_IBUFG_OUT
CLK0_OUT
LOCKED_OUT
CD
CLK
Contador1
CD
CE
CLK
contador_out
Contador21
CD
CE
CLK
contador_out2
CE
( 3 downto 0 ) ( 3 downto 0 )
TC_out TC_out2
Figura 43 Esquema Contador (Contador 1 + Divisor frecuencia) y (Contador 21 + Bloque DCM).
La primera salida vendrá gestionada por el divisor de frecuencia creado
manualmente y la segunda salida por el gestor de reloj interno (Digital Clock
Manager), el cual se implementará posteriormente.
3.1.2.3. Diagrama de estados del Contador.
El diagrama de estados es muy similar al del divisor de frecuencia.
53
0
TC_out = ‘0’
4
TC_out = ‘0’
(Nº - 1)TC_out = ‘1’
1
TC_out = ‘0’
3
TC_out = ‘0’
2
TC_out = ‘0’
Nota:
N es el valor máximo del vector.
While CE = „0‟
TC_out = ‘1’
While CE = „0‟
While CE = „0‟ While CE = „0‟
While CE = „0‟
While CE = „0‟
CE = „1‟
CE = „1‟
CE = „1‟
CE = „1‟
CE = „1‟CE = „1‟
Figura 44 Estados contador.
Los dos contadores que se implementaran serán idénticos.
3.1.2.4. Código del Contador.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity Contador is
PORT (CD,CLK,CE : IN std_logic;
TC_out : out std_logic;
contador_out : out std_logic_vector(3 downto 0)
);
end Contador;
architecture Behavioral of Contador is
SIGNAL present_state, future_state : std_logic_vector(3 DOWNTO 0);
begin
state_register1: PROCESS (CD,CLK)
BEGIN
IF (CD='1') THEN
present_state <= "0000";
ELSIF (CLK='1' AND CLK'event) THEN
present_state <= future_state;
END IF;
54
END PROCESS state_register1;
conta :process (present_state,CE)
BEGIN
IF (CE = '1') THEN
IF (present_state = "1010") THEN -- 0x18 == 0d24
future_state <= "0000";
ELSE
future_state <= present_state + 1;
END IF;
ELSE
future_state <= present_state;
END IF;
end process;
TC_out <= '1' WHEN (present_state = "1010" AND CE = '1') ELSE '0';
contador_out <= present_state;
end Behavioral;
Código 12 Código contador.
3.1.3. Código top Contador.
Este es el archivo top que engloba todas las declaraciones, asignaciones y
salidas a fin de ser visualizadas en la simulación o tras grabar el programa en
la placa.
Para declarar el divisor de frecuencia dentro del contador se tienen que hacer básicamente dos definiciones:
1ª: Definir las entras y salidas del componente.
COMPONENT freq_div IS
Port ( CD,CLK,CE : IN std_logic;
TC10 : OUT std_logic
);
END COMPONENT;
Código 13 Declaración Divisor.
2º: Asignar dentro del contador las entradas y salidas del divisor de frecuencia, y si es necesario las señales que se utilizarán para conectar las salidas o entradas con otros componentes.
Uut : freq_div_10
PORT MAP (
CD => CD,
CLK => CLK,
CE => CE,
TC10 => TC10
);
Código 14 Asignación entradas/salidas Divisor.
55
En el caso del contador las señales declaradas son:
signal TC10 : std_logic;
Código 15 Señales necesarias Divisor.
TC10 está conectada al pulso a 1MHz y se utiliza como condición dentro del proceso para incrementar el valor del contador
Para declarar el contador, el código y las asignaciones necesarias son las
siguientes.
COMPONENT Contador
PORT(
CD : IN std_logic;
CLK : IN std_logic;
CE : IN std_logic;
TC_out : OUT std_logic;
contador_out : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
Inst_Contador1: Contador PORT MAP(
CD =>CD ,
CLK => CLK0_OUT,
CE =>TC10 ,
TC_out =>TC_out,
contador_out => contador_out
);
Código 16 Declaración y asignación Contador 1.
3.1.3.1. Código archivo top Contador.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity Sumador is
PORT (CD,CLK,CE : IN std_logic;
TC_out,TC_out2 : out std_logic;
div_10out,DCMout : out std_logic;
contador_out2 : out std_logic_vector(3 downto 0);
contador_out : out std_logic_vector(3 downto 0)
);
end Sumador;
architecture Behavioral of Sumador is
56
COMPONENT Contador
PORT(
CD : IN std_logic;
CLK : IN std_logic;
CE : IN std_logic;
TC_out : OUT std_logic;
contador_out : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
COMPONENT freq_div_10
PORT(
CD : IN std_logic;
CLK : IN std_logic;
CE : IN std_logic;
TC10 : OUT std_logic
);
END COMPONENT;
signal TC10 : std_logic;
begin
Inst_Contador1: Contador PORT MAP(
CD =>CD ,
CLK => CLK0_OUT,
CE =>TC10 ,
TC_out =>TC_out,
contador_out => contador_out
);
uut: freq_div_10 PORT MAP (
CD => CD,
CLK => CLK0_OUT,
CE => CE,
TC10 => TC10
);
div_10out <= TC10;
end Behavioral;
Código 17 Top Contador (freq_div_10 + Inst_Contador1)
3.1.3.2. Simulación funcional Contador + Divisor de frecuencia.
Como se ha decidido anteriormente la metodología de simulación que se utilizará será mediante TestBench. Se ha de añadir al proyecto el archivo como se ha explicado anteriormente.
El periodo inicial del reloj son 10 ns y según las especificaciones se necesita una entrada a 50MHz, por esta razón será el primer punto a modificar en el código.
-- Clock period definitions
constant CLK_period : time := 20 ns;
Código 18 Modificación Reloj Test Bench.
Hecho esto se empezará a introducir el código dentro del proceso de simulación para definir las pautas a seguir.
57
3.1.3.2.1. Assert o afirmaciones lógicas.
Para este proyecto a fin de seguir el comportamiento del reloj, ya que es un elemento autónomo, es interesante introducir una herramienta nueva de control.
Las afirmaciones lógicas son un método fiable para obtener información del correcto funcionamiento del código. Se muestra como un evento en el panel de notificaciones, ofreciendo así la posibilidad de saber que error se ha producido o donde se ha producido, y el instante temporal en el cual este ha ocurrido.
Estructura:
assert “Condición”
report "<Texto que queremos mostrar>"
severity note/warning/error;
Note: Texto simple que notifica del evento.
Warning: Muestra un warning dentro de la ventana de compilación.
Error: Muestra un error dentro de la ventana de compilación e interrumpe el flujo del programa.
Esquema:
Figura 45 Esquema funcionamiento Assert's.
Si la afirmación introducida dentro de la secuencia de simulación es correcta, no se producirá el evento definido.
Tras introducir esta herramienta dentro del proceso de simulación el código queda de la siguiente manera:
58
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
ENTITY Simulacion IS
END Simulacion;
ARCHITECTURE behavior OF Simulacion IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Sumador
PORT(
CD : IN std_logic;
CLK : IN std_logic;
CE : IN std_logic;
div_10out,DCMout : out std_logic;
TC_out,TC_out2 : out std_logic;
contador_out2 : OUT std_logic_vector(3 downto 0);
contador_out : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
--Inputs
signal CD : std_logic := '0';
signal CLK : std_logic := '0';
signal CE : std_logic := '0';
--Outputs
signal contador_out : std_logic_vector(3 downto 0);
signal TC_out : std_logic;
signal div_10out : std_logic;
-- Clock period definitions
constant CLK_period : time := 20 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: Sumador PORT MAP (
CD => CD,
CLK => CLK,
CE => CE,
TC_out=> TC_out,
TC_out2=> TC_out2,
div_10out=> div_10out,
contador_out => contador_out
);
-- Clock process definitions
CLK_process :process
begin
CLK <= '0';
wait for CLK_period/2;
CLK <= '1';
wait for CLK_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ms.
CD <= '1';
CE <= '0';
wait for 100 ns;
CD <= '0';
CE <= '1';
wait for CLK_period*500;
assert contador_out = "1001"
report "<Paso 1 error!>"
severity note;
wait for CLK_period*50;
59
CD <= '0';
CE <= '0';
wait for CLK_period*500;
assert contador_out = "1010"
report "<Paso 2 error!>"
severity note;
wait for CLK_period*50;
CD <= '1';
CE <= '0';
wait for CLK_period*500;
assert contador_out = "0001"
report "<Paso 3 error!>"
severity note;
wait for CLK_period*50;
CD <= '0';
CE <= '1';
wait for CLK_period*500;
assert contador_out = "1001"
report "<Paso 4 error!>"
severity note;
wait for CLK_period*50;
-- insert stimulus here
wait;
end process;
END;
Código 19 Código simulación funcional Contador.
Se fuerza un error o una afirmación falsa para ver el comportamiento del Assert.
Tras simular esta secuencia, en donde como se puede ver se ha producido el evento error en el paso 3, el resultado es el siguiente.
Figura 46 Simulación sumador + divisor frecuencia.
Se puede observar la ejecución del assert y el correcto funcionamiento del
sistema.
60
3.1.4. DCM (Digital Clock Manager)
Esta herramienta es un método de gestionar el reloj de entrada, que permitirá
realizar diferentes operaciones para adecuarlo tanto en frecuencia como en
fase a un modo de trabajo deseado.
Este componente es una propiedad intelectual (IP) que proporciona el
programa de forma gratuita. Al estar implementada dentro del programa, su uso
es mediante formularios y la mayoría del código vendrá prediseñado, como a la
hora de crear el archivo de simulación TestBench.
Para implementar este componente y ver su funcionamiento se hará una
ampliación del sumador anterior.
3.1.4.1. Especificaciones.
Se pretende, a la salida del componente DCM obtener una frecuencia de 5
MHz simple y de fase fija.
3.1.4.2. Esquema del componente.
Bloque_DCM
CLKIN_IN
RST_IN
CLKDV_OUT
CLKFX_OUT
CLKIN_IBUFG_OUT
CLK0_OUT
LOCKED_OUT
Figura 47 Esquema componente DCM.
Todas las salidas tendrán que ser declaradas como señales y a partir de la
inclusión de este componente en el proyecto, el resto de elementos
dependientes del reloj tendrán que estar conectados a la salida CLK0_OUT.
La salida CLK0_OUT proporciona la misma frecuencia que insertamos al
componente DCM en su entrada de reloj, a fin de ser utilizada por el resto de
a izquierda mediante tabulaciones. Esto significa que el LCD es capaz de
cargar más datos de los que es capaz de mostrar a tiempo real.
Figura 87 Comportamiento pantalla LCD.
Si se quiere que los datos siempre sean visibles, se tendrá que tabular de tal
manera la información que se enviara a la pantalla, para que el contenido
deseado siempre este dentro del margen visible.
Figura 88 Introducción datos en pantalla.
Las casillas en blanco serán espacios, a fin de desplazar el texto útil a derecha
o izquierda según se necesite.
4.6.2. Modificación del código inicial.
Para corregir el tiempo de refresco de las letras en pantalla, puesto que el
diseño inicial del condigo se establecía un tiempo elevado entre la aparición de
una letra y la siguiente, se modificará el patrón para esta parte del código.
((stCur = stCharDelay and count = "00000000000011111"))
Código 29 Condición de retardo en la lectura de un carácter.
Otro punto a modifica es el hecho que este condigo funcionaba de forma
autónoma, una vez que empezaba, cargaba la variable fija de entrada y
91
mostraba su contenido automáticamente sin posibilidad de intervención
externa. Únicamente permitía reiniciar el proceso mediante la entrada rst.
Se hará uso precisamente de esto para gestionar como actualizar el contenido
de la variable de entrada, que será convertida en una señal para poder
modificar su información mediante la declaración de un proceso para esta
tarea.
El evento más rápido del reloj, es la actualización en tiempo real de los datos
de los segundos, por esa razón se utilizara la salida a 1 Hz del divisor de
frecuencia para reiniciar el proceso de presentación de datos. De este modo
cada vez se modifique el valor de los segundo, el programa automáticamente
recargara la señal de datos y realizara todo el proceso necesario para rellenar
la parrilla a mostrar por pantalla.
Algunos datos a mostrar por pantalla serán cargados inicialmente y solo se
tendrá que ir actualizando 6 variables, correspondientes a las unidades de
decenas de segundo, minutos y horas.
Tras declarar las entradas necesarias en el código, el proceso que gestiona la
adquisición y actualización de datos a mostrar es el siguiente:
4.6.2.1. Proceso de adquisición de datos a mostrar.
begin process
begin
LCD_CMDS(44) <= entrada5;
LCD_CMDS(45) <= entrada6;
LCD_CMDS(47) <= entrada3;
LCD_CMDS(48) <= entrada4;
LCD_CMDS(50) <= entrada1;
LCD_CMDS(51) <= entrada2;
end process;
Código 30 Proceso de adquisición.
Las posiciones asignadas han seguido el patrón descrito para situarlos en el
margen visible de la pantalla.
Tras efectuar estas modificaciones se hará uso de la función RTL para
visualizar el resultado, y así se dispondrá de la nomenclatura del componente
de forma general para su declaración en el archivo general, que contendrá
todos los bloques anteriormente explicados.
92
Figura 89 RTL componente LCD.
4.7. Convertidor de 4 bits a ASCII.
Los datos para ser enviados al componente LCD tiene que estar en formato
ASCII, pero las salidas de todos los componentes son 4 bits tanto para
unidades como para las decenas.
A fin de proporciona la entrada necesaria se ha diseñado un convertidor de
datos, capaz de transformar la entrada de 4 bits a la entrada de 10 bits, con la
estructura y el contenido en ASCII, necesaria para su correcto procesado por el
sistema de adquisición de datos del componente LCD.
Figura 90 Convertidor 4 bits a ASCII.
Este componente se declarara para cada uno de los valores a mostrar por
pantalla.
4.7.1. Método de conversión.
El método de conversión viene gestionado por un case que asigna la salida
adecuada en cada caso, recorriendo valores que van desde 0 a 9, ya que son
los necesarios para mostrar todas las configuraciones posibles en un reloj
tradicional.
93
Ejemplo:
WHEN "1000" => LDR1 <= "10"&X"38";
“10” -> Forma parte del vector de posicionamiento en pantalla.
“28” -> Corresponde al número 8 en ASCII.
4.7.2. Código Convertidor.
Anexo: 8.1.3.1.
4.7.3. Simulación se la conversión.
Figura 91 Simulación de la conversión.
El la figura se puede observar la conversión de 6 valores a ASCII, y la
correspondencia del estado 10 del CASE con un espacio en blanco, a fin de
propiciar el parpadeo.
94
4.8. Parpadeo del número seleccionado.
El último componente dentro del espacio de visualización, es el encargado de
hacer parpadear la cifra a modificar dentro de los estados de control de la
máquina de estados.
Aunque este componente pertenece propiamente a la máquina de estados, y
será declarado dentro de su componente, su explicación se ha relegado a la
parte visual del proyecto para seguir con la linealidad del desarrollo del mismo.
Esto se justifica porque hasta este punto no era necesario incluir ningún
método visual que permitiera al usuario saber en qué punto se encuentra la
máquina de estados.
Figura 92 Componente parpadeo.
Este componente es controlado por la salida a 10 Hz del divisor de frecuencia,
por esa razón se tendrá que incluir una segunda entrada de reloj al
componente maquina de estados (CLK2) y definir la señal necesaria para llevar
el segundo pulso a la entrada de reloj del componente.
4.8.1. Método de funcionamiento del parpadeo de la cifra.
Como hacer parpadear la cifra a 10 Hz era un número muy elevado se ha
implementado un divisor de frecuencia muy simple para conseguir
aproximadamente un parpadeo a 2 Hz.
PAR<='1' WHEN (DIV="00" or DIV="01") ELSE '0';
Figura 93 División simple de frecuencia.
95
En la condición anterior DIV, es un vector de 2 bits que incrementa su valor con
cada pulso de reloj, de este modo se consigue que la cifra solo parpadee la
mitad de su recorrido.
Antes se consideraba que el evento más rápido del programa era la
actualización del valor de segundos, ahora para poder visualizar el evento
parpadeo se necesita que el proceso del componente LCD se reinicie a mayor
velocidad. Por esa razón se substituirá la entrada rst del componente que
anteriormente estaba conectada la salida a 1 Hz del divisor de frecuencia, por
la salida de 10 Hz del mismo.
El control del dato que debe parpadear viene regido por la condición PAR y la
entrada estado proveniente de la máquina de estados.
ELSIF (PAR='0' And estado="11" ) THEN
STout<=STin;
SUout<=SUin;
MTout<=MTin;
MUout<=MUin;
HTout<="1010";
HUout<="1010";
Figura 94 Condición del parpadeo.
Cada estado menos el de reposo tiene un bloque de condición igual. En este
caso se muestra el modo de control de las horas. Cuando al número le
corresponda parpadear, se le asignara un valor definido por el usuario que
corresponderá a una posición del case del Convertidor de datos. Este valor
está definido fuera del método normal de funcionamiento para que no se
produzcan errores, y corresponde a la posición 10 del case. En esta posición
se asigna a la salida el valor correspondiente a un espacio en código ASCII
para que cuando el LCD lo capture, pinte por pantalla un hueco en blanco.
WHEN "1010" => LDR1<= "10"&X"20";
“Espacio”
Asi el comportamiento queda de la forma siguiente:
Par -> 1 1 0 0 1 1
HTout -> Dato Dato Espacio Espacio Dato Dato
96
4.8.2. Código parpadeo.
Anexo: 8.1.4.1.
4.8.3. Simulación parpadeo.
Figura 95 Simulación Parpadeo.
En la figura se puede observar como la cifra pasa de su valor origina a 1010
(correspondiente a un espacio en blanco en ASCII) cada dos pulsos del reloj de
entrada.
La condición que decide que cifra parpadea en cada instante es el estado en
que se encuentra, este estado concuerda con el valor de present_state en la
máquina de estados, haciendo coincidir así el parpadeo con el estado con el
cual se está interaccionando.
Con estas últimas modificaciones ya se tienen todas las herramientas que
fomentaran un buen funcionamiento del dispositivo.
97
4.9. Esquema final completo.
Se ha ido describiendo las conexiones bloque a bloque, pero para facilitar y comprobar el diseño, se ha elaborado el esquema completo que interconecta todos los componentes.
El código final tiene más salidas que las que se muestran, se han ido utilizando para seguir el funcionamiento y para mostrar el comportamiento de algunos elementos, como por ejemplo el bloque de reloj y sus medidas en el laboratorio.
4.9.1. Código archivo top global.
Anexo: 8.1.6.
98
4.9.2. Esquema teórico global.
lcd
CLKDB
RS
RW
ADR1
ADR2
CS
OE
rdone
(7 downto 0)
Convnum1Count LDR1
freq_divider_topDCMclock
CLK_1Hz
CLK_10Hz
CLK_1000Hz
CLKIN_IN
RST_IN
CLK_10000hez
CLKFX_OUT
CLKIN_IBUFG_OUT
CLK0_OUT
LOCKED_OUT
UD_L
STATE
MACHINESET
MODE
CLK
CLK2
CD
CEHT
HU
MT
MU
ST
SU
CLK
CD
CE
UD_L
SETE
MODE
OE
CS
rdone
ADR2
ADR1
RW
RS
DB (7 downto 0)
Salidas
Entradas
rst
CLK
CD
CE
CL
K0
_O
UT
CL
K_
1h
ez
CL
K_
10
he
z
Convnum2Count LDR1
Convnum3Count LDR1
Convnum4CountLDR1
Convnum5CountLDR1
Convnum6CountLDR1
TENS3sig (3 downto 0)
UNIS3sig (3 downto 0)
TENS2sig (3 downto 0)
UNIS2sig (3 downto 0)
TENSsig (3 downto 0)
UNISsig (3 downto 0)
LDR1sigLDR2sigLDR3sigLDR4sigLDR5sigLDR6sig
entrada1entrada2entrada3entrada4entrada5entrada6
Figura 96 Esquema completo de la aplicación.
99
4.9.3. RTL del sistema completo.
Por causa de su tamaño solo se muestra la primera parte, pero aun así se ve
que las pautas de conexiones son las mismas que en el esquema teórico.
Figura 97 RTL de la aplicación.
100
4.9.4. Comprobación de la aplicación.
4.9.4.1. UCF Aplicación.
Anexo: 8.1.7.
Tras introducir el código en la Spartan-3AN y tras un lago peregrinaje uniendo
todas las partes, por fin se puede ver el comportamiento del reloj en tiempo real
funcionando, y funcionando de forma predecible y satisfactoria.
Figura 98 Plano general funcionamiento aplicación.
Figura 99 Plano detalle aplicación.
101
5. Posibles mejoras.
Hoy en día se pueden encontrar en el mercado multitud de relojes diferentes,
desde los más sencillos a relojes destinados a senderismo y escalada que
disponen de brújula, altímetro, GPS y barómetro.
Figura 100 Reloj de montaña (RS800CX G3 - polar).
Por las dimensiones del hardware en el que se trabaja, no sería viable hacer un
dispositivo móvil similar, pero se podrían incluir los periféricos necesarios para
construir una estación fija para recopilar esta información.
El paso siguiente seria instalar este dispositivo en un determinado lugar y que
fuera capaz de realizar una tabla o base de datos de las condiciones del
entorno que le rodean, o incluso enviar dicha información a un ordenador o
móvil mediante su tarjeta de red.
Finalmente se podría abordar una tecnología emergente como la domótica para
incorporar la información de los periféricos que controlan un hogar o sistema de
alarma en el abanico de información que recopilamos con la Spartan-3AN, o
incluso utilizar el dispositivo para gobernar el domicilio, ya sea físicamente o
mediante la tarjeta de red desde un lugar remoto.
Figura 101 Hogar domótico.
102
6. Conclusiones
Este trabajo surgió de la necesidad de conocer la forma de programar las
diferentes FPGA‟s que nos rodean de los distintos fabricantes.
El documento iría destinado a gente similar al creador de este proyecto, que
hasta hace menos de un año desconocía por completo la programación de este
tipo de dispositivos, y cuando empezó carecía de un documento compacto y en
castellano para introducirse en el mundo de la Spartan-3AN, ya que la mayora
de tutoriales abarcaban proyectos mucho mayores y complejos.
En la elaboración de proyectos, se han construidos códigos sencillos y códigos
compuestos gobernados por un reloj de entrada. En cuando a los diferentes
métodos de adecuar la frecuencia de entrada a nuestro dispositivo, se han
implementado divisores de frecuencia y utilizado IP‟s (Intelectual Properties),
como el componente DCM para evitar saltos abruptos en frecuencia.
Se ha visto que el uso del componente DCM es mucho mejor, ya que
reconstruye mucho mejor la señal de salida, pero presenta un abanico de
frecuencias muy elevadas para conseguir un pulso a un 1 Hz.
Simulando los diseños se ha podido comprobar la practicidad frente al archivo
.DO del uso del TestBench, por su incrustación dentro del programa de diseño
y su inmediatez tanto por la cantidad de código que ofrece resuelto, como
puede ser la implementación del reloj, o en la obtención de los datos de la
simulación.
Se ha implementado un maquina de estados capaz de gobernar un buen grupo
de componentes sumisos a ella y a su vez dependiente de un reloj de entrada.
Esta máquina es la encargada de gestionar el modo de funcionamiento y la
puesta en hora del dispositivo. Para su creación se ha seguido un diagrama de
estados y un modelo circuital creado previamente de forma teórica.
La visualización se ha resuelto incorporando el uso del periférico LCD. Se ha
podido ver cómo funciona y como modificar un código origen para un uso
deseado. La adecuación de la información de entrada ha sido resuelta
mediante un convertidor de datos a un formato esperado, a fin de ser
correctamente procesada la información por el LCD.
Finalmente se han implementado pequeñas mejoras estéticas como el
parpadeo del dato seleccionado para ser modificado, dentro de los estados de
control en la STATE MACHINE.
103
7. Bibliografía
7.1. Tutoriales en formato PDF que proporción la Web de
Xilinx.
Spartan-3 Generation Configuration User Guide (PDF)
Spartan-3 Generation FPGA User Guide (PDF)
Device Reliability Report, First Quarter 2010 (PDF)