VIABILIDAD DE LA TARJETA BASYS2 PARA SU

Anuncio
INSTITUTO TECNOLÓGICO DE TEHUACÁN
Departamento de Ingeniería Eléctrica-Electrónica
Reporte de Residencia Profesional
Proyecto:
VIABILIDAD DE LA TARJETA BASYS2
PARA SU IMPLEMENTACIÓN EN EL
CONTROL DE UN PROCESO
Presenta:
Mario Merino Márquez
Asesor Interno:
Ing. Juan José Ortiz Flores
Asesor Externo:
Dr. Oscar Leopoldo Pérez Castañeda
Tehuacán, Puebla; a 24 Mayo de 2012
pág. 1
ÍNDICE
ÍNDICE .................................................................................................................... 2
INTRODUCCIÓN ................................................................................................... 4
JUSTIFICACIÓN .................................................................................................... 6
OBJETIVOS............................................................................................................ 8
OBJETIVO GENERAL .................................................................................... 8
OBJETIVOS ESPECÍFICOS ............................................................................. 8
ÁREA DE PARTICIPACIÓN ................................................................................. 9
PROBLEMAS A RESOLVER.............................................................................. 10
CRONOGRAMA DE ACTIVIDADES ................................................................. 10
Búsqueda y Compra de Tarjeta basada en FPGA XILINX Spartan 3E 100K ... 10
Instalación y Manejo del Software ISE Design Suite 13.4 y Digilent Adept ....... 10
Investigación de la Arquitectura de la Tarjeta basada en FPGA ....................... 10
Manejo del Lenguaje de Programación VHDL ................................................... 11
Desarrollo e Implementación de Prácticas de Circuitos Digitales básicos con
VHDL y la Tarjeta basada en FPGA ............................................................................... 11
Desarrollo e Implementación de Máquinas de Estados Finitos (FSM) .............. 11
Acondicionamiento de Entradas y Salidas de la Tarjeta basada en FPGA para
adquisición de datos y activación de actuadores............................................................ 12
Desarrollo e Implementación del Control de un Proceso por medio de la Tarjeta
basada en FPGA ............................................................................................................. 12
ALCANCES Y LIMITACIONES........................................................................... 13
ALCANCES ................................................................................................ 13
LIMITACIONES............................................................................................ 13
MARCO TEÓRICO .............................................................................................. 15
SISTEMAS DE CONTROL Y SISTEMAS DIGITALES .......................................... 15
DISPOSITIVOS FPGA ................................................................................. 17
FAMILIAS COMERCIALES DE FPGAS. ........................................................... 19
FPGA’s de Xilinx. ............................................................................................... 19
FPGA’s de Altera. ............................................................................................... 19
FPGA’s de Actel ................................................................................................. 20
FAMILIA XILINX SPARTAN-3E FPGA............................................................ 21
TARJETA BASYS2 ...................................................................................... 22
Características Generales: ................................................................................. 23
TENDENCIAS TECNOLÓGICAS POR MERCADO DEL FPGA ............................. 25
Comunicaciones ................................................................................................. 25
Aeroespacial y Militar ......................................................................................... 26
Automotriz .......................................................................................................... 26
Industrial ............................................................................................................. 26
Electrónica de Consumo .................................................................................... 27
Procesamiento de Datos .................................................................................... 27
LENGUAJE VHDL ...................................................................................... 27
pág. 2
Formas de describir un circuito .......................................................................... 27
Secuencia de diseño .......................................................................................... 28
Ventajas de los lenguajes HDL .......................................................................... 31
Entity................................................................................................................... 31
Architecture ........................................................................................................ 33
Bibliotecas .......................................................................................................... 34
Paquetes ............................................................................................................ 34
PROCEDIMIENTO Y DESCRIPCIÓN DE LAS ACTIVIDADES REALIZADAS .. 35
ADQUISICIÓN DE LA TARJETA BASYS2 ......................................................... 35
DESCARGA E INSTALACIÓN DE SOFTWARE ISE DESIGN SUITE 13.4 Y ADEPT
2.6.1 SYSTEM ....................................................................................................... 36
USO DEL SOFTWARE ISE DESIGN SUITE 13.4, ADEPT 2.6.1 SYSTEM Y
CONFIGURACIÓN DE LA TARJETA BASYS2 ............................................................... 38
Entidad y Arquitectura .......................................................................... 43
Simulación............................................................................................ 47
Diseño Estructural en VHDL ................................................................. 56
Configuración de la Tarjeta Basys2 ...................................................... 66
RESULTADOS ..................................................................................................... 74
DESARROLLO DE PRÁCTICAS UTILIZANDO LA TARJETA BASYS2 .................... 74
Practica 1 – Decoder Display ............................................................................. 74
Practica 2 - Contador Ascendente ..................................................................... 77
Practica 3 - Contador con salida a Display ........................................................ 81
Practica 4 - Encendido de un motor de CD....................................................... 83
Práctica 5 - Motor Reversible ............................................................................. 85
Practica 6 – Sumador Aritmético con Salida a Display ...................................... 88
Practica 7 – Unidad Aritmética Lógica (ALU) ..................................................... 97
Practica 8 – Elementos de Memoria (Flip-Flops) Pulsador .............................105
Practica 9 – Maquinas de Estados Finitos (FSM) ............................................108
Práctica 10 – Circuito Anti rebotes (Debounce Circuit) ...................................120
Practica 11 - Generación de una señal PWM .................................................125
Practica 12 - PWM con salida a display. ..........................................................129
Practica 13 – Señal PWM con Potenciómetro. ...............................................135
Practica 14 - Control de un motor debido a la señal de un sensor. .................140
Práctica 15 - Señal PWM controlada con Pushbuttons ...................................152
Práctica 16 - Contador Parametrizable (Mod_m_Counter) ..............................157
Práctica 17 - FIFO Buffer .................................................................................159
Práctica 18 – Comunicación Serial Puerto PS2 – Teclado ..............................162
CONCLUSIONES Y RECOMENDACIONES .................................................. 171
REFERENCIAS BIBLIOGRÁFICAS ................................................................. 172
pág. 3
INTRODUCCIÓN
Viabilidad de la Tarjeta Basys2 para su Implementación en el
Control de un Proceso
Ante las diferentes aplicaciones a realizar dentro del campo de los
Sistemas Digitales, nuevas tecnologías han emergido como herramientas a
las mismas. La adquisición de datos es una de estas aplicaciones, para la
cual se han utilizado diferentes herramientas como son sistemas basados en
microprocesadores, microcontroladores, CPLD, entre otros.
Con la aparición de los dispositivos FPGA’s (Fiel Programmable Gate
Array), se dispone de una nueva herramienta para los sistemas digitales. Su
alta disponibilidad de recursos lógicos, bloques de memoria SRAM, bloques
MAC, aumento de las entradas y salidas y sobre todo su reprogramación,
han colocado a estos dispositivos como una de las herramientas más
versátiles en estos momentos.
La opción de generar maquinas de estados finitos FSM (Finite State
Machines) de forma rápida y sencilla gracias a los lenguajes HDL (Lenguajes
de Descripción de Hardware), colocan a los dispositivos FPGA’s como una
solución eficaz ante el diseño de sistemas digitales.
La combinación del lenguaje HDL y los dispositivos FPGA’s permiten a
los diseñadores simular, probar e implementar físicamente circuitos digitales
sofisticados, reduciendo el tiempo que existe desde el diseño hasta la
producción final.
En este documento se propone analizar la viabilidad de la tarjeta
Basys2, basada en tecnología FPGA para su aplicación en el Control de un
Proceso.
Para demostrar la viabilidad y poner a prueba la Tarjeta Basys2 se
proponen una serie de prácticas que servirán como guía de aprendizaje de
las bases del Lenguaje de Programación VHDL (Very High Speed Hardware
Description Language), la instalación y uso del software XILINX ISE13.4, la
traducción por medio del software Digilent Adept y el manejo de la Tarjeta
Basys2.
pág. 4
Se recomienda al lector tener conocimientos de Electrónica Digital y
Electrónica Analógica Básica para la total comprensión de los temas
expuestos.
El FPGA utilizado es el XILINX Spartan 3E-100K por lo cual este
documento puede servir de referencia para el manejo de otras Tarjetas tales
como la Spartan-3 Starterboard, Spartan-3E Starterboard, Nexys-2 board,
Pegasus, Basys o de arquitecturas semejantes.
pág. 5
JUSTIFICACIÓN
Velocidad, Reprogramación, Múltiples I/0, Rendimiento, Costo
Los Dispositivos Lógicos Programables ofrecen múltiples ventajas en
el diseño de sistemas digitales; son una alternativa viable ante
microprocesadores, microcontroladores y ASIC’s (Circuitos Integrados de
Aplicación Específica) debido a su naturaleza reprogramable, alto
rendimiento y facilidad de uso; todo esto a un costo accesible.
Diseñadores de Sistemas Digitales pueden desarrollar prototipos para
el control de procesos de forma rápida y sencilla, evitando retrasos en la
adecuada elección de un microprocesador o microcontrolador. Con un FPGA
de gama baja se cuenta con los suficientes recursos para diseñar, probar e
implementar el control de múltiples procesos.
La Tarjeta Basys2 basada en el FPGA XILINX Spartan 3E-100K es un
laboratorio completo para el diseño de circuitos digitales ya que cuenta con
Memoria Flash, Interfaz programable USB2, push buttons, switches, led’s,
puerto PS2, puerto VGA y 4 módulos de expansión. Al tener todo lo
necesario en una sola placa se reduce el tiempo de salida del prototipo, ya
que se evita el tener que diseñar un PCB (Printed Circuit Board) o utilizar
protoboards que por lo general ocasionan fallos en las señales eléctricas.
El Lenguaje de Descripción de Hardware VHDL representa una
ventaja debido a lo sencilla e intuitiva que es su programación y su síntesis
que no ocupa demasiados recursos; en comparación al Lenguaje
Ensamblador que es más complejo y poco entendible, o el uso de Lenguajes
de alto nivel como lo son C, Basic, Java para microcontroladores y
microprocesadores que gastan recursos excesivamente.
El uso de múltiples microprocesadores embebidos en un FPGA
significa una de las mayores ventajas de estos dispositivos lógicos
programables, la creación de un microprocesador a la medida proporciona un
diseño flexible y escalable que satisface las necesidades del productor y
evita el hecho de que el microprocesador, microcontrolador o ASIC elegido
para el control del proceso quede obsoleto.
El mercado de los FPGA’s ha ido en aumento y XILINX, la empresa
creadora de estos dispositivos lógicos programables se coloca como líder
mundial con el 56% de las ventas de FPGA’s, seguido por Altera, Lattice y
pág. 6
Actel. Las aplicaciones finales que se le dan a estos dispositivos suelen ser
diversas y se presentan en campos tales como telecomunicaciones, industria
automotriz, industria de consumo, entre otros.
Este documento busca además de demostrar la viabilidad de la
Tarjeta Basys2 para ser utilizada en el control de un proceso, beneficiar y
orientar a todos aquellos que se comienzan a sumergir dentro del campo de
los dispositivos lógicos programables para el diseño de sistemas digitales a
través de FPGA’s, de modo que puedan hacer consideraciones para la
elección de la arquitectura que controle sus procesos.
pág. 7
OBJETIVOS
Objetivo General
-
Determinar la Viabilidad de la Tarjeta Basys2 para Implementar el
Control de un Proceso
Objetivos Específicos
-
Manejar VHDL (Very High Speed Integrated Circuit Hardware
Description Language) para la Descripción de circuitos Digitales en
un FPGA Spartan 3E
-
Manejar la Tarjeta Basys2 basada en el FPGA XILINX Spartan 3E
100K y sus Similares
-
Manejar el Software compilador y traductor necesario para utilizar
el FPGA XILINX Spartan 3E 100K
-
Determinar e Implementar el control de un proceso
pág. 8
ÁREA DE PARTICIPACIÓN
Ingeniería Electrónica – “Ciencia Aplicada para Crear e Innovar”
El desarrollo de este documento así como las prácticas propuestas se
han llevado a cabo en el Instituto Tecnológico de Tehuacán en el área de
Ingeniería Eléctrica-Electrónica por parte del equipo de Residentes
investigadores del área.
En la Figura1 se muestra el organigrama del Instituto Tecnológico de
Tehuacán, siendo el área de Ingeniería Electrónica dentro del departamento
de investigación el lugar donde se ha desarrollado este proyecto.
Figura 1 - Organigrama del Instituto Tecnológico de Tehuacán
pág. 9
PROBLEMAS A RESOLVER
Cronograma de Actividades
A continuación se exponen los problemas a resolver para el desarrollo
del proyecto, asi como una breve descripción de los mismos.
Búsqueda y Compra de Tarjeta basada en FPGA XILINX Spartan 3E
100K
-
Duración: 2 semanas
-
Objetivo: Buscar y Comprar una Tarjeta de prototipos basada en
un FPGA
-
Descripción: Durante el tiempo propuesto se buscará en internet y
proveedores locales una Tarjeta de Prototipos basada en un FPGA
sencillo.
Instalación y Manejo del Software ISE Design Suite 13.4 y Digilent Adept
-
Duración: 1 semana
-
Objetivo: Descargar e instalar el software necesario para el manejo
de la Tarjeta basada en el FPGA de elección
-
Descripción: Durante el tiempo propuesto se descargarán e
instalarán los programas necesarios para el manejo de la Tarjeta
adquirida, así como el acondicionamiento del equipo de cómputo
necesario.
Investigación de la Arquitectura de la Tarjeta basada en FPGA
-
Duración: 1 semana
-
Objetivo: Investigar y analizar la arquitectura de la Tarjeta basada
en FPGA
pág. 10
-
Descripción: Durante el tiempo propuesto se buscarán y analizarán
las hojas de datos de la Tarjeta adquirida así como del FPGA que
contenga.
Manejo del Lenguaje de Programación VHDL
-
Duración: 3 semanas
-
Objetivo: Conocer y manejar el lenguaje de Descripción de
Hardware VHDL
-
Descripción: Durante el tiempo propuesto se buscará información
acerca del lenguaje VHDL en biblioteca e internet y se aprenderán
las bases del mismo para la programación de la Tarjeta basada en
FPGA.
Desarrollo e Implementación de Prácticas de Circuitos Digitales básicos
con VHDL y la Tarjeta basada en FPGA
-
Duración: 3 semanas
-
Objetivo: Diseñar e Implementar en la Tarjeta basada en FPGA
circuitos digitales combinacionales y secuenciales básicos.
-
Descripción: Durante el tiempo propuesto se diseñaran e
implementarán prácticas de circuitos combinacionales y
secuenciales básicos programados en lenguaje VHDL y
compilados a través del software necesario para la descarga hacia
la Tarjeta basada en FPGA.
Desarrollo e Implementación de Máquinas de Estados Finitos (FSM)
-
Duración: 3 semanas
-
Objetivo: Diseñar e implementar circuitos digitales secuenciales
avanzados.
pág. 11
-
Descripción: Durante el tiempo propuesto se diseñaran e
implementarán prácticas de circuitos combinacionales avanzados
utilizando para ello Maquinas de Estados Finitos (FSM). Se
analizarán las diversas opciones con las que se cuenta para
diseñarlas y se elegirá la más viable.
Acondicionamiento de Entradas y Salidas de la Tarjeta basada en FPGA
para adquisición de datos y activación de actuadores.
-
Duración: 2 semanas
-
Objetivo: Acondicionar las señales eléctricas para hacer interfaces
humano-sensores-actuadores-CI-tarjeta
-
Descripción: Durante el tiempo propuesto se investigará acerca de
los dispositivos analógicos necesarios para hacer la interconexión
de actuadores, sensores, circuitos integrados y demás dispositivos
que interactúen con la tarjeta basada en FPGA para su correcto
funcionamiento sin dañarla; así como las etapas de potencia
necesarias.
Desarrollo e Implementación del Control de un Proceso por medio de la
Tarjeta basada en FPGA
-
Duración: 3 semanas
-
Objetivo: Controlar un Proceso a través de la Tarjeta basada en
FPGA seleccionada
-
Descripción: Durante el tiempo propuesto se buscará una
aplicación de control utilizando la tarjeta basada en FPGA
seleccionada, se diseñará, implementará y se determinará la
viabilidad de su uso.
pág. 12
ALCANCES Y LIMITACIONES
Alcances
Las prácticas expuestas en este documento pretenden demostrar la
viabilidad del uso de una tarjeta de desarrollo basada en FPGA para su
implementación en el control de un proceso, además servirán de guía para
todos aquellos que busquen diseñar sistemas digitales con dispositivos
lógicos programables.
El impacto de este proyecto beneficia a la carrera de Ingeniería
Electrónica en sus cursos de Electrónica Digital y Diseño Digital con VHDL.
La tarjeta Basys 2 cuenta con 4 módulos de expansión PMOD los
cuales cuentan con 4 entradas y salidas externas cada uno que nos permiten
ingresar señales eléctricas de sensores u otros dispositivos, o enviar señales
eléctricas para activar actuadores o establecer comunicación entre el FPGA y
un ordenador.
La Tarjeta Basys2 nos permite trabajar a velocidades de 50Mhz y
controlar múltiples procesos de forma paralela, lo cual es su principal ventaja
en comparación a un microcontrolador.
Limitaciones
La adquisición de la Tarjeta Basys2 en el territorio nacional es
complicada; los distribuidores autorizados de la empresa Digilent se
encuentran fuera del estado de Puebla. Es más sencillo pedirla directamente
al proveedor en USA pero se debe pagar un impuesto aduanal.
Se debe analizar el proceso a controlar para determinar si las entradas
y salidas con las que cuenta la Tarjeta Basys2 son suficientes para su
implementación.
Los componentes electrónicos con los que se cuenta dentro del área
de Ingeniería Electrónica son insuficientes, por lo cual se opta por adquirirlos
en distribuidores locales generando gastos adicionales.
El voltaje de las entradas y salidas de la Tarjeta Basys2 utiliza
tecnología LVTTL de 3.3V por lo tanto se requiere acondicionar
pág. 13
correctamente las señales eléctricas. Además, no cuenta con puerto serial,
LCD (Liquid Crystal Display), ni convertidor analógico-digital integrados en la
tarjeta, por lo que hay que comprarlos y diseñar su interfaz.
La licencia del software ISE Design Suite 13.4 utilizada es de versión
gratuita, por lo tanto para proyectos de mayor volumen o que utilicen FPGA’s
mas avanzados se debe comprar la licencia completa.
El control de procesos más sofisticados está sujeto a la disposición de
recursos económicos, equipo de laboratorio disponible en el área de
Ingeniería Electrónica y componentes electrónicos extras.
pág. 14
MARCO TEÓRICO
Sistemas de Control y Sistemas Digitales
El control de procesos a través de tecnologías reprogramables es un
área en constante crecimiento con dispositivos lógicos programables
evolucionando rápidamente.
Un proceso es un conjunto de actividades o eventos que se realizan
o suceden (alternativa o simultáneamente) bajo ciertas circunstancias con un
fin determinado.
Los sistemas de control son parte integrante de la sociedad moderna y
sus numerosas aplicaciones están alrededor de nosotros: Un sistema de
control esta formado por subsistemas y procesos unidos con el fin de
controlar las salidad de los procesos. En su forma más sencilla, un sistema
de control produce una salida o respuesta para una entrada o estímulo dado.
En la Figura 2 se muestra un sistema de control simple.
Entrada; Estimulo
Salida; Respuesta
Sistema de Control
Respuesta Deseada
Respuesta Real
Figura 2 – Diagrama Sistema de Control
Los sistemas de control se dividen en sistemas en lazo abierto y en
lazo cerrado. Un sistema genérico en lazo abierto se ilustra en la Figura 3 (a),
formado por un subsistema llamado transductor de entrada, que convierte la
forma de la entrada a la empleada por el controlador. El controlador maneja
un proceso o planta. A veces, la entrada se denomina referencia, mientras
que la salida se puede llamar variable controlada. Otras señales, por ejemplo
las perturbaciones se muestran agregadas al controlador y a las salidas del
proceso por medio de puntos de suma que dan la suma algebraica de sus
señales de salida por medio de signos asociados. La característica distintiva
de un sistema en lazo abierto es que no puede compensar ninguna
perturbación que se sume a la señal de actuación del controlador;
simplemente se comandan por la entrada.
pág. 15
Figura 3 – Diagramas a bloques de Sistemas de Control
a) En Lazo Abierto b) En Lazo Cerrado
La estructura genérica de un sistema en lazo cerrado se ilustra en la
Figura 3(b). En diferencia a los sitemas en lazo abierto estos compensan
perturbaciones al medir la respuesta de salida, alimentando esa medida a
una trayectoria de realimentación comparando esa respuesta con la entrada
en el punto de suma. Si hay alguna diferencia entre las dos respuestas, el
sistema acciona el proceso, por medio de una señal de actuación, para hacer
la corrección. 1
El controlador (o compensador) puede ser un dispositivo lógico
programable o un microcontrolador que ejecute las acciones de control.
Un sistema digital es un conjunto de dispositivos destinados a la
generación,
transmisión,
procesamiento
o
almacenamiento
de
señales digitales. También un sistema digital es una combinación de
dispositivos diseñados para manipular cantidades físicas o información que
estén representadas en forma digital; es decir, que sólo puedan tomar
valores discretos.
Para el análisis y la síntesis de sistemas digitales binarios se utiliza
como herramienta el álgebra de Boole.
1
Norman S. Nise, Sistemas de Control para Ingeniería. (1a Edición), Compañía Editorial Continental, Mexico: 2004
pág. 16

Sistemas digitales combinacionales: Aquellos en los que sus
salidas sólo depende del estado de sus entradas en un momento
dado. Por lo tanto, no necesita módulos de memoria, ya que las
salidas no dependen de los estados previos de las entradas.

Sistemas digitales secuenciales: Aquellos en los que sus salidas
dependen además del estado de sus entradas en un momento dado,
de estados previos. Esta clase de sistemas necesitan elementos
de memoria que recojan la información de la “historia pasada” del
sistema.
Dispositivos FPGA
Un FPGA (Field programable gate array) es un dispositivo lógico que
contiene una matriz de celdas lógicas idénticas, con interconexiones
programables (switches programables). La estructura conceptual de un
dispositivo FPGA se muestra en la Figura 4. Una celda lógica puede ser
configurada (programada) para realizar una función simple, y un switch
programable puede ser configurado para proveer interconexión a través de
las celdas lógicas. Un diseño puede ser implementado en un FPGA
especificando la función de cada celda lógica y estableciendo selectivamente
la conexión de cada switch programable. Una vez que el diseño y la síntesis
son completados, podemos utilizar un simple cable adaptador para descargar
la celda lógica deseada y la configuración del switch programable al
dispositivo FPGA, para obtener el circuito digital diseñado.
Figura 4 – Estructura Conceptual FPGA
pág. 17
Las celdas lógicas usualmente contienen un pequeño circuito
combinacional y un flip-flop D (DFF). El método mas común para
implementar un circuito combinacional configurable es a través de una tabla
de búsqueda (look-up table LUT). Una LUT de n entradas puede ser
considerada como una pequeña memoria de 2 n-por-1. Escribiendo
adecuadamente el contenido de la memoria, podemos utilizar una LUT para
implementar cualquier función combinacional de n entradas. El diagrama
conceptual de una celda lógica basada en una LUT de 3 entradas es
mostrado en la Figura 5 (a). La función a⊕b⊕c implementada en una LUT
de 3 entradas es mostrada en la Figura 5(b). Nótese que la salida de la LUT
puede ser utilizada directamente o puede ser almacenada en el Flip-Flop D.
Figura 5 - LUT (Look-up Table)
Macro Celda (Macro cell). La mayoría de los dispositivos FPGA
cuentan con macro celdas o macro bloques embebidos. Estos son diseñados
y fabricados a nivel de transistores, y sus funcionalidades complementan a
las celdas lógicas. Comúnmente las macro celdas usadas incluyen bloques
de memoria, multiplicadores combinacionales, circuitos de manejo de reloj y
circuitos de interface entre entradas y salidas. Dispositivos FPGA mas
sofisticados suelen contener uno o más núcleos de procesador
prefabricados.2
2
Pong P. Chu, FPGA Prototyping by VHDL Examples XILINX Spartan-3 Version. (1a Edición), John Wiley
& Sons Inc, Hoboken, New Jersey: 2008
pág. 18
Familias comerciales de FPGAs.
Existen tres fabricantes mayoritarios en la distribución de FPGA’s y
software de soporte, estos son Xilinx, Altera y Actel. Sin embargo, en el
mercado mundial también existen otros como Lucent, Texas Instruments,
Philips, QuickLogic, Cypress, Atmel, entre otros. No obstante, por la
importancia de las tres primeras compañías se mencionaran algunas de las
familias lógicas que ofrecen.
FPGA’s de Xilinx.
Son uno de los fabricantes más fuertes en el nivel mundial. Sus
FPGAs están basados en la tecnología SRAM, son dispositivos
reprogramables (Many-Times Programable, MTP) y programables en
sistema (ISP).
Sus principales familias son: XC3000, XC4000, XC Virtex y XC
Spartan. Dichos dispositivos están compuestos por módulos lógicos CLBs,
basados en tablas de búsqueda. Cada CLB contiene circuitos que permiten
realizar operaciones aritméticas eficientes. Los usuarios también pueden
configurar las tablas de búsqueda como celdas lectura/escritura (read/write)
de RAM. Asimismo, a partir de la seria XC 4000 se incluye un generador
interno de señal de reloj, con 5 diferentes frecuencia.
Además de los CLBs, los FPGAs de este fabricante incluyen otros
bloques complejos que configuran la entrada de los pines físicos, estos a si
ves conectan el interior del dispositivo con el exterior y los bloques son
llamados bloques de Entrada/Salida (Input/Output Blocks, IOBs). Cada
IOB contiene una lógica compleja que permite que un pin actué como
entrada, salida o triestado (el triestado puede tomar valores de 0, 1 o de alta
impedancia).
FPGA’s de Altera.
Altera ofrece dos familias de FPGAs con características diferentes,
pero conservando algunas básicas que representan las ventajas originales
de las primeras familias estándar: FLEX 6000, 8000 y 10K; así como la más
novedosa, APEX 20K. Las primeras familias estándar, la FLEX 6000 y la
8000 aún se utilizan ampliamente. La serie FLEX (Matriz Flexible de
Elementos Lógicos, Flexible Logic Element Matrix) estándar contiene un
numero considerando de compuertas en tecnología SRAM con tablas de
búsqueda, agregando mayor flexibilidad a los diseños.
pág. 19
La serie estándar FLEX combina la arquitectura de los CPLD con los
FPGAs. El dispositivo consiste de una arquitectura muy parecida a la de un
CPLD; en su nivel más bajo de la jerarquía tiene un conjunto de tablas de
búsqueda, en lugar de un bloque muy similar a un SPLD, por ello se
considera un FPGA. El modulo lógico básico, nombrado por Altera, elemento
lógico (Logic Element), contiene una LUT de 4 entradas, un flip-flop y un
elemento de acarreo (carry) de propósito especial para circuito aritméticos. El
elemento lógico también incluye circuitos en cascada, que permiten una
implementación eficiente de funciones AND amplias.
Esta arquitectura agrupa elementos lógicos en grupos de 8, y los llama
bloques de arreglos lógicos (Arrays Logic Blocks, ALBs). Cada ALB,
contiene una interconexión local que le permite conectarse con otro ALB y a
la vez, la misma interconexión sirve para conectarse a la interconexión global
de la crossbar (matriz de interconexiones), nombrada por Altera como
FastTrack. Así, las interconexiones se hacen al estilo de los CPLDs, pero la
configuración de los bloques de arreglos lógicos utiliza tecnología SRAM
propia de los FPGAs.
FPGA’s de Actel
Actel ofrece una seria de familias OTP que resultan ampliamente
utilizadas después de haber probado satisfactoriamente un diseño (emigrar a
otro FPGA). Las principales son: la serie estándar ACT, y las más nuevas por
orden cronológico de aparición, sX, sX-A, mX y eX. Todas las anteriores son
programables fuera del sistema (OPS). También ofrece una familia
reprogramable a la llamada Pro ASIC (por ser de alta densidad de
componentes, Actel no la considera parte de los FPGAs), basada en una
tecnología Flash EEPROM programable en sistema (ISP).
Los FPGAs de Actel, emplean como modulo o elemento básico una
estructura tipo arreglo fijo de compuertas. La lógica del arreglo está
dispuesta en renglones de módulos lógicos interconectables, rodeados hacia
afuera por módulos de E/S. la estructura de interconexiones consiste en
pistas o líneas fijas de interconexión, horizontales y verticales, con
segmentos de alambrado. Hay muchas pistas en cada canal entre los
renglones de la lógica. Las pistas verticales son menos y pasan sobre los
canales horizontales y los módulos lógicos.
El FPGA de Actel utiliza tecnología antifusible que proporciona una
programación permanente y no volátil. El dispositivo tiene muchos
antifusibles para conectar las entradas y salidas de los módulos de lógica y
E/S, a los segmentos de alambrado de los canales. También tiene antifusible
pág. 20
que interconectan los segmentos de alambrado entre las pistas para ofrecer
conexiones de diferentes longitudes.
Una de las principales características de los módulos lógicos de los
FPGAs de Actel, es que los módulos no se programan para que efectúen una
operación, sino que toda la programación se hace mediante antifusibles en
las pistas de alambrado.3
Familia Xilinx Spartan-3E FPGA
El FPGA utilizado en este proyecto es el Spartan-3E 100K de la marca
Xilinx.
Las características y capacidades de la familia Spartan-3E se han
optimizado para un alto volumen y aplicaciones de bajo costo. Debido a su
excepcional bajo costo, los FPGA de la familia Spartan-3E son viables para
un extenso mercado de aplicaciones electrónicas, incluyendo accesos de
banda ancha, redes locales, control de procesos y equipos de televisión
digital.
Celdas Lógicas, Slice, y Bloques Lógicos Configurables (CLB). El
elemento mas básico de un dispositivo Spartan-3 es una celda lógica (Logic
Cell LC), el cual contiene LUTs de 4 entradas y un Flip-Flop D similar al de la
figura 3. Además, una celda lógica contiene un circuito de acarreo (carry), el
cual es usado para implementar funciones aritméticas, y un circuito
multiplexor. Las LUT pueden ser configuradas como memorias estáticas de
acceso aleatorio (Static Random Access Memory SRAM) de 16-por-1 o como
registros de corrimiento (Shift Register) de 16-bit.
Para incrementar la flexibilidad y mejorar el rendimiento, 8 celdas
lógicas son combinadas con una estructura especial en el ruteo interno. En
términos del fabricante Xilinx, 2 celdas lógicas son agrupadas para formar un
Slice, y 4 slices son agrupado para formar un bloque lógico configurable
(Configurable Logic Block (CLB)).
Macro Celdas del Spartan-3. El dispositivo Spartan-3 cuenta con 4
tipos de macro bloques: multiplicador combinacional, bloque RAM, digital
clock manager (DCM) y bloque de entrada/salida (IOB). El bloque
multiplicador combinacional acepta dos números de 18-bits como entrada y
calcula el producto. El bloque RAM es una SRAM de 18K-bit síncrona que
3
Menéndez Ortiz María Alejandra, Arquitectura FPGA para la adquisición de Datos Térmicos. Universidad
del Mar Campus Puerto Escondido Oaxaca México: 2010.
pág. 21
puede ser configurada de distintas formas. El DCM usa un ciclo “digitaldelayed” para reducir los problemas con los tiempos y controlar la frecuencia
y fase de las señales de reloj. Las IOB controlan el flujo de datos entre los
pines de E/S y la lógica interna.4 La arquitectura del Spartan-3E es mostrada
en la Figura 6.
La Familia Spartan-3E cuenta con 5 miembros que ofrecen distintas
densidades, las cuales van desde los 100,000 hasta los 1.6 millones de
compuertas, tal y como se muestra en la Tabla 1.
Tabla 1- Densidades Familia Spartan-3E
Las características generales del Spartan 3-E se pueden encontrar en
su datasheet a través del siguiente enlace 5
www.xilinx.com/support/documentation/data_sheets/ds312.pdf
Tarjeta Basys2
La tarjeta Basys2 es una plataforma para el diseño e implementación
de circuitos digitales. La tarjeta esta construida en base a un FPGA Spartan3E de Xilinx y un controlador USB Atmel AT90USB2. La tarjeta Basys2
provee el hardware necesario listo para usarse capaz de soportar circuitos
que van desde el rango de lo básico hasta el control complejo de procesos.
Una amplia gama de dispositivos de E/S y todas las conexiones del FPGA
son incluidas, por lo que incontables diseños pueden ser creados sin la
necesidad de componentes adicionales.
4
Pong P. Chu, FPGA Prototyping by VHDL Examples XILINX Spartan-3 Version. (1a Edición), John Wiley
& Sons Inc, Hoboken, New Jersey: 2008
5
Sitio web oficial de Xilinx sección documentación de productos.
www.xilinx.com/support/documentation/data_sheets/ds312.pdf
pág. 22
Figura 6 – Arquitectura Spartan 3-E FPGA
Cuatro conectores de expansión estándar permiten a la tarjeta Basys2
crecer utilizando circuitos diseñados por el usuario o PMods. (Los PMods son
módulos de E/S analógicos y digitales de bajo costo que ofrecen conversión
A/D y D/A, drivers para motor, entradas de sensor y muchas otras
características). Las señales en los conectores de 6 pines están protegidas
contra corto circuito, garantizando una larga vida de funcionamiento en
cualquier ambiente. La tarjeta Basys2 trabaja en cualquier versión del
compilador Xilinx ISE tools, incluyendo la licencia gratuita WebPack.
Contiene un cable USB que le proporciona energía y es utilizado como
interfaz de programación, por lo que ninguna otra fuente de poder o cable de
programación es requerido. 6 En la Figura 7 se muestra el diagrama a
bloques de la tarjeta Basys2.
Características Generales:
-
Xilinx Spartan 3-E FPGA, 100K or 250K gate
6
Manual de Referencia Tarjeta Basys2:http://www.digilentinc.com/Data/Products/BASYS2/Basys2_rm.pdf
pág. 23
-
FPGA con multiplicadores de 18-bit, 72Kbits de bloque RAM dual-port,
y 500MHz+ velocidad de operación
Puerto USB2 full-speed para la configuración y transferencia de datos
hacia el FPGA (utilizando el software Adept 2.0 disponible en
descarga gratuita)
XCF02 Platform Flash ROM que almacena las configuraciones del
FPGA
Frecuencia de oscilación ajustable (25, 50, and 100 MHz), además
cuenta con socket para un oscilador extra
3 reguladores de voltaje incluidos (1.2V, 2.5V, and 3.3V) que permiten
el uso de fuentes externas de 3.5V a 5.5V.
Figura 7– Diagrama a bloques Tarjeta Basys2
-
8 LEDs, 4 displays de siete segmentos, 4 pushbuttons, 8 slide
switches, Puerto PS/2, y un puerto VGA de 8-bit
Cuatro conectores de 6-pines para E/S del usuario, y compatibles con
los circuitos Digilent PMOD.
La compra, asi como la documentación completa y ejemplos acerca de
la tarjeta Basys2 se encuentran en el siguiente enlace7.
7
Documentación Completa, Compra y ejemplos de la Tarjeta Basys2 de Digilent INC.
http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,400,790&Prod=BASYS2
pág. 24
Tendencias Tecnológicas por Mercado del FPGA
Las tendencias de Aplicaciones FPGA a nivel Mundial se muestran en
la Figura 8.
Figura 8– Aplicaciones FPGA a nivel Mundial
Comunicaciones
De acuerdo a la empresa de consultoría industrial Gartner, durante el
ciclo fiscal 2008-2009, el mercado de la tecnología FPGAs para
Comunicaciones generó aproximadamente USD $ 1,45 millones de dólares,
mientras que las proyecciones para el 2012 ascienden a unos USD $ 2,096
millones de dólares.
En cuanto a la cantidad de patentes registradas con esta tecnología
para Comunicaciones, indica que a la fecha se tiene un total de 2,527
documentos y solicitudes a nivel internacional. Los campos en donde se ha
generado mayor propiedad intelectual son: Comunicaciones ópticas,
Comunicaciones Inalámbricas/Alámbricas, Antenas, Moduladores y
Codificadores y Redes.
pág. 25
Aeroespacial y Militar
El mercado de la tecnología FPGA en el 2008 fue de
aproximadamente USD$447 millones y se estima que para el 2012 sea de
USD$717 millones.
Aplicaciones:
-
Sistemas de radar
Enlaces de comunicaciones de alta velocidad
Misiles
Aplicaciones de alta confiablidad en el espacio
Procesamiento digital de señales robusto y de alta seguridad
Automotriz
El mercado de la tecnología FPGA en el 2008 fue de
aproximadamente USD$83 millones y se estima que para el 2012 sea de
USD$358 millones.
-
Aplicaciones:
GPS
Infoentretenimiento
Control de frenos
Control de luces
Sistemas de seguridad
Industrial
Los sectores industriales que mayor consumo de FPGAs registran son
para aplicaciones de Sistemas de Manufactura, Equipo Médico y Monitoreo
de Pacientes, Seguridad, Administración de Energía, Pruebas y Mediciones,
Redes y Domótica. En el 2008 el sector industrial recaudó 852 millones de
dólares (mdd) y se estima que para el 2012 ascienda a unos 1,406 mdd. La
cantidad de patentes internacionales en el sector Industrial con tecnología
FPGAs llega a 524 documentos y solicitudes.
pág. 26
Electrónica de Consumo
En el área de electrónica de consumo, los FPGAs generaron en el
2008 un total de 469 mdd por ingresos y se estima que para el año 2012 se
eleve a 672 mdd. En cuanto a propiedad intelectual a nivel internacional se
han registrado 102 documentos y solicitudes. Las aplicaciones más comunes
en las que son utilizados son: Audio, Video y Equipo de Oficina.
Procesamiento de Datos
El mercado de FPGAs en el 2008 para este campo sumó 312 mdd y
se tiene proyectado que para el año 2012 alcance los 335 mdd. Sus
principales aplicaciones han sido para el desarrollo de Súper computadoras,
Tarjetas Inteligentes, Servidores, Procesadores y Computadoras Personales
(PCs). 8
Lenguaje VHDL
VHDL es el acrónimo que representa la combinación
de VHSIC y HDL, donde VHSIC es el acrónimo de Very High Speed
Integrated Circuit y HDL es a su vez el acrónimo de Hardware Description
Language.
Es un lenguaje definido por el IEEE (Institute of Electrical and
Electronics Engineers) (ANSI/IEEE 1076-1993) usado por ingenieros para
describir circuitos digitales.
Aunque puede ser usado de forma general para describir cualquier
circuito se usa principalmente para programar PLD (Programable Logic
Device - Dispositivo Lógico Programable), FPGA (Field Programmable Gate
Array), ASIC y similares.
Formas de describir un circuito
Dentro del VHDL hay varias formas con las que podemos diseñar el
mismo circuito y es tarea del diseñador elegir la más apropiada.
8
Red Estrategica de Tecnologia FPGA (AERI – FPGA):
http://www.conacyt.gob.mx/fondos/institucionales/Tecnologia/Avance/Redes/1-FPGA-FUMEC-AERI.pdf
pág. 27

Funcional: Describimos la forma en que se comporta el circuito. Esta
es la forma que más se parece a los lenguajes de software ya que la
descripción es secuencial. Estas sentencias secuenciales se
encuentran dentro de los llamados procesos en VHDL. Los procesos
son ejecutados en paralelo entre sí, y en paralelo con asignaciones
concurrentes de señales y con las instancias a otros componentes.

Flujo de datos: describe asignaciones concurrentes (en paralelo) de
señales.

Estructural: se describe el circuito con instancias de componentes.
Estas instancias forman un diseño de jerarquía superior, al conectar
los puertos de estas instancias con las señales internas del circuito, o
con puertos del circuito de jerarquía superior.

Mixta: combinación de todas o algunas de las anteriores.
En VHDL también existen formas metódicas para el
de máquinas de estados, filtros digitales, bancos de pruebas etc.
diseño
Secuencia de diseño
El flujo de diseño de un sistema es:





Construcción del diagrama en bloque del sistema.
Elaboración del código en VHDL para cada modulo, para sus
interfaces y sus detalles internos. Como el VHDL es un lenguaje
basado en texto, se puede utilizar cualquier editor para esta tarea,
aunque el entorno de los programas de VHDL incluye su propio editor
de texto.
Compilación. El compilador de VHDL analiza el código y determina
los errores de sintaxis y chequea la compatibilidad entre módulos.
Crea toda la información necesaria para la simulación.
Simulación funcional. En este tipo de simulación se comprueba que
el código VHDL ejecuta correctamente lo que se pretende.
Síntesis. En este paso se adapta el diseño anterior a un hardware en
concreto, ya sea una FPGA o un ASIC. Hay sentencias del lenguaje
que no son sintetizables, como por ejemplo divisiones o
exponenciaciones con números no constantes. El hecho de que no
todas las expresiones en VHDL sean sintetizables es que el VHDL es
un lenguaje genérico para modelado de sistemas (no sólo para diseño
pág. 28





de circuitos digitales), por lo que hay expresiones que no pueden ser
transformadas a circuitos digitales. Durante la síntesis se tiene en
cuenta la estructura interna del dispositivo, y se definen restricciones,
como la asignación de pines. El sintetizador optimiza las expresiones
lógicas con objeto de que ocupen menor área, o bien son eliminadas
las expresiones lógicas que no son usadas por el circuito.
Simulación post-síntesis. En este tipo de simulación se comprueba
que el sintetizador ha realizado correctamente la síntesis del circuito,
al transformar el código HDL en bloques lógicos conectados entre sí.
Este paso es necesario ya que, a veces, los sintetizadores producen
resultados de síntesis incorrectos, o bien realiza simplificaciones del
circuito al optimizarlo.
Ubicación y enrutamiento. El proceso de ubicación consiste en situar
los bloques digitales obtenidos en la síntesis de forma óptima, de
forma que aquellos bloques que se encuentran muy interconectados
entre sí se sitúen próximamente. El proceso de enrutamiento consiste
en interconectar adecuadamente los bloques entre sí, intentando
minimizar retardos de propagación para maximizar la frecuencia
máxima de funcionamiento del dispositivo.
Anotación final. Una vez ha sido completado el proceso de ubicación
y enrutamiento, se extraen los retardos de los bloques y sus
interconexiones, con objeto de poder realizar una simulación temporal
(también llamada simulación post-layout). Estos retardos son anotados
en un fichero SDF (Standard Delay Format) que asocia a cada bloque
o interconexión un retardo mínimo/típico/máximo.
Simulación temporal. A pesar de la simulación anterior puede que el
diseño no funcione cuando se programa, una de las causas puede ser
por los retardos internos del chip. Con esta simulación se puede
comprobar, y si hay errores se tiene que volver a uno de los pasos
anteriores.
Programación en el dispositivo. Se implementa el diseño en el
dispositivo final y se comprueba el resultado.
En la Figura 9 se muestra el diagrama de flujo con la secuencia de
diseño necesaria.
pág. 29
Inicio
Diagrama a bloques del
sistema
Código en VHDL
No
Compilación
Si
Simulación
Funcional
No
Si
No
Síntesis
Si
Simulación
Pos-Sintesis
No
Si
Ubicación y
Enrrutamiento
Fichero SDF
Anotación Final
Simulación
Temporal
No
Programación del
Dispositivo
Fin
Figura 9- Diagrama de Flujo Secuencia de Diseño
pág. 30
Ventajas de los lenguajes HDL
El empleo de HDL presenta ventajas respecto al empleo de
descripciones basadas en esquemáticos. Algunas de ellas son las siguientes:
1)
Puesto que una descripción HDL es simplemente un fichero de
texto, es mucho más portable que un diseño esquemático, que
debe ser visualizado y editado empleando la herramienta gráfica
específica del entorno de CAD (Computer-Aided Design - Diseño
asistido por ordenador) con el que se ha creado.
2)
Una descripción esquemática únicamente describe el diseño de
manera estructural, mostrando los módulos y la conexión entre
ellos. Por el contrario, la descripción del circuito usando un HDL
puede realizarse bien mostrando la estructura, o bien describiendo
el comportamiento. Es decir, los HDL permiten describir el
comportamiento que se desea que tenga el circuito, sin hacer
ninguna referencia a su estructura. Las herramientas de síntesis
permiten generar automáticamente la estructura del circuito lógico a
partir de la descripción de su comportamiento.
3)
El mismo HDL que se ha usado para la descripción del circuito,
puede emplearse para describir los vectores de test y los resultados
esperados del test. Los vectores de test son los valores de las
señales aplicadas a los pines de entrada del circuito con la finalidad
de probar si el funcionamiento del circuito es correcto. Así pues,
pueden realizarse los programas de test (vectores de test e
instantes en los cuales son aplicados) del circuito a medida que se
diseña el propio circuito, pudiéndose con ello ir realizando
diferentes pruebas a medida que se avanza en el diseño. Como
ventajas añadidas, la descripción de los programas de test usando
HDL es altamente portable y repetible.
Entity
La entity define la interfaz externa de la entidad de diseño. Incluye:
– El nombre de la entidad de diseño.
– La lista de las señales de salida y de entrada que componen la
interfaz (normalmente se aplica el convenio de escribir primero las salidas y a
continuación las entradas). A cada una de estas señales se le denomina
pág. 31
puerto (port). Existen tres tipos de puertos: in (entrada), out (salida) e inout
(bidireccional).
La palabra reservada entity, seguida del nombre de la interfaz y de las
palabras reservadas is port, indica el comienzo de la definición de la interfaz.
A continuación, se especifica el nombre de cada uno de los puertos, su
dirección (in, out o inout) y su tipo. En el ejemplo mostrado en la Figura 10,
todos los puertos son señales del tipo std_logic.
Finalmente, las palabras reservadas end entity, seguidas del nombre
de la interfaz, indican el final de la definición.
Figura 10 – Definición de Entidad de compuertas NOT, XOR y AND
Los nombres definidos por el usuario deben comenzar por una letra,
seguida opcionalmente por cualquier secuencia de letras, números y
caracteres guion bajo, con la limitación de que ni pueden aparecer dos
guiones bajos seguidos, ni el guion bajo puede ser el ultimo caracter del
nombre. En VHDL no se diferencia entre los caracteres en mayúscula y en
minúscula.
Los tipos de señales utilizados en el lenguaje VHDL se muestran en la
Tabla 2.
TIPO
Características
BIT
En este tipo las señales solo toman los valores de "1" y
"0"
Booleana
En este tipo las señales solo toman los valores de True y
False
pág. 32
Std_logic
En este tipo las señales toman 9 valores, entre ellos
tenemos: "1", "0", "Z" (para el 3er estado), "-" (para
los opcionales).
Integer
En este tipo las señales toman valores enteros. Los 1 y
los 0 se escriben sin “
Bit_Vector
En este tipo los valores de las señales son una cadena de
unos y ceros. Ejemplo: “1000”
Std_Logic_Vector
En este tipo los valores de las señales son una cadena de
los nueve valores permisibles para el tipo std_logic.
Character
Contiene todos los caracteres ISO de 8 bits, donde los
primeros 128 son los caracteres ASCII.
Tabla 2 – Tipos de Datos VHDL
Architecture
La architecture describe el comportamiento o la estructura de la
entidad de diseño. En la Figura 11 se muestra la arquitectura de las
compuertas NOT, XOR y AND.9
Figura 11 – Arquitectura compuertas NOT, XOR y AND
9
Urquía Alfonso, Martín Villalba Carla, Casos prácticos de diseño de circuitos digitales con VHDL,
Universidad Nacional de Educación a Distancia (UNED) Departamento de Informática y Automática, Madrid,
España: 2008
pág. 33
Bibliotecas
Una biblioteca en VHDL es un lugar en donde se guarda la
información relacionada con un diseño determinado. Al comienzo de cada
diseño el compilador crea automáticamente una biblioteca llamada WORK
con este objetivo. Además de esta biblioteca particular existen otras
bibliotecas de tipo general que contienen un conjunto de definiciones que
pueden utilizarse en cualquier diseño. Un ejemplo de biblioteca general es la
llamada Library IEEE, que contiene definiciones estándar para VHDL. Para
utilizar una biblioteca general es necesario escribir su nombre al inicio del
programa, por eso es muy común que en la primera línea de un diseño en
VHDL aparezca escrito "Library IEEE", de ésta forma dicha biblioteca se
hace visible para el diseño.
Paquetes
En los paquetes se guardan definiciones de tipos y objetos que
pueden ser utilizados en los diferentes diseños que invoquen su utilización.
Un
paquete
muy
utilizado
es
el
paquete
estándar
IEEE_STD_LOGIC_1164.ALL; La utilización de un paquete en un diseño se
realiza invocando su empleo mediante la cláusula USE y el nombre del
paquete. Por ejemplo USE IEEE_STD_LOGIC_1164.ALL;
La terminación ALL, permite utilizar todas las definiciones y objetos
que contiene dicho paquete. Además del estándar, existen otros paquetes de
utilización general y también los diseñadores que trabajan con VHDL pueden
definir sus propios paquetes, lo que les permite reutilizar diseños realizados
anteriormente como parte de nuevos diseños.
pág. 34
PROCEDIMIENTO Y DESCRIPCIÓN DE LAS
ACTIVIDADES REALIZADAS
Adquisición de la Tarjeta Basys2
La Tarjeta Basys2 y otros instrumentos fueron solicitados a la empresa
Digilent a través de su sitio web oficial www.digilentinc.com.
El catálogo completo de las tarjetas basadas en FPGA’s y CPLD’s se
encuentra en el siguiente vínculo:
http://www.digilentinc.com/Products/Catalog.cfm?NavPath=2,400&Cat=10&F
PGA
Cantidad
Producto
1
Basys2
Basys2 Spartan 3E FPGA Board
2
Multimete
r-MS821
PMOD-TMP
Autorange Digital Multimeter
1
Descripción
PMOD-TMP Thermometer
Precio
Unitario
$ 59.00
USD
$ 29.99
USD
$ 24.99
USD
Sub
Total
$ 59.00
USD
$ 59.98
USD
$ 24.99
USD
Tabla 3: Gastos en Digilent Inc
El envió desde USA se hizo a través del servicio de paquetería Fed-Ex
en un lapso de 3 días hábiles.
Cantidad
Producto
1
Envío
1
Impuesto
Descripción
Servicio de Paquetería FedEx
Impuesto Aduanal
Precio
Unitario
$ 81.77
USD
$ 30.00
USD
Sub
Total
$ 81.77
USD
$ 30.00
USD
Tabla 4: Gastos de Envio
Además se utilizaron componentes electrónicos pasivos y activos para
la implementación de las prácticas que implicaron un gasto extra en el
desarrollo del proyecto. Estos componentes fueron adquiridos en
distribuidores locales.
pág. 35
Cantidad
Producto
Descripción
Precio
Unitario
2
Protoboard
Tablilla para Prototipos
1
SN754410
Quadruple Half-H Driver
1
NE555
Multivibrador 555
30
Resistor
5
Capacitor
20
2N25
Resistores de distintos
valores
Capacitores Electrolíticos
y Cerámicos
Optoacoplador MOC
10
2N2222
NPN Transistor
1
Motor
Motro de 5V CD
2
Relay
Relays de 5V CD
3
Cable
Telefónico
Metros de Cable Telefónico
$ 9.00
USD
$ 2.99
USD
$ 0.95
USD
$ 0.10
USD
$ 0.30
USD
$ 0.80
USD
$ 0.23
USD
$ 1.00
USD
$ 1.00
USD
$ 0.88
USD
Sub
Total
$ 18.00
USD
$ 2.99
USD
$ 0.95
USD
$ 3.00
USD
$ 1.50
USD
$ 16.00
USD
$ 2.30
USD
$ 1.00
USD
$ 2.00
USD
$ 2.64
USD
Tabla 5: Gastos Extras
Por lo tanto el gasto total es de:
$
306.12 USD
Convertido a moneda nacional a una tasa de cambio de $ 13.43 MN el
gasto total es de:
$ 4111.18 MN
Descarga e Instalación de Software ISE Design Suite 13.4 y Adept
2.6.1 System
Xilinx ofrece una licencia gratuita de su entorno de desarrollo y diseño
para sus dispositivos reconfigurables, la versión gratuita se conoce como
Webpack, en últimas versiones no se trata de un software separado del
principal sino de una licencia de uso especial para el mismo, a continuación
se muestran los pasos necesarios para descargar el software y obtener la
licencia gratuita.
1- Ingresar y registrarse en el sitio web de Xilinx: www.xilinx.com. Al
ingresar al sitio, en el menú de la parte superior se tiene la opción
“Sign In”, que permite ingresar con una cuenta creada con
anterioridad o registrarse con una nueva mediante el enlace
“Create Account”.
pág. 36
Figura 12– Página Principal de Xilinx
Para el registro se deben proporcionar algunos datos personales tales
como nombre, dirección y correo electrónico.
2- Una vez registrados en el sitio, se puede acceder a la sección de
descargas, puede hacerse desde el enlace “Downloads” en la
parte superior del sitio. El software que nos interesa se llama ISE
Design Suite, en la página se puede seleccionar la versión a
descargar así como el sistema operativo con el cual trabajaremos:
hay tres opciones de descarga, instalador para Windows,
instalador para Linux o los binarios. La versión más reciente del
software y la utilizada en este documento es la 13.4.
3- La descarga no es directa, sino que al hacer clic en alguno de los
enlaces se instala el administrador de descargas de Xilinx, es
necesario permitir la ejecución del mismo, el cual permitirá pausar
y continuar la descarga de los archivos, algo bastante útil ya que el
software pesa 5.67 GB.
4- Una vez descargado el software, es necesario obtener una licencia
de uso, se utilizará la licencia Webpack que es gratuita, como se
ha expuesto anteriormente la principal diferencia con la versión de
pago es que soporta menos dispositivos, por lo tanto para el
desarrollo de proyectos de mayor volumen no será de utilidad. En
la misma página de descargas, a la derecha de los enlaces para
descargar ISE Design Suite se encuentra el enlace “License
Solution Center”
pág. 37
Figura 13– Sección de Descargas
5- Una vez adquirido el software ISE Design Suite y la Licencia,
procedemos a instalarlo; basta con seguir los sencillos pasos y
ubicar el directorio de la licencia. Para el uso de las tarjetas de
Digilent que cuentan con conector Mini-USB como lo son la Basys2
y Nexys2 se requiere un software extra para poder realizar la
comunicación: Adept de Digilent; El software puede descargarse
de manera gratuita en el sitio web de Digilent www.digilentinc.com ,
en la sección “Software”: Digilent Adept, el paquete a descargar
para Windows es Adept 2.6.1 System, 32/64-bit. Su instalación es
muy sencilla, basta con hacer doble clic en el icono del software
descargado y seguir las instrucciones.
Con esto se tiene instalado el software necesario para el uso de la
Tarjeta Basys2.
Uso del Software ISE Design Suite 13.4, Adept 2.6.1 System y
configuración de la Tarjeta Basys2
Para explicar el uso del software ISE Design Suite 13.4, Adept 2.6.1
System, la descarga y configuración de los programas hacia la Tarjeta
Basys2 así como las bases del lenguaje de programación VHDL, se
desarrollará una práctica sencilla que servirá de guía a través de la creación,
simulación y descarga del proyecto. Iniciaremos por compuertas lógicas
pág. 38
AND, OR y XOR, y estas mismas serán utilizadas para hacer un medio
sumador y a su vez un sumador completo. A continuación se muestran todos
los pasos que se realizarán:
Se inicia por abrir ISE Project Navigator. Al iniciar el programa, carga
automáticamente el último proyecto con el cual se trabajó. Se crea un nuevo
proyecto, para ello se selecciona el menú File y después New Project, con
esto se iniciará el asistente de creación de nuevo proyecto, en la primera
ventana que se muestra habrá que indicar el nombre del proyecto, la carpeta
de trabajo del proyecto (al introducir el nombre del proyecto se indicará
automáticamente una carpeta con el mismo nombre), una descripción del
proyecto (opcional) y en la parte inferior se tiene que indicar el tipo de archivo
fuente que será el módulo principal del proyecto, se deja en HDL.
Figura 14– Asistente de Creación de un nuevo Proyecto
A continuación se da clic en el botón Next, lo cual mostrará la ventana
Project Settings, donde se indica el modelo del dispositivo utilizado en el
proyecto, además de las herramientas a utilizar para las diferentes etapas del
diseño. Para el uso de la Tarjeta Basys2, las opciones necesarias son las
mostradas en la Figura 15.
pág. 39
Figura 15– Opciones de Configuración de Tarjeta Basys2
Una vez indicadas las opciones adecuadas, se hace clic en el botón
Next, se mostrará un resumen del proyecto, finalmente se da clic en el botón
Finish y se creará el proyecto nuevo, todavía sin ningún archivo fuente
agregado, solamente se verá el nombre del archivo de proyecto en la parte
superior y en la ventana Hierarchy dentro del panel Design el dispositivo
seleccionado.
Ahora se procede a agregar un nuevo archivo fuente al proyecto, esto
se realizará utilizando el menú Project => New Source…, con lo que
aparecerá una ventana donde se debe indicar el tipo de módulo que se
desea agregar al proyecto, se selecciona VHDL Module y como nombre del
programa compuerta_and. Es importante que esté seleccionada la opción
Add to Project. Observe la Figura 16.
pág. 40
Figura 16 – Ventana New Source Wizard
Después se da clic en el botón Next lo cual mostrará la ventana
Define Module, aquí se deben indicar las características del módulo; el
nombre de la entidad, el nombre de la arquitectura y las entradas y salidas
con las que contará. Se debe tener algo como lo mostrado en la Figura 17.
Figura 17 – Ventana Define Module
pág. 41
A continuación se da clic en el botón Next, con lo que se mostrará un
resumen del nuevo archivo fuente que se ha agregado al proyecto. Por
último se da clic en el botón Finish para que se agregue la nueva fuente al
proyecto, se abrirá la ventana del editor donde se cargará el contenido del
nuevo archivo compuerta_and.vhd (el nombre indicado para el nuevo
archivo fuente con la extensión .vhd que corresponde a un módulo VHDL)
Analice el código que se presenta al terminar de crear la nueva fuente
del proyecto; la primera sección que se aprecia con dos guiones al inicio, es
código predefinido que ISE Project Navigator inserta al inicio de cada módulo
que se agrega a un proyecto, se puede notar que todas las líneas en esta
primera sección inician con un par de guiones “–”: al igual que en los
lenguajes de programación de software, VHDL permite insertar comentarios
en el código, los cuales se indican mediante esos dos guiones, todo el texto
que siga a estos guiones se toma como un comentario.
---------------------------------------------------------------------------------- Company:
-- Engineer:
--- Create Date:
15:11:22 05/10/2012
-- Design Name:
-- Module Name:
compuerta_and - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--- Dependencies:
--- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
---------------------------------------------------------------------------------Código 1 – Código Predefinido por ISE Project Navigator
Mas adelante se tiene el siguiente código:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
Código 2– Librerías utilizadas en el programa
La instrucción library permite indicar una biblioteca externa de la cual
se desee utilizar sus tipos de datos, operadores y algunas otras
declaraciones; sería equiparable a la instrucción #include de los lenguajes C
pág. 42
y C++. De manera similar a estos lenguajes, VHDL termina cada instrucción
con punto y coma: “;”.
Después se tiene una instrucción use, que permite indicar qué
paquete se va a utilizar de la biblioteca que antes se había declarado con
library. En este caso, se indica que se va a hacer uso de la biblioteca IEEE,
que es una biblioteca estándar definida por el Institute of Electrical and
Electronics Engineers, seguido de use se tiene STD_LOGIC_1164 lo cual
hace referencia al paquete de la biblioteca que se utilizará y por ultimo se
indica que de ese paquete se utilizaran todas sus declaraciones por medio
de la instrucción ALL.
Cabe mencionar que VHDL es un lenguaje que no distingue
minúsculas de mayúsculas.
Entidad y Arquitectura
En VHDL, cada módulo está compuesto por dos partes: la entidad y la
arquitectura. La entidad es la sección donde se indican las conexiones
(señales) del módulo con el resto de componentes, se indican el número de
entradas y salidas, además del tipo de cada una de ellas. La sintaxis de
declaración de entidad y de sus conexiones es la siguiente:
entity NOMBRE_ENTIDAD is
port (
NOMBRE_SEÑAL1 : MODO TIPO;
NOMBRE_SEÑAL2 : MODO TIPO
);
end NOMBRE_ENTIDAD;
Código 3– Sintaxis de la Entidad
En primer lugar se indica el nombre de la entidad, utilizando la palabra
reservada entity, y después de la instrucción is se inicia la descripción de la
entidad, en este caso de las señales o puertos mediante los cuales se
comunicará con el exterior; para cada señal se indica su nombre, el modo
(entrada, salida o ambos) y el tipo. Notese que las declaraciones de puertos
finalizan con punto y coma, excepto la última antes del paréntesis que
culmina la instrucción port.
Por lo tanto, continuando con el módulo, ISE Project Navigator ha
insertado el código mostrado en el recuadro de código 4:
entity compuerta_and is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
pág. 43
s : out
end compuerta_and;
STD_LOGIC);
Código 4 – Entidad Compuerta_and
La entidad cuyo nombre es compuerta_and, tiene tres puertos, todos
de tipo std_logic, los dos primeros denominados a y b, son entradas (in),
mientras que el tercero, denominado s, es una salida (out), el diagrama
esquemático de la entidad creada se puede representar de la siguiente
manera:
Figura 18 – Diagrama esquemático compuerta_and
De cierta forma, se considera la declaración de la entidad como una
“caja negra”, para la cual se conocen sus entradas y salidas, pero no su
funcionamiento interno, el cual se describe en la arquitectura.
La arquitectura es la sección de un módulo VHDL en la que se
describe el funcionamiento de la entidad, y puede hacerse de dos maneras
diferentes: describiendo su estructura interna mediante interconexiones entre
compuertas y componentes que constituyen al módulo, lo que se denomina
una descripción estructural, o con una descripción de lo que hace el módulo,
ya sea mediante funciones booleanas o mediante una descripción
algorítmica, lo que se conoce como una descripción de comportamiento. La
sintaxis para declarar una arquitectura es mostrada en el recuadro de código
5.
architecture NOMBRE_ARQUITECTURA of NOMBRE_ENTIDAD is
-- Aquí se declaran elementos auxiliares para usar en la descripción
begin
-- Aquí se realiza la descripción de la arquitectura,
-- mediante la utilización de sentencias secuenciales,
pág. 44
-- combinacionales o subprogramas.
end NOMBRE_ARQUITECTURA;
Código 5– Sintaxis de la Arquitectura
Como se puede observar se utiliza la instrucción architecture para
iniciar la declaración de la arquitectura, después se indica su nombre y el
nombre de la entidad a la cual corresponde la descripción que se realizará,
se continua con la instrucción begin para indicar el inicio del código que
describe el funcionamiento de la arquitectura, y finaliza con la instrucción end
seguido del nombre de la arquitectura. Entre las instrucciones is y begin, es
posible declarar señales, componentes o elementos auxiliares para la
descripción de la arquitectura, algunos de estos elementos se verán más
adelante.
ISE Project Navigator nos crea la plantilla de la arquitectura, para que
el programa compuerta_and funcione se debe describir su comportamiento;
para lo cual se agrega después de la instrucción begin lo que se desea que
haga el programa. El resultado se muestra en el recuadro de código 6.
architecture behavioral of compuerta_and is
begin
s <= a and b;
end behavioral;
Código 6– Arquitectura compuerta_and
Con esto, se asigna el resultado de la operación and entre las señales
de entrada a y b a la señal de salida s. Como se observa, la pareja de
caracteres “<=" son el operador de asignación de señales en VHDL, también,
se hace uso del operador and, que realiza la operación lógica AND entre sus
dos operandos. Además del operador and, en VHDL se tienen definidos los
siguientes operadores lógicos: or, nand, nor, xor y xnor. Finalmente, se
termina la instrucción con un punto y coma.
Una vez que se ha adicionado este código al módulo, se procede a
guardar los cambios realizados usando el comando Save dentro del menú
File o pulsando en el botón con icono de un disco flexible en la barra de
herramientas. Para comprobar que no se han cometido errores en el código
del módulo, se debe realizar una revisión de sintaxis, para ello, en la ventana
Hierarchy, se da clic en el nombre del módulo (compuerta_and), después,
en la ventana Processes, se expande la sección Synthesize – XST, de
manera que se pueda ver el proceso Check Syntax tal y como se muestra
en la figura 19.
pág. 45
Figura 19– Revisión de Sintaxis
Para iniciar la revisión de sitanxis del código, se hace doble clic sobre
el nombre del proceso o con un clic derecho y luego seleccionando el
comando Run del menú contextual. Se puede observar el resultado del
proceso de revisión de sintaxis en la parte inferior del programa en la
ventana de resultados.
Figura 20– Resultado del Chequeo de Sintaxis
Al terminar el proceso, un icono con una palomita blanca indica que la
revisión de sintaxis ha concluido exitosamente pues no se encontraron
errores en el código.
pág. 46
Con esto se ha revisado el código del módulo, resta comprobar que
funcione correctamente, para ello se puede realizar una simulación antes de
proceder a la implementación en un dispositivo reconfigurable.
Simulación
Analicemos cómo realizar una simulación del componente
compuerta_and. En primer lugar, dentro de Project Navigator, en la sección
Design, en la opción View, se selecciona Simulation:
Figura 21 – Simulación
A continuación, dentro de la ventana Hierarchy, se selecciona el
componente que se desea simular, al hacerlo cambiarán las opciones
disponibles en la ventana Processes, en este caso se muestra ISim
Simulator, se da clic en el signo “+” a la izquierda de ISim Simulator con lo
que se mostrarán dos procesos: Behavioral Check Syntax y Simulate
Behavioral Model
pág. 47
Figura 22– Ventana Processes ISim Simulator
Este último proceso es el que permitirá realizar la simulación, se hace
doble clic en Simulate Behavioral Model y se espera a que inicie ISim.
Figura 23– Ventana ISim Simulator
ISim muestra por defecto cuatro ventanas o secciones, una en la parte
inferior y tres en el medio: Instances and Processes, muestra las entidades,
bibliotecas y procesos existentes en el módulo; Objects, despliega una lista
de los puertos que forman parte del módulo, indicando con un pequeño icono
con la letra I aquellos que son entradas y con la letra O los que son salidas; y
la ventana de simulación, donde se despliegan nuevamente los puertos del
pág. 48
módulo con líneas de tiempo que permitirán visualizar el comportamiento de
cada uno de dichos puertos para cada instante de la simulación.
La tabla de verdad de una compuerta AND de dos entradas se
muestra en la Tabla 6.
b
a
s
0
0
1
1
0
1
0
1
0
0
0
1
Tabla 6 – Tabla de verdad compuerta AND
Se tienen cuatro combinaciones posibles de valores para las entradas
a y b, para comprobar el funcionamiento del módulo es conveniente simular
estos cuatro casos; para ello, se asignan valores a las entradas de manera
que se tengan las cuatro combinaciones posibles y se pueda evaluar el valor
que toma la salida para cada una de ellas.
Se inicia por la primera combinación, cuando ambas entradas valen 0,
para indicar que una entrada tendrá el valor 0 en el simulador, se da clic con
el botón derecho del ratón sobre dicha entrada en la ventana de simulación,
del menú que se despliega se selecciona la opción Force Constant…
Aparecerá la ventana Force Selected Signal; en la opción Force to
Value: escribiremos un 0 como se muestra en la Figura 24. Se hace clic en el
botón OK.
Se repiten estos pasos para la señal de entrada b: se hace clic con el
botón derecho sobre el nombre de la entrada en la ventana de simulación, se
selecciona la opción Force Constant…, y se establece a 0 la opción Force
to Valué: se da clic en el botón OK.
Al hacer esto no se nota ningún cambio en la ventana de simulación
una vez que se han indicado los valores de 0 para las dos señales, estos se
notarán hasta que se ejecute la simulación. Para ello se hará uso de la barra
de herramientas de ISim.
pág. 49
Figura 24 – Ventana Force Selected Signal
Se da clic en el botón que tiene como icono una punta de flecha y un
reloj de arena, esto ejecuta la simulación por un tiempo determinado, el cual
se indica a la derecha del botón; en este caso, 1 us, la ventana de simulación
ahora muestra lo que se observa en la figura 25.
Figura 25 – Resultado Simulación Valor 1
Como se puede observar, los valores en la columna Value han
cambiado de U a 0, la U indica valor desconocido, que era el caso antes de
iniciar la simulación, ahora que se ha simulado por un tiempo de 1us, las
entradas se encuentran en valores de 0, que fue como se “forzó”, además la
señal de salida s también tiene el valor de 0, esta no se forzó, sino que toma
el valor especificado en el módulo: la operación AND entre las
entradas a y b, que en este caso es 0.
Ahora, cambie el valor de la entrada a por 1, para evaluar el segundo
caso de la tabla de verdad de la operación AND de dos entradas, se hace
clic con el botón derecho sobre el nombre de la señal y se selecciona el
comando Force Constant nuevamente; en esta ocasión se establecerá un 1
en la opción Force to value. Se hace clic en el botón para ejecutar la
pág. 50
simulación por cierto tiempo, lo que nos mostrará algo como lo que se tiene
en la Figura 26.
Figura 26– Resultado Simulación Valor 2
La columna Value ha cambiado a 1 para el caso de la señal a,
además, en la ventana de tiempo la línea verde a la derecha de la misma
señal se encuentra más arriba y ahora con una zona sombreada debajo, esto
indica que durante ese tiempo la señal se encuentra en un estado alto (1). La
señal de salida s se mantiene en 0, que es correcto debido a que solamente
cambiará de estado cuando ambas entradas sean 1. Ahora simule el tercer
caso de la tabla de verdad, cuando a vale 0 y b vale 1.
Figura 27– Resultado Simulación Valor 3
Como se puede observar en la figura 27 la señal se mantiene en alto
durante el tiempo de la simulación, pero la salida s se mantiene en 0. Por
último simule el caso cuando ambas entradas valen 1.
pág. 51
Figura 28– Resultado Simulación Valor 4
Observe en la figura 28 como finalmente la salida s ha cambiado a 1,
lo cual corresponde con la tabla de verdad de la operación AND, de esta
forma se ha comprobado que el componente funciona correctamente.
Cabe mencionar que en cada paso, en la ventana de simulación
apareció a la derecha un valor con letras amarillas que cambió de 1,000,000
ns a 2,000,000 ns en el primer tiempo de simulación, y así hasta llegar a
5,000,000 ns. Esto indica que entre cada paso se avanzó 1 us, que es el
tiempo que se configuró en la barra de herramientas.
Para poder visualizar la simulación completa se hace clic en el
botón Zoom to Full View; la simulación completa se observa en la figura 29
donde se pueden ver los cuatro pasos de simulación ejecutados, los cuales
corresponden a la tabla de verdad de la compuerta AND.
Figura 29– Resultado de Simulación Completa
A continuación, se agregarán un par de componentes más: una
compuerta OR y otra XOR. Cierre ISim y vuelva a ISE Project Navigator.
Desde el menú Project seleccie New Source, o también puede hacer
clic con el botón derecho sobre el nombre del proyecto o del dispositivo para
el cual está destinado, donde de igual manera aparece la opción New
Source.
Agrege
un
módulo
VHDL
y
como
nombre
de
archivo compuerta_or, enseguida haga clic en el botón Next.
La ventana Define module debe quedar como se muestra en la figura
30.
pág. 52
Figura 30 – Define Module Compuerta_or
Haga clic en el botón Next y después en Finish, con lo cual se
obtendrá el nuevo módulo compuerta_or en la ventana Hierarchy, en el
editor se mostrará el código generado por Project Navigator.
El código de la arquitectura deberá ser el mostrado en el recuadro de
código siguiente:
architecture Behavioral of compuerta_or is
begin
s <= a or b;
end Behavioral;
Código 7 – Arquitectura compuerta_or
El siguiente paso es revisar la sintaxis del módulo creado, se debe
seleccionar la opción Implementation en la ventana Design, después
seleccionar el módulo compuerta_or y en la ventana de procesos hacer
doble clic en Check Syntax, si hubo algún problema se indicará en la
consola ubicada en la parte inferior.
pág. 53
Figura 31– Chequeo de Sintaxis Compuerta_or
Como se puede observar en la figura 31 no se tiene ningún error de
sintaxis, por lo que ahora se prosigue a hacer la simulación del módulo.
En Project Navigator, sección Design, pase View a Simulation,
enseguida se selecciona el componente compuerta_or y por último en la
ventana Processes haga doble clic en Simulate Behavioral Model.
Nuevamente se abre ISim Simulator, y de manera similar a la
simulación del módulo compuerta_and, se evaluarán las cuatro
combinaciones posibles según la tabla de verdad de la operación OR para
dos entrada:
b
a
s
0
0
1
1
0
1
0
1
0
1
1
1
Tabla 7– Tabla de verdad compuerta OR
Haga clic con el botón derecho sobre la entrada a en la ventana de
simulación, pero en esta ocasión no se utilizará el comando Force Constant,
sino el comando Force Clock, lo cual desplegará una ventana como la
mostrada en la figura 32.
pág. 54
Figura 32– Ventana Define Clock
El comando Force Clock permite indicar que una entrada tendrá
valores alternados entre 0 y 1 durante la simulación, es decir, como una
señal de reloj. En la ventana Define Clock se defininen algunas opciones
como el periodo, ciclo de trabajo y el valor del primer pulso, para el caso de
esta simulación, se configura Leading Edge Value a 0 y Trailing Edge
Value a 1, mientras que Period será de 100 ns, tal y como se muestra en la
figura 33.
Figura 33 – Configuración Define Clock
pág. 55
Haga clic en OK y configure de manera similar la entrada b, pero
variando el periodo a 200 ns
Hecho esto se ejecuta la simulación por un tiempo determinado; por
defecto 1 us, se da clic en el botón Run for the time specified on the
toolbar y después en el botón Zoom to Full View, el resultado es mostrado
en la siguiente figura.
Figura 34 – Resultado Simulación compuerta_or
En la figura 34 se observan algunos cambios de valor entre 0 y 1 de
las señales de entrada a y b, los suficientes para evaluar las cuatro
combinaciones diferentes de la tabla de verdad de la compuerta OR. Estas
transiciones se consiguen al usar la opción Force Clock para las
señales a y b, además, notese que al configurar el periodo de la señal b
como el doble con respecto al periodo de la señal a, las transiciones
corresponden de manera exacta con las de la tabla de verdad.
Por último practique creando el módulo de la compuerta XOR. Para
agregar el módulo, siga los mismos pasos que con los módulos anteriores.
Después de haber creado el modulo, chequee la sintaxis, y prosiga a la
simulación; para comprobar la simulación obsérvese la tabla de verdad de la
compuerta XOR.
b
a
s
0
0
1
1
0
1
0
1
0
1
1
0
Tabla 8– Tabla de Verdad Compuerta XOR
Diseño Estructural en VHDL
Una de las características más potentes del lenguaje VHDL, es la
posibilidad de utilizar los módulos que se han desarrollado para construir
módulos más grandes, es decir, un módulo VHDL puede convertirse
en componente de otro módulo, de esta forma se reutilizan o aprovechan
pág. 56
módulos ya diseñados con anterioridad, o se puede dividir un diseño
complejo en varios diseños más simples.
Utilizar módulos VHDL para construir otros módulos se
denomina diseño estructural, que difiere del diseño por comportamiento
que se ha utilizado en la creación de las compuertas AND, OR y XOR.
Se aprovecharán dos de los componentes que se han creado hasta
este momento para crear un componente nuevo: Un Medio Sumador.
Como primer paso observe la tabla de verdad de un medio sumador el
cual cuenta con un par de entradas (A y B) y un par de salidas: suma (S) y
acarreo (C):
B
A
C
S
0
0
1
1
0
1
0
1
0
0
0
1
0
1
1
0
Tabla 9: Tabla de Verdad Medio Sumador
Expresado en ecuaciones booleanas:
C= A·B
S= A⊕B
Se utilzarán como componentes los módulos compuerta_and y
compuerta_xor para crear un nuevo módulo llamado medio_sumador. Por
lo tanto agrege un nuevo módulo llamado medio_sumador, en el asistente
indique cuatro señales, dos entradas (A y B) y dos salidas (C y S) como se
muestra en la figura 35.
Se finaliza con el asistente y para obtener el código creado
por Project Navigator.
Antes de utilizar un componente, es necesario declararlo, esta
declaración se realiza en el código de la arquitectura, entre la declaración del
nombre de arquitectura y la instrucción begin, se incluye el nombre de la
entidad que se utilizará como componente, además de la declaración de sus
señales (mediante la instrucción port), la sintaxis es la mostrada en el
recuadro de Código 8.
pág. 57
Figura 35– Modulo Medio Sumador
architecture NOMBRE_ARQUITECTURA of NOMBRE_ENTIDAD is
component NOMBRE_ENTIDAD_COMPONENTE
port(
NOMBRE_SEÑAL1: DIRECCIÓN TIPO;
NOMBRE_SEÑAL2: DIRECCIÓN TIPO
);
end component;
begin
end NOMBRE_ARQUITECTURA;
Código 8 – Sintaxis declaración de componente.
La instrucción port dentro de la declaración del componente es
prácticamente una copia de las señales que se declaran en el código de
entidad del módulo que se usa como componente. Por ejemplo, la
declaración de componente del módulo compuerta_and sería la siguiente:
component compuerta_and is
port(
a : in std_logic;
b : in std_logic;
s : out std_logic
);
end component;
Código 9– Declaración component compuerta_and
pág. 58
Con este ejemplo ya se pueden agregar las declaraciones de los
componentes
compuerta_and y compuerta_xor en
el
módulo medio_sumador.
architecture behavioral of medio_sumador is
component compuerta_and is
port(
a : in std_logic;
b : in std_logic;
s : out std_logic
);
end component;
component compuerta_xor is
port(
a : in std_logic;
b : in std_logic;
s : out std_logic
);
end component;
begin
end behavioral;
Código 10– Declaración de componentes para medio_sumador
Ya se han declarado los componentes, ahora se debe hacer uso de
ellos, esto se hace mediante una instanciación de componente, en la que
se indica el componente del cual se crea una instancia y las conexiones de
sus señales, esta es la sintaxis:
ETIQUETA: NOMBRE_COMPONENTE port map( CONEXION1, CONEXION2 );
Código 11– Sintaxis Instanciación de componentes
La etiqueta es obligatoria, permite identificar entre diferentes
instanciaciones del mismo componente. La etiqueta va seguida del nombre
del componente y después se indican las conexiones de las señales del
componente, es decir, se indica con qué entradas, salidas o señales
auxiliares se conectarán las señales que forman parte de la interfaz del
componente. Para el caso del medio sumador, las entradas A y B se
conectarán con las entradas a y b de ambas compuertas, mientras que la
salida del módulo compuerta_and se conectará con la señal de salida C y la
salida del módulo compuerta_xor con la señal de salida S.
pág. 59
ACARREO: compuerta_and port map( A, B, C );
SUMA: compuerta_xor port map( A, B, S );
Código 12 – Instanciación compuerta_and y compuerta_xor
De esta forma, el código final del módulo medio_sumador es el
siguiente:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity medio_sumador is
port(
A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC;
S : out STD_LOGIC
);
end medio_sumador;
architecture behavioral of medio_sumador is
component compuerta_and is
port(
a : in std_logic;
b : in std_logic;
s : out std_logic
);
end component;
component compuerta_xor is
port(
a : in std_logic;
b : in std_logic;
s : out std_logic
);
end component;
begin
ACARREO: compuerta_and port map( A, B, C );
SUMA: compuerta_xor port map( A, B, S );
end behavioral;
Código 13 – Programa completo Medio_sumador
Al guardar el código del módulo medio_sumador, la jerarquía de
archivos del proyecto cambia.
pág. 60
Los módulos compuerta_and y compuerta_xor aparecen anidados
dentro del módulo medio_sumador, indicando que se están utilizando como
componentes de este, además, se muestran las etiquetas que se han
utilizado para instanciar los componentes.
Córrase la sintaxis para observar que este bien estructurado el módulo
de medio_sumador.
Figura 36 – Chequeo de Sintaxis medio_sumador
El resultado de la simulación se muestra en la figura 37.
Figura 37– Simulación medio_sumador
pág. 61
De manera similar a la creación del medio_sumador, elabore un
sumador_completo para demostrar las ventajas del diseño estructural y
como teniendo los módulos hechos se pueden realizar diseños de mayor
tamaño muy fácilmente.
La construcción de un sumador_completo de un bit a partir de dos
medios sumadores y una compuerta OR se muestra en la figura 38.
Figura 38 – Diagrama esquemático sumador completo
Agregue un nuevo módulo VHDL al proyecto, el cual se llamará
sumador_completo,
tendrá
tres
entradas:
EntradaA, EntradaB y Cin (acarreo de entrada), y dos salidas: Suma
y Cout (Acarreo de salida).
Agregue la declaración de los componentes que serán utilizados:
medio_sumador y compuerta_or, de manera que quede algo como lo
expuesto en el recuadro de código 14.
architecture behavioral of sumador_completo is
component medio_sumador
port(
A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC;
S : out STD_LOGIC
);
end component;
component compuerta_or
port (
a : in std_logic;
b : in std_logic;
s : out std_logic
pág. 62
);
end component;
begin
end behavioral;
Código 14– Declaración medio_sumador y compuerta_or
Hecho esto toca realizar la instanciación de los componentes e indicar
sus conexiones, no debe haber ningún problema para la conexión de las
señales del módulo sumador_completo (EntradaA, EntradaB, Cin, Suma y
Cout), pero seguro habrá duda sobre cómo realizar las conexiones entre los
componentes, por ejemplo, ¿cómo indicamos que la salida S del primer
medio sumador debe conectarse a la entrada A del segundo? La respuesta
es: mediante señales auxiliares. Las señales auxiliares podrían ser algo afín
a variables temporales en otros lenguajes de programación (como las usadas
en los ciclos, o las usadas para permitir una mayor claridad de código), en
VHDL permiten realizar la conexión entre señales de varios componentes. En
la siguiente figura se muestran en rojo las señales auxiliares de las que se
haran uso para realizar las interconexiones de los componentes del
módulo sumador_completo.
Figura 39– Interconexión de señales auxiliares
De manera similar a los componentes, las señales deben ser
declaradas antes de poder utilizarse, y también como el caso de los
componentes, las señales auxiliares se declaran después de la línea que
indica el nombre de la arquitectura y antes de la instrucción begin. La
sintaxis para declarar una señal es la siguiente (código 15):
pág. 63
signal NOMBRE_SEÑAL : tipo;
Código 15– Sintaxis declaración de señal auxiliar
El código para agregar las señales s1, c1 y c2 al módulo es el
mostrado en el recuadro de código 16.
Signal s1 : std_logic;
signal c1, c2 : std_logic;
Código 16– Señales auxiliaries para sumador_completo
Nótese que el tipo de las señales auxiliares debe coincidir con el tipo
de las señales de los componentes con los que se desea realizar la
conexión.
A continuación se crean dos instancias del módulo medio_sumador y
una del módulo compuerta_or, y se utilizarán las señales s1, c1 y c2 para
interconectar dichas instancias.
MS0: medio_sumador port map( EntradaA, EntradaB, c1, s1 );
MS1: medio_sumador port map( s1, Cin, c2, Suma );
COR: compuerta_or port map( c1, c2, Cout );
Código 17– Instanciación sumador_completo
El código completo del módulo sumador_completo se muestra en el
recuadro de código 18.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity sumador_completo is
Port (
EntradaA : in STD_LOGIC;
EntradaB : in STD_LOGIC;
Cin : in STD_LOGIC;
Suma : out STD_LOGIC;
Cout : out STD_LOGIC
);
end sumador_completo;
architecture behavioral of sumador_completo is
component medio_sumador
port(
A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC;
S : out STD_LOGIC
pág. 64
);
end component;
component compuerta_or
port (
a : in std_logic;
b : in std_logic;
s : out std_logic
);
end component;
signal s1 : std_logic;
signal c1, c2 : std_logic;
begin
MS0: medio_sumador port map( EntradaA, EntradaB, c1, s1 );
MS1: medio_sumador port map( s1, Cin, c2, Suma );
COR: compuerta_or port map( c1, c2, Cout );
end behavioral;
Código 18 – Módulo sumado_completo
En cuanto se guarda el código, la jerarquía del proyecto se modifica
como antes ocurrió con el módulo medio_sumador.
Figura 40 – Jerarquía sumador_completo
pág. 65
Nótese que todos los módulos anteriores se han anidado dentro del
módulo sumador_completo, además de que hay dos apariciones del
módulo medio_sumador, correspondiendo con las instancias que se han
creado del mismo. A continuación se realiza una revisión de sintaxis, si no
hay problemas proceda con la simulación. Para comprobar la simulación
observe la tabla de verdad para el sumador completo de 1 bit:
Cin
EntradaB
EntradaA
Cout
Suma
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
0
0
1
0
1
1
1
0
1
1
0
1
0
0
1
Tabla 10 – Tabla de Verdad sumador_completo
Para facilitar la simulación, utilize la opción Force Clock, colocando
una frecuencia de 100 ns para EntradaA, 200 ns para EntradaB y 400 ns
para Cin. El resultado se muestra en la figura 41.
Figura 41– Simulación Sumador_completo
La figura 41 engloba todas las combinaciones de la tabla de verdad,
con lo que podemos observar que el módulo funciona correctamente.
Además, en la simulación es posible ver los valores que toman las señales
auxiliares, de forma que sea más fácil depurar y encontrar posibles errores
lógicos en el módulo.
Configuración de la Tarjeta Basys2
Después de haber revisado que el código sea el correcto y que los
módulos funcionen como se desea mediante la simulación, el siguiente paso
pág. 66
es indicar a qué pines del dispositivo lógico programable corresponderán las
entradas y salidas del módulo que se ha desarrollado.
Estas entradas y salidas deben ser asociadas con pines o puertos del
dispositivo en el que se desee implementar el diseño, de manera que se
pueda conectar el módulo con el resto del circuito que se a diseñando.
Para este diseño, se deberán conectar las tres entradas con tres
interruptores (switches), mientras que las dos salidas serán conectadas a dos
leds de la tarjeta de desarrollo, la siguiente figura indicamos a qué elemento
de la tarjeta se conectará cada puerto del módulo sumador_completo.
Cout
(M11)
Suma
(M5)
Cin
(K3)
EntradaA
(L3)
EntradaB
(P11)
Figura 42– Asignación de switches y leds sumador_completo
Como se puede observar, debajo de cada señal a conectar se
encuentra entre paréntesis una letra y un número, así es como se indican los
pines del encapsulado del dispositivo que se este configurando, en este caso
una Basys2. Una vez que se sabe a qué pin del FGPA se asociarán los
puertos del módulo, se debe indicarlo en el proyecto, para ello en primera
instancia se hace uso de la aplicación PlanAhead: se selecciona el
pág. 67
módulo sumador_completo en la ventana Design, se debe asegurar de que
esté
seleccionada
la
opción Implementation,
después,
en
la
ventana Processes, se expande la categoría User Constraints, y se hace
doble clic en el proceso I/O Pin Plannig (Plan Ahead) – Post-Synthesis.
Figura 43 – I/O Pin Planning
Espere unos instantes y se abrirá el programa PlanAhead,
probablemente antes de cargar PlanAhead se muestre un mensaje que
indica que se agregará un archivo de restricciones de usuario (UCF), a lo que
se indica que si (Yes).
pág. 68
Figura 44 – Indicación para agregar archivo UCF
Si todo ha salido correctamente se debe tener en pantalla la ventana
PlanAhead. En la parte superior se muestran dos pestañas en las cuales se
pueden ver los gráficos que representan el dispositivo que se esta por
configurar: la pestaña de la izquierda despliega los pines del FPGA en un
arreglo matricial (Package), mientras que la de la derecha representa el
dispositivo en su totalidad (Device).
Debajo de esas imágenes, se encuentra una sección con dos
pestañas: I/O Ports y Package Pins, si se selecciona I/O Ports y se
expanden las opciones All ports y Scalar ports se mostrarán los puertos
que forman parte del módulo sumador_completo, haciendo clic en uno de
ellos se pueden arrastrar hacia la imagen que representa los puertos del
dispositivo donde deberemos soltarlo estando ubicados en el pin al que se
desea asociar el puerto o también se puede hacer mediante la columna site
en la cual solo se escribe la letra y el número del pin deseado. (Figura 45)
Figura 45 – Ventana PlanAhead
pág. 69
Una vez que se han asociado todos los puertos del
módulo sumador_completo con pines del FPGA. Haga clic en el botón para
guardar el diseño de Plan Ahead y cierre para continuar en ISE Project
Navigator. Nótese que un nuevo archivo se ha agregado al proyecto, el
nombre de este archivo corresponde con el módulo que se va a enviar al
dispositivo reconfigurable y tendrá como extensión .ucf.
Una
vez
realizado
lo
anterior,
se
selecciona
el
módulo sumador_completo en la ventana Hierarchy, después, en la
ventana Processes haga clic con el botón derecho en Generate
Programming File, se selecciona la opción Process Properties lo cual
abrirá un diálogo en el que se deberá asegurar de 2 cosas: que en la
categoría General Options (figura 46) esté habilitada la opción Create Bit
File, y que en la categoría Startup Options (figura 47), la propiedad FPGA
Start-Up Clock esté configurada a JTAG Clock.
Figura 46– General Options
Haga clic en el botón OK para cerrar el diálogo y enseguida doble clic
en el proceso Generate Programming File (Figura 48), iniciará la creación
del archivo de configuración .bit que se descargará al FPGA. Si el proceso
termina con éxito, se habrá creado el archivo sumador_completo.bit dentro
de la carpeta del proyecto.
pág. 70
Figura 47 – Startup Options
Figura 48– Generate Programming File
Ahora se procede a enviar este archivo al FPGA, para ello se utilizará
el software Adept 2.6.1 System de Digilent. Conecte la tarjeta Basys2 a un
puerto USB disponible de una computadora, Windows reconocerá que se ha
conectado un nuevo dispositivo y procederá a asociarlo con el controlador
pág. 71
adecuado. Abra el software Adept, y si la tarjeta se encuentra conectada
adecuadamente, se debe tener algo como lo que se muestra en la figura 49.
Figura 49– Software Adept 2.6.1 System
Una vez detectada la tarjeta toca configurar el FPGA: haga clic en el
botón Browse (Figura 50) a la derecha de donde aparece el dispositivo
FPGA, se abre un diálogo de Windows en el que se debe indicar el archivo
de configuración sumador_completo.bit que se generó antes en Project
Navigator.
Por último haga clic en el botón Program a la derecha del
botón Browse e inicie el proceso de carga del archivo de configuración al
FPGA. Durante la programación, un led de color rojo, que se encuentra a un
lado de los pines de alimentación externa de la tarjeta se enciende, una vez
terminado el proceso se indica si ha sido exitoso en la ventana de mensajes
de Adept, si no ha habido problemas, el FPGA ha sido configurado y se
puede probar si funciona.
Con esto se termina la explicación del desarrollo de un nuevo proyecto
y su descarga hacia la tarjeta Basys2.
pág. 72
Figura 50– Búsqueda de archivo .bit
Teniendo las bases del manejo de la tarjeta se procedió al desarrollo
de nuevas prácticas las cuales son expuestas en los resultados. El diseño de
las prácticas involucra adquisición de datos y control de procesos.
pág. 73
RESULTADOS
Desarrollo de Prácticas utilizando la Tarjeta Basys2
Las prácticas expuestas a continuación se desarrollaron con la Tarjeta
Basys2 basada en el Xilinx Spartan 3E, estas prácticas tienen como objetivo
demostrar la viabilidad del uso de la tarjeta Basys2 como arquitectura base
en el control de un proceso.
El diseño estructural con VHDL permite agregar módulos y crear
prácticas cada vez más complejas. El diseño estructural, la asignación de
pines y la descarga hacia la tarjeta se explica de forma breve en este
documento y para no extender de más las prácticas se omiten dentro del
desarrollo de las mismas.
Se recomienda tener bases del lenguaje VHDL y de electrónica digital
para comprender en su totalidad las practicas expuestas.
Practica 1 – Decoder Display
En la siguiente práctica se diseñará un Decoder para el Display de 7
segmentos de la Tarjeta Basys2. Con los switches de la tarjeta se pretende
ingresar un número binario el cual será desplegado en los leds y en el
display de 7 segmentos. El diagrama esquemático se muestra en la figura
1.1
Figura 1.1 – Esquemático Decoder_Display
En base al diagrama esquemático se declara la entidad la cual se
muestra en la figura 1.2. Notese el bus de datos utilizado en cada entrada y
salida.
pág. 74
Figura 1.2 – Asignación de Entidad
A continuación se muestra el código de la entidad creado por el ISE
Project Navigator:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity Display is
Port ( a : in
STD_LOGIC_VECTOR (3 downto 0);
Led : out STD_LOGIC_VECTOR (3 downto 0);
Sel_Disp: out STD_LOGIC_VECTOR (3 downto 0);
d : out STD_LOGIC_VECTOR (6 downto 0));
end Display;
Código 1.1 - Entidad con sus respectivas señales
Enseguida agregue el código mostrado en el recuadro de código 1.2 a
la arquitectura para que el módulo funcione correctamente.
pág. 75
architecture Behavioral of Display is
begin
-- Los Leds del Display se activan con 0
process (a) begin
case a is
when "0000" => d <= "0000001"; -- 0
when "0001" => d <= "1001111"; -- 1
when "0010" => d <= "0010010"; -- 2
when "0011" => d <= "0000110"; -- 3
when "0100" => d <= "1001100"; -- 4
when "0101" => d <= "0100100"; -- 5
when "0110" => d <= "0100000"; -- 6
when "0111" => d <= "0001111"; -- 7
when "1000" => d <= "0000000"; -- 8
when "1001" => d <= "0001100"; -- 9
when "1010" => d <= "0001000"; -- a
when "1011" => d <= "1100000"; -- b
when "1100" => d <= "1110010"; -- c
when "1101" => d <= "1000010"; -- d
when "1110" => d <= "0110000"; -- e
when "1111" => d <= "0111000"; -- f
when others => d <= "0000000";
end case;
end process;
Led <= a;
-- ANO = F12, AN1 = J12, AN2 = M13, AN3 = K14
-- El display seleccionado se enciende con valor en bajo 0
Sel_Disp <= "1010";
end Behavioral;
Código 3.2 Arquitectura terminada
El código inicia con el nombre de la arquitectura, en este caso se le
dejo el nombre que automáticamente le da el programa (Behavioral),
después de ello se inicia con un proceso con la entrada (a), y dentro del
proceso la condición case donde se incluyen los valores que la salida (d)
puede tomar, dependiendo del valor que se le asigne a la entrada (a). Al
finalizar el proceso, se agrega una línea (Led <= a;) en la cual solo se le
asigna el valor que tiene la entrada (a) a la salida (Led), esta última
corresponde a los 4 leds de la tarjeta.
Cabe mencionar que los leds de los displays se encienden con un
valor en bajo.
La última línea antes de terminar la arquitectura (Sel_Disp <= "1010";)
es para la selección del display a utilizar.
pág. 76
Para finalizar se comprueba el correcto funcionamiento del modulo
Display_7seg a través de la siguiente tabla se verdad:
a(entrada)
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
Leds
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
Display
0
1
2
3
4
5
6
7
8
9
a
b
c
d
e
f
Tabla 1.1 – Tabla de verdad Display_7seg
Compile y Pruebe el funcionamiento del Programa con la Tarjeta
Basys2.
Practica 2 - Contador Ascendente
En esta práctica se diseñará un contador ascendente. Para que un
contador funcione se necesita un generador de pulsos (reloj), y en este caso
será utilizado el reloj de la tarjeta Basys2, recuerde que el reloj de la tarjeta
es de 50 Mhz lo que significa un problema ya que el ojo humano es incapaz
de ver pulsos a esa velocidad, es por ello que dentro del proyecto será
necesario hacer un reloj más lento que el de la tarjeta; a continuación se
describe paso a paso el desarrollo del proyecto.
Se inicia creando un nuevo proyecto, con el nombre de
contador_ascendente y la entidad contadorAD que cuenta con las
entradas clk y reset y la salida Q de 4 bits.
El código de la entidad se muestra en el recuadro de código 2.1
pág. 77
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
entity contadorAD is
Port ( clk : in STD_LOGIC;
reset:in std_logic;
Q : out STD_LOGIC_VECTOR (3 downto 0));
end contadorAD;
Código 2.1 - Entidad contadorAD
Se declara una señal auxiliar auxiliar en la arquitectura:
signal aux : std_logic_vector( 3 downto 0 );
Esta señal aux sustituye a la señal Q dentro de la arquitectura debido
a que la señal Q es una salida (out), y no se puede leer una salida.
Se utilizarán otras dos señales auxiliares para el diseño del reloj a baja
frecuencia.
signal divisor : std_logic_vector( 24 downto 0 );
signal reloj_lento : std_logic;
Código 2.2 - Declaración de señales auxiliares
La primera señal como se puede observar en el recuadro de código
2.2 es un vector de 24 bits que permite dividir la frecuencia de 50MHZ del
reloj de la tarjeta Basys2; la segunda señal será el reloj a baja frecuencia que
se utilizará para el contador.
Después de haber declarado las señales auxiliares, se iniciará un
proceso con las señales de reloj_lento y reset, este proceso será el que
realizará el conteo ascendente, el código del proceso se muestra a
continuación:
pág. 78
begin
-- Proceso que lleva la cuenta de 4 bits
process( reloj_lento, reset )
begin
if reset = '1' then
aux <= "0000";
elsif reloj_lento'event and reloj_lento = '1' then
aux <= aux + 1;
end if;
end process;
Q <= aux;
Código 2.3 - Proceso contador ascendente
Como se observa en el código 2.3 se inicia con un begin después de
haber declarado las señales auxiliares, este begin indica el inicio de la
arquitectura; después de eso sigue la declaración de un proceso con las
señales: reloj_lento y reset, a continuación se encuentra un nuevo begin el
cual indica el inicio del proceso, enseguida se tiene una sentencia if para el
reset, con la cual cada que reset tome el valor de ‘1’ la señal aux toma el
valor de “0000”, después continua con la sentencia elsif, en la cual se indica
que cada vez que reloj_lento tenga un flanco de subida la señal aux se
incrementará en 1.
Enseguida se le asigna el valor de la señal aux a la señal Q la cual es
la salida que se mostrará en los leds.
Ahora lo único que falta es el proceso para el reloj_lento, el cual es
mostrado continuación:
-- Contador auxiliar que corre con el cristal de la tarjeta (50 MHz)
-- permite reducir la frecuencia
process( clk, reset )
begin
if ( reset = '1' ) then
divisor <= ( others => '0' );
elsif clk'event and clk = '1' then
divisor <= divisor + 1;
end if;
end process;
-- Tomamos el bit más significativo del contador auxiliar para
-- dividir la frecuencia de operación
reloj_lento <= divisor( 24 );
Código 2.4 - Proceso para crear un reloj lento
pág. 79
Para el reloj lento se diseñó un contador ascendente, solo que esta
vez se utilizó el reloj de la tarjeta y se incrementó en 1 el valor de la señal
divisor en cada flanco de subida de clk, por lo tanto contará hasta llegar al
valor máximo el cual es 2^ 24, debido a que la señal es de 24 bits. Teniendo
este contador solo basta con asignar el bit más significativo de la señal
divisor a la señal reloj_lento, esto se observa en la última línea del código
anterior (reloj_lento <= divisor( 24 );). El código completo se muestra en el
recuadro de código 2.5.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
entity contadorAD is
Port ( clk : in STD_LOGIC;
reset:in std_logic;
Q : out STD_LOGIC_VECTOR (3 downto 0));
end contadorAD;
architecture Behavioral of contadorAD is
signal aux : std_logic_vector( 3 downto 0 );
signal divisor : std_logic_vector( 24 downto 0 );
signal reloj_lento : std_logic;
begin
-- Proceso que lleva la cuenta de 4 bits
process( reloj_lento, reset )
begin
if reset = '1' then
aux <= "0000";
elsif reloj_lento'event and reloj_lento = '1' then
aux <= aux + 1;
end if;
end process;
Q <= aux;
-- Contador auxiliar que corre con el cristal de la tarjeta (50 MHz)
-- permite reducir la frecuencia
process( clk, reset )
begin
if ( reset = '1' ) then
divisor <= ( others => '0' );
elsif clk'event and clk = '1' then
divisor <= divisor + 1;
end if;
end process;
-- Tomamos el bit más significativo del contador auxiliar para
-- dividir la frecuencia de operacion
reloj_lento <= divisor( 24 );
pág. 80
end Behavioral;
Código 2.5 - Módulo contadorAD
Finalmente se hace un chequeo de sintaxis, si no hay algún error, se
asignan lo pines, se crea el archivo .bit y se descarga a la tarjeta Basys2 por
medio del software Adept para probar el programa.
Cabe mencionar que la velocidad del reloj_lento depende del número
de bits que se le asignen a la señal auxiliar divisor.
Practica 3 - Contador con salida a Display
A continuación se diseñará un contador ascendente como el de la
Practica 2 y se desplegará el resultado de la cuenta en los Displays de 7
segmentos de la tarjeta Basys2.
Se crea un nuevo proyecto y un módulo VHDL con el nombre
cont_display.
entity cont_display is
Port ( clk : in STD_LOGIC;
reset:in std_logic;
sal : out STD_LOGIC_VECTOR (6 downto 0));
end cont_display;
Código 3.1 Entidad cont_display
Como se puede observar en el recuadro de código 3.1 la entidad es
similar a la de la práctica 2 con la diferencia que la salida es de 7 bits, esto
es debido a que se enviará el resultado de la cuenta a los displays.
Enseguida se muestra el código correspondiente a la arquitectura el
cual cuenta con un reloj a baja frecuencia y un proceso que despliega el
resultado en el display.
architecture Behavioral of cont_display is
signal divisor : std_logic_vector( 24 downto 0 );
signal reloj_lento : std_logic;
signal cuenta:integer;
begin
process (reloj_lento,reset)
begin
pág. 81
if (reset='1') then
cuenta<=0;
elsif (reloj_lento'event and reloj_lento = '1') then
cuenta<= cuenta + 1
end if;
end process;
-- Contador auxiliar que corre con el cristal de la tarjeta (50 MHz)
-- permite reducir la frecuencia
process( clk,reset )
begin
if ( reset = '1' ) then
divisor <= ( others => '0' );
elsif clk'event and clk = '1' then
divisor <= divisor + 1;
end if;
end process;
-- Tomamos el bit más significativo del contador auxiliar para
-- dividir la frecuencia de operacion
reloj_lento <= divisor( 24 );
--asiganamos las salidas al display de 7 segmentos
sal<= "0000001" when cuenta=0 else
"1001111" when cuenta=1 else
"0010010" when cuenta=2 else
"0000110" when cuenta=3 else
"1001100" when cuenta=4 else
"0100100" when cuenta=5 else
"0100000" when cuenta=6 else
"0001111" when cuenta=7 else
"0000000" when cuenta=8 else
"0001100" when cuenta=9 else
"0001000" when cuenta=10 else
"1100000" when cuenta=11 else
"0110001" when cuenta=12 else
"1000010" when cuenta=13 else
"0110000" when cuenta=14 else
"0111000";
end Behavioral;
Código 3.2 - Arquitectura cont_display
Como se observa en el recuadro de código 3.2 se utiliza una condición
when para hacer la traducción entre el valor de cuenta y el valor asignado a
la salida sal que despliega el resultado en el display.
Para probar el programa cont_display se asignan los pines a la
Tarjeta Basys2 con PlanAhead, compile y baje el programa al FPGA para
verificar su funcionamiento.
pág. 82
Practica 4 - Encendido de un motor de CD
Materiales:
-
1 Optoacoplador 2N25
1 Transistor NPN 2N2222
1 Protoboard
1 Resistor 330 Ω
1 Resistor 10K Ω
1 Relevador de 5V
Alambre telefónico
1 Motor de CD @ 5V
La tarjeta Basys2 cuenta con 4 módulos de expansión PMOD con 4
entradas/salidas cada uno. Utilizando una de estas salidas se encenderá un
motor de CD de 5V por medio de uno de los switches de la tarjeta.
Se crea un nuevo proyecto y módulo VHDL llamado encender_motor.
La entidad es mostrada en el recuadro de código 4.1
entity encender_motor is
Port ( start_stop : in STD_LOGIC;
motor : out STD_LOGIC);
end encender_motor;
Código 4.1 - Entidad encender_motor
El funcionamiento de la arquitectura es simple y es idéntico al de un
interruptor, solo se debe enviar el valor de la entrada start_stop a la salida
motor.
architecture Behavioral of encender_motor is
begin
motor <= start_stop;
end Behavioral;
Código 4.2 – Arquitectura encender_motor
Como se puede observar el módulo es bastante sencillo. Compile y
descargue el programa hacia la tarjeta Basys2 para comprobar el
funcionamiento.
pág. 83
Una vez teniendo el programa se debe hacer un acondicionamiento de
la señal de salida de la tarjeta Basys2 para que esta pueda encender el
motor. La principal dificultad radica en el hecho de que la tarjeta tiene una
salida de 3.3 V y se necesitan 5V para que el motor funcione.
Cabe mencionar que los motores de CD consumen bastante corriente
eléctrica y si se le exigue corriente de más a la Tarjeta Basys2 se puede
dañarla por siempre. Es por ello que se utiliza un opto-acoplador 2N25 el
cual es un dispositivo que aísla a la tarjeta del circuito de potencia del motor.
Además se necesita un Transistor 2N2222 en su configuración de
amplificador para activar un relevador el cual funcionará como un interruptor
para encender o detener el motor según la acción de control enviada desde
el switch de la tarjeta Basys2. Por medio de una fuente externa de 5V se
obtiene la potencia eléctrica necesaria para que el motor y el circuito externo
funcionen sin problemas.
El diagrama eléctrico del acondicionamiento de señal es mostrado en
la figura 4.1
Se arma el circuito externo en un protoboard y para probar su
funcionamiento.
Nota importante: Las tierras GND de la tarjeta Basys y del circuito
externo de acondicionamiento de señal deben estar acopladas.
Figura 4.1 – Acondicionamiento de Señal
pág. 84
Práctica 5 - Motor Reversible
Materiales:
-
3 Opto-Acoplador 2N25
1 Protoboard
3 Resistor 330 Ω
3 Resistor 1K Ω
1 Puente H SN754410
Alambre telefónico
1 Motor de CD @ 5V
Teniendo la experiencia de la práctica 4 para hacer el
acondicionamiento de señal necesario para utilizar las salidas de la Tarjeta
Basys2, se pretende en esta práctica que el Motor de CD encienda y cambie
su sentido de rotación al enviar la acción de control desde los switches de la
tarjeta.
Se inicia la práctica creando un nuevo proyecto y módulo VHDL
llamado puente_h. La entidad se muestra en el recuadro de código 5.1
entity puente_h is
Port ( start : in STD_LOGIC;
sentido : in STD_LOGIC;
s1 : out STD_LOGIC;
led_start: out std_logic;
led_sent: out std_logic;
s2 : out STD_LOGIC;
enable: out std_logic);
end puente_h;
Código 5.1 - Entidad puente_h
Como se puede apreciar en el código 5.1 se cuenta con una entrada
start, para encender o apagar el motor, una entrada sentido, para cambiar
el sentido de rotación del motor, dos salidas s1 y s2, las cuales enviarán un
pulso dependiendo del valor de la entrada sentido y otras dos salidas
led_start y led_sent para indicar que el motor está en marcha y para indicar
el sentido de rotación respectivamente, estos dos leds serán de la tarjeta.
pág. 85
Figura 5.1 – Configuración y conexión CI SN754410
Para poder controlar el sentido de rotación del motor se necesita un
puente H, en este caso como es un motor pequeño de 5 volts, se utilizará el
integrado SN754410. Este Circuito integrado es capaz de controlar el sentido
de rotación de 2 motores de CD, a la vez. El diagrama del circuito integrado
se muestra en la figura 5.1, además de los pines en los cuales debe ser
conectado el motor:
Como se puede observar en la figura 5.1 el integrado tiene dos pines
de alimentación debido a que puede controlar 2 motores, dos pines de
enable, cuatro entradas (1A, 2A, 3A y 4A) y cuatro salidas (1Y, 2Y, 3Y y 4Y),
en esta práctica se utilizarán 2 entradas y dos salidas (véase la conexión del
motor izquierdo figura 5.1).
Para diseñar el código de la arquitectura se debe saber que para que
sean activadas las salidas 1Y y 2Y, necesitamos un pulso de enable en el
pin 1, y a su vez para ser activadas estas salidas, necesitan un pulso en 1A
para activar 1Y, y un pulso en 2A para activar 2Y.
El código de la arquitectura del modulo puente_h se muestra en el
recuadro de código 5.2
architecture Behavioral of puente_h is
begin
enable<= not start;
led_start<= start;
pág. 86
process (sentido)
begin
if sentido='0' then
--SENTIDO DEL MOTOR HACIA LA IZQUIERDA
s1<= '1';
s2<='0';
led_sent <= '0';
else
--SENTIDO DEL MOTOR HACIA LA DERECHA
s1<='0';
s2<='1';
led_sent <= '1';
end if;
end process;
end Behavioral;
Código 5.2 - Arquitectura puente_h
Como se puede observar en la arquitectura el sentido de rotación del
motor se controla a través de la sentencia if que manda un pulso en alto o
bajo a las salidas s1 y s2 las cuales se conectarán al puente H en las
entradas 1A y 2A. El enable controla el encendido y apagado del motor
habilitando el chip.
Como se utilizan 3 salidas que son conectadas a un circuito externo,
son necesarios 3 opto-acopladores. El acondicionamiento de señal propuesto
se muestra en la figura 5.2.
Finalmente cheque la sintaxis, asigne pines, arme en el protoboard el
circuito externo y descargue el programa hacia la tarjeta Basys2 para
comprobar el funcionamiento.
En el siguiente enlace se muestra un video del programa funcionando
sobre la tarjeta Basys2: http://youtu.be/gWH4DcUR6oQ
pág. 87
Figura 5.2 Acondicionamiento de señal
Practica 6 – Sumador Aritmético con Salida a Display
A continuación se diseñará un Sumador de 3 bits con carry de
entrada; la salida del sumador será desplegada en los Leds de la Tarjeta
Basys2 en código binario y a su vez en los Displays de 7 Segmentos.
Para comprender mejor el diseño del programa observe el diagrama a
bloques de la figura 6.1; como se puede observar este es un diseño de tipo
estructural donde se mapea el programa de Encidende7Segmentos hacia
el Top Module (Programa Maestro) Sumador_Arith.
pág. 88
Figura 6.1 Diagrama a Bloques Sumador Aritmético
La entidad del Sumador Aritmético se muestra en el código 6.1; cabe
mencionar que dentro de la entidad se agregan las salidas de ánodos y
segmentos para realizar posteriormente el mapeo por software.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Sumador_Arith is
Port ( a : in STD_LOGIC_VECTOR (2 downto 0); -- dato "a" de 3
bits
b : in
STD_LOGIC_VECTOR (2 downto 0); -- dato "b" de 3
bits
cin : in STD_LOGIC;
reloj_tarjeta : in STD_LOGIC;
reset : in STD_LOGIC;
-- Carry in de 1 bit
segmentos : out std_logic_vector( 6 downto 0 );
-- encender display
anodos : out
std_logic_vector( 3 downto 0 );
-- multiplexar display
suma : inout STD_LOGIC_VECTOR (5 downto 0));
-- Salida
de a + b + cin
end Sumador_Arith;
Código 6.1 Entidad Sumador Aritmético
Como
se
observa
se
agregó
la
librería
IEEE.STD_LOGIC_UNSIGNED.ALL para poder realizar operaciones con
operadores aritméticos (+, - , *, /) esta es una gran ventaja ya que ahorra
código
y
facilita
la
programación.
(La
librería
pág. 89
IEEE.STD_LOGIC_UNISGNED.ALL ya no es soportada por la IEEE por lo
que se utiliza en su lugar la IEEE.NUMERIC_STD.ALL; en esta práctica se
utiliza la librería IEEE.STD_LOGIC_UNISGNED.ALL por la sencillez en el
manejo de los operadores aritméticos sin necesidad de castear el tipo de
variable.
En
practicas
posteriores
se
analizará
la
librería
IEEE.NUMERIC_STD.ALL y como castear correctamente).
Para agregar un módulo previamente hecho y mapearlo al diseño se
necesita Inicializar el componente antes del inicio de la arquitectura (código
6.2) y después mapearlo dentro de la arquitectura (código 6.3). En esta
práctica se utiliza el código Enciende7Segmentos.vhd mostrado en el
recuadro de código 6.4:
COMPONENT Enciende7Segmentos
PORT(
valor0 : IN std_logic_vector(3 downto 0);
valor1 : IN std_logic_vector(3 downto 0);
valor2 : IN std_logic_vector(3 downto 0);
valor3 : IN std_logic_vector(3 downto 0);
reloj_50MHz : IN std_logic;
reset : IN std_logic;
segmentos : OUT std_logic_vector(6 downto 0);
anodos : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
Código 6.2 Inicialización del Componente
ETI: Enciende7Segmentos PORT MAP(
valor0 =>numerobcd (3 downto 0) ,
valor1 => numerobcd (7 downto 4),
valor2 => numerobcd(11 downto 8),
valor3 => numerobcd(15 downto 12),
segmentos =>segmentos ,
reloj_50MHz => reloj_tarjeta,
reset => reset,
anodos => anodos
);
Código 6.3 Mapeo del Componente
entity Enciende7Segmentos is
Port (
valor0 : in STD_LOGIC_VECTOR (3 downto 0);
valor1 : in STD_LOGIC_VECTOR (3 downto 0);
valor2 : in STD_LOGIC_VECTOR (3 downto 0);
valor3 : in STD_LOGIC_VECTOR (3 downto 0);
segmentos : out STD_LOGIC_VECTOR (6 downto 0);
reloj_50MHz : in std_logic;
reset : in std_logic;
pág. 90
anodos : out std_logic_vector( 3 downto 0 )
);
end Enciende7Segmentos;
architecture Behavioral of Enciende7Segmentos is
signal activo : std_logic_vector( 1 downto 0 );
signal divisor : std_logic_vector( 15 downto 0 );
signal reloj_1KHz : std_logic;
signal valor_aux : std_logic_vector( 3 downto 0 );
begin
-- Proceso que genera una señal de 1 KHz a partir del cristal
-- de 50 MHz de la tarjeta de desarrollo.
process(reloj_50MHz,reset)
begin
if reset = '1' then
divisor <= (others => '0');
reloj_1KHz <= '0';
elsif reloj_50MHz'event and reloj_50MHz = '1' then
divisor <= divisor + 1;
if ( divisor = 25000 ) then
reloj_1KHz <= not reloj_1KHz;
divisor <= ( others => '0' );
end if;
end if;
end process;
-- Proceso que multiplexa los displays
process( reloj_1KHz, reset)
begin
if reset = '1' then
activo <= "00";
anodos <= "1111";
elsif rising_edge(reloj_1KHz) then
activo <= activo + 1;
case activo is
when "00"
=>
anodos
<=
"1110";
valor_aux
<=
when
"01"
=>
anodos
<=
"1101";
valor_aux
<=
when
"10"
=>
anodos
<=
"1011";
valor_aux
<=
valor0;
valor1;
valor2;
when others => anodos <= "0111"; valor_aux <=
valor3;
end case;
pág. 91
end if;
end process;
-a
----- f| g | b
----- e|
| c
----d
-- Activa los segmentos adecuados
-- Por hacer: manejar el punto decimal y ampliar a más caracteres.
with valor_aux select
segmentos <=
-- abcdefg
"1001111"
"0010010"
"0000110"
"1001100"
"0100100"
"0100000"
"0001111"
"0000000"
"0000100"
"0001000"
"1100000"
"0110001"
"1000010"
"0110000"
"0111000"
"0000001"
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
"0001",
"0010",
"0011",
"0100",
"0101",
"0110",
"0111",
"1000",
"1001",
"1010",
"1011",
"1100",
"1101",
"1110",
"1111",
others;
--1
--2
--3
--4
--5
--6
--7
--8
--9
--A
--b
--C
--d
--E
--F
--0
end Behavioral;
Código 6.4 Programa Enciende7Segmentos
Como se puede observar el Programa Enciende7Segmentos se
encarga del multiplexado de los displays para ello genera un reloj que
proporciona una señal de 1khz a partir de la señal de reloj de la tarjeta
Basys2 de 50Mhz, con esto inicia un proceso que lleva una cuenta a
velocidad de 1khz la cual se guarda en la señal activo de 2 bits cuyo
resultado multiplexea los displays de manera automática con una tasa de
refresco de 1khz/4_displays = 250Hz (T=4ms).
pág. 92
Figura 6.2 – Diagrama esquemático de los displays de 7 Segmentos de la Tarjeta Basys2
Como se puede observar en el código 6.2 para inicializar un
componente se utiliza la entidad del código VHDL previamente diseñado. La
forma general de inicializar cualquier componente se muestra en el código
6.5.
COMPONENT Nombre_del_programa
GENERIC( Variables_genericas: natural;
N : integer
);
PORT(
Entradas : IN std_logic;
Bus_Entradas : IN std_logic_vector(N downto 0);
Salidas : OUT std_logic;
Bus_Salidas : OUT std_logic_vector(N downto 0);
);
END COMPONENT;
Código 6.5 – Inicialización de componentes (Forma General)
La forma general de mapear un componente hacia otro programa se
muestra en el código 6.6
Nombre_del mapeo: Nombre_del_programa
GENERIC MAP (
Variables_genericas => ,
N => )
PORT MAP(
Entradas => ,
Bus_Entradas => , -- Después del => se ingresa el
puerto,
Salidas => ,
-- señal, constante o variable a
mapear
pág. 93
Bus_Salidas => ,
);
Código 6.6 – Mapeo de componentes (Forma General)
A continuación se muestra el código de la arquitectura del sumador
aritmético (Código 6.7) en donde se observa la inicialización del componente
Enciende7Segmentos y el Mapeo del mismo llamado ETI
architecture Behavioral of Sumador_Arith is
-- Declaración de Señales Auxiliares
signal A_aux, B_aux : STD_LOGIC_VECTOR (5 downto 0); -- Largo del
vector de 6 bits para porder hacer la suma
signal Suma_aux: STD_LOGIC_VECTOR ( 15 downto 0 ); -- Señal auxiliar
para hacer el resize
signal numerobcd : std_logic_vector( 15 downto 0 ); -- 16 bits para
encender los 4 displays
-- Llamada al archivo componente "Enciende7Segmentos"
component Enciende7Segmentos
Port (
valor0 : in STD_LOGIC_VECTOR (3 downto 0);
valor1 : in STD_LOGIC_VECTOR (3 downto 0);
valor2 : in STD_LOGIC_VECTOR (3 downto 0);
valor3 : in STD_LOGIC_VECTOR (3 downto 0);
segmentos : out STD_LOGIC_VECTOR (6 downto 0);
reloj_50MHz : in std_logic;
reset : in std_logic;
anodos : out std_logic_vector( 3 downto 0 )
);
end component;
-- Función que recibe un valor binario de 16 bits y devuelve su
representación
-- BCD de cuatro dígitos (16 bits).
-- Usa el algoritmo de corrimiento y suma 3.
function bin_a_bcd( bin : std_logic_vector(15 downto 0))
return std_logic_vector is
variable i : integer := 0;
variable resultado : std_logic_vector( 15 downto 0 ) :=
"0000000000000000";
variable copiabin : std_logic_vector( 15 downto 0 ) :=
bin;
begin
-- Aquí va el código de la función
for i in 0 to 15 loop
resultado( 15 downto 1 ) := resultado( 14 downto
0 );
resultado( 0 ) := copiabin( 15 );
copiabin( 15 downto 1 ) := copiabin( 14 downto 0
pág. 94
);
copiabin( 0 ) := '0';
-- unidades
if i < 15 and resultado( 3 downto 0 ) > "0100"
then
resultado( 3 downto 0 ) := resultado( 3
downto 0 ) + "0011";
end if;
-- decenas
if i < 15 and resultado( 7 downto 4 ) > "0100"
then
resultado( 7 downto 4 ) := resultado( 7
downto 4 ) + "0011";
end if;
-- centenas
if i < 15 and resultado( 11 downto 8 ) > "0100"
then
resultado( 11 downto 8 ) := resultado( 11
downto 8 ) + "0011";
end if;
-- millares
if i < 15 and resultado (15 downto 12) > "0100"
then
resultado ( 15 downto 12 ) := resultado ( 15
downto 12 ) + "0011";
end if;
end loop;
return resultado;
end bin_a_bcd;
-- Inicio de la Arquitectura
begin
-- Utilización de los 3 LSB de "a" y "b" para hacer una Suma con
vectores de 6 bits
A_aux (2 downto 0) <= a;
B_aux (2 downto 0) <= b;
--process (A_aux, B_aux, cin, reloj_tarjeta)
--begin
--if reloj_tarjeta'event and reloj_tarjeta = '1' then
suma <= A_aux + B_aux + cin;
--end if;
--end process;
suma_aux (5 downto 0) <= suma;
numerobcd <= bin_a_bcd(Suma_aux);
pág. 95
-- Mapeo del controlador de displays
ETI: Enciende7Segmentos port map(
valor0 =>numerobcd (3 downto 0) , -valor1 => numerobcd (7 downto 4), -valor2 => numerobcd(11 downto 8), -valor3 => numerobcd(15 downto 12),-segmentos =>segmentos ,
reloj_50MHz => reloj_tarjeta,
reset => reset,
anodos => anodos
);
unidades
decenas
centenas
millares
end Behavioral;
Código 6.7 – Arquitectura Sumador_Arith
Dentro del código de la arquitectura se puede observar la función
bin_a_bcd la cual recibe un valor binario de 16 bits y devuelve su
representación BCD de cuatro dígitos (16 bits) usando un algoritmo de
corrimiento y sumando “011”.
Recordemos que las señales auxiliares, la inicialización de los
componentes y las funciones (function nombre_de_la_función) se declaran
antes del inicio (begin) de la arquitectura.
El Sumador Aritmético se resume en “suma <= A_aux + B_aux +
cin;” donde se suma el dato A, el dato b y el Cin de manera mas simple.
La salida suma es enviada a una señal auxiliar suma_aux de 16 bits
asignándole a los 6 bits menos significativos de suma_aux los 6 bits de suma
(suma_aux (5 downto 0) <= suma); esto debido a que la función bin_a_bcd
requiere un ancho de bus de 16 bits. El resultado de la función bin_a_bcd es
asignado a la señal numerobcd de 16 bit, quedando de la siguiente manera
el casteo de la función (numerobcd <= bin_a_bcd(Suma_aux);)
Al final se mapean las señales al componente Enciende7Segmentos
utilizando los 4 bits del bus de 16 bit de la señal numerobcd necesarios de
cada display para representar las unidades, decenas, centenas y millares.
Este código será de bastante utilidad para prácticas posteriores donde se
necesite mostrar en valor BCD números binarios.
pág. 96
Practica 7 – Unidad Aritmética Lógica (ALU)
Una Unidad Aritmética Lógica es un circuito digital que calcula
operaciones aritméticas (como suma, resta, multiplicación, etc.) y
operaciones lógicas (and, or, not, sll, slr, etc), entre dos números.
A continuación se diseñará una ALU con 2 entradas de 3 bits y 2
líneas de selección que permitirán elegir entre las siguientes opciones (Tabla
7.1).
Sel
Suma (a+b)
Multiplicación (a-b)
Corrimiento a la Izq de “a”
Corrimiento a la Der de “a”
X
Y
0
0
1
1
0
1
0
1
Tabla 7.1 – Operaciones de la ALU
Se utilizará la función bin_a_bcd de la práctica anterior para mandar el
resultado de la operación hacia los displays de 7 segmentos y se utilizará el
diseño estructural para mapear el programa de Salida y multiplexeo de
displays (Disp_hex_mux.vhd) el cual es una versión mejorada del programa
Enciende7Segmentos.vhd que incluye punto decimal (DP).
Esta vez se utilizará la librería IEEE.NUMERIC_STD.ALL y se
explicará como hacer conversión entre los tipos de datos y los casteos de
salida.
El diagrama a bloques de la ALU se muestra en la figura 7.1
Figura 7.1 – Diagrama Esquemático de la ALU
pág. 97
El código del programa disp_hex_mux.vhd que será mapeado hacia el
top module ALU es mostrado en el recuadro de código 7.1
entity disp_hex_mux is
port(
clk, reset: in std_logic;
hex3, hex2, hex1, hex0: in std_logic_vector (3 downto
0);
dp_in: in std_logic_vector (3 downto 0);
an: out std_logic_vector (3 downto 0);
sseg: out std_logic_vector (7 downto 0)
);
end disp_hex_mux;
architecture Behavioral of disp_hex_mux is
constant N : integer :=18;
signal q_reg , q_next : unsigned (N-1 downto 0) ;
signal sel: std_logic_vector (1 downto 0 ) ;
signal hex: std_logic_vector (3 downto 0 );
signal dp: std_logic;
begin
-- register
process (clk, reset)
begin
if reset = '1' then
q_reg <= ( others => '0' ) ;
elsif (clk'event and clk='1') then
q_reg <= q_next;
end if;
end process;
-- next-state logic for the counter
q_next <= q_reg + 1;
-- 2 MSBs of counter to control 4-to-1 multiplexing
-- and to generate active-low enable signal
sel <= std_logic_vector (q_reg(N-1 downto N-2));
process (sel, hex0, hex1, hex2, hex3, dp_in)
begin
case sel is
when "00" =>
an <= "1110";
hex <= hex0;
dp <= dp_in(0);
when "01" =>
an <= "1101";
hex <= hex1;
pág. 98
dp <= dp_in(1);
when "10" =>
an <= "1011";
hex <= hex2;
dp <= dp_in(2);
when others =>
an <= "0111";
hex <= hex3;
dp <= dp_in(3);
end case;
end process;
-- hex-to-7- segment led decoding
with hex select
sseg (6 downto 0) <=
"0000001" when
"1001111" when
"0010010" when
"0000110" when
"1001100" when
"0100100" when
"0100000" when
"0001111" when
"0000000" when
"0001100" when
"0001000" when
"1100000" when
"1110010" when
"1000010" when
"0011000" when
"0111000" when
"0000",
"0001",
"0010",
"0011",
"0100",
"0101",
"0110",
"0111",
"1000",
"1001",
"1010",
"1011",
"1100",
"1101",
"1110",
others;
--a
--b
--c
--d
--P
--f
--decimal point
sseg(7) <= dp;
end Behavioral;
Código 7.1 – disp_hex_mux (Salida a Displays y Multiplexeo)
El código completo de la ALU se muestra en el recuadro de código
7.2; tómese en cuenta el uso de la librería IEEE.NUMERIC_STD.ALL, la
inicialización del componente disp_hex_mux y el mapeo del mismo, así como
el uso de la función bin_a_bcd.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU is
Port ( Dato_A : in STD_LOGIC_VECTOR (2 downto 0);
Dato_B : in STD_LOGIC_VECTOR (2 downto 0);
pág. 99
Sel
: in STD_LOGIC_VECTOR (1 downto 0);
clk : in STD_LOGIC;
reset : in STD_LOGIC;
segmentos : out std_logic_vector( 7 downto 0 );
Componente para encender display
anodos : out std_logic_vector( 3 downto 0 ); -Componente para multiplexar display
Salida : out STD_LOGIC_VECTOR (5 downto 0));
--
end ALU;
architecture Behavioral of ALU is
-- Declaración de Señales Auxiliares
signal a: unsigned (Dato_A'range);
signal b: unsigned (Dato_B'range);
signal Salida_aux: unsigned (Salida'range);
signal numerobcd : unsigned( 15 downto 0 );
encender los 4 displays
-- 16 bits para
--===========================================================
-- Llamada al archivo componente "disp_hex_mux"
--===========================================================
COMPONENT disp_hex_mux
PORT(
clk : IN std_logic;
reset : IN std_logic;
hex3 : IN std_logic_vector(3 downto 0);
hex2 : IN std_logic_vector(3 downto 0);
hex1 : IN std_logic_vector(3 downto 0);
hex0 : IN std_logic_vector(3 downto 0);
dp_in : IN std_logic_vector(3 downto 0);
an : OUT std_logic_vector(3 downto 0);
sseg : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
-===========================================================================
=======
-- Función que recibe un valor binario de 16 bits y devuelve su
representación
-- BCD de cuatro dígitos (16 bits).
-- Usa el algoritmo de corrimiento y suma 3.
function
bin_a_bcd(
bin
:
unsigned(15
downto
0))
return
unsigned is
variable i : integer := 0;
variable resultado : unsigned(
15
downto
0
)
:=
"0000000000000000";
pág. 100
variable copiabin : unsigned( 15 downto 0 ) := bin;
begin
-- Código de la función
for i in 0 to 15 loop
resultado( 15 downto 1 ) := resultado( 14 downto
0 );
resultado( 0 ) := copiabin( 15 );
copiabin( 15 downto 1 ) := copiabin( 14 downto 0
);
copiabin( 0 ) := '0';
-- unidades
if i < 15 and resultado( 3 downto 0 ) > "0100"
then
resultado( 3 downto 0 ) := resultado( 3
downto 0 ) + "0011";
end if;
-- decenas
if i < 15 and resultado( 7 downto 4 ) > "0100"
then
resultado( 7 downto 4 ) := resultado( 7
downto 4 ) + "0011";
end if;
-- centenas
if i < 15 and resultado( 11 downto 8 ) > "0100"
then
resultado( 11 downto 8 ) := resultado( 11
downto 8 ) + "0011";
end if;
-- millares
if i < 15 and resultado (15 downto 12) > "0100"
then
resultado ( 15 downto 12 ) := resultado ( 15
downto 12 ) + "0011";
end if;
end loop;
return resultado;
end bin_a_bcd;
-- Inicio de la Arquitectura
begin
-- Proceso de la ALU
PROCESS (a, b, Sel)
BEGIN
pág. 101
CASE Sel IS
WHEN "00" => Salida_aux <= RESIZE(a,Salida_aux'length) +
RESIZE(b,Salida_aux'length);
WHEN
"01"
=>
Salida_aux
<=
RESIZE((a
*
b),Salida_aux'length);
WHEN "10" => Salida_aux <= RESIZE((a(1 downto 0) &
a(2)),Salida_aux'length); -- Rot izq
WHEN "11" => Salida_aux <= RESIZE((a(0) & a(2 downto
1)),Salida_aux'length); -- Rot derecha
WHEN OTHERS => null;
END CASE;
END PROCESS;
--Conversión de entradas Dato_A y Dato_B a unsigned y asignación a
señales auxiliares
a <= UNSIGNED(Dato_A);
b <= UNSIGNED(Dato_B);
--Salida a Leds
Salida <= std_logic_vector (Salida_aux);
-- Conversión a BCD llamada a Función
numerobcd <= bin_a_bcd (RESIZE (Salida_aux,numerobcd'length));
--=====================================================
-- Mapeo del controlador de displays
--=====================================================
Inst_disp_hex_mux: disp_hex_mux PORT MAP(
clk => clk,
reset => reset,
hex3 => std_logic_vector (numerobcd(15 downto 12)),
hex2 => std_logic_vector (numerobcd(11 downto 8)),
hex1 => std_logic_vector (numerobcd(7 downto 4)),
hex0 => std_logic_vector (numerobcd(3 downto 0)),
dp_in => "1111",
an => anodos,
sseg => segmentos
);
end Behavioral;
Código 7.2 – ALU
Como podemos observar en el código 7.2, la selección de las
operaciones se hace con un CASE donde la entrada Sel es la referencia y
pág. 102
dependiendo del valor asignado a Sel desde los switches de la tarjeta
Basys2 se realiza la operación mostrada en la tabla 7.1.
La muestra del poder y versatilidad de VHDL se observa en la
multiplicación. Al multiplicar 2 números de 3 bits se necesita una salida de 6
bits para representar el número máximo que sería 7*7 = 49. Esto ocasiona
una discrepancia en el ancho de los vectores; para ello se llama a la función
RESIZE.
RESIZE (a, Salida_aux’lenght)
Esto quiere decir que se redimensiona a de 3 bits al ancho de la señal
auxiliar salida_aux de 6 bits; de igual forma se utiliza el RESIZE para hacer
el llamado de la función bin_a_bcd de un ancho de 6 bits a 16 bits sin
necesidad de mandar la salida_aux a otra señal auxiliar de 16 bits y
recortarla como en la práctica 6.
numerobcd <= bin_a_bcd
(RESIZE(Salida_aux,numerobcd'length));
Observe la declaración de las señales de tipo unsigned a y b; esto es
debido a que con la librería IEEE.NUMERIC_STD.ALL no se pueden hacer
implícitamente operaciones aritméticas entre vectores (std_logic_vector) de
las 2 entradas Dato_A y Dato_B.
signal a: unsigned (Dato_A'range);
signal b: unsigned (Dato_B'range);
Se asigna el contenido de Dato_A y Dato_B a las señales auxiliaries
de tipo unsigned a y b con las siguientes líneas; nótese la palabra
UNSIGNED antes de la asignación que convierte de tipo std_logic_vector a
Unsigned.
a <= UNSIGNED(Dato_A);
b <= UNSIGNED(Dato_B);
Por último analice el casteo de Salida que convierte la Salida_aux de
tipo unsigned a std_logic_vector la cual encenderá los leds de la Tarjeta
Basys2. De igual forma se hace la misma conversión en las entradas hex del
componente disp_hex_mux.vhd para encender los displays.
Salida <= std_logic_vector (Salida_aux);
pág. 103
De esta forma se hace el manejo entre entradas o salidas de tipo
std_logic_vector a señales de tipo signed o unsigned.
Para probar la ALU asigne los pines a la Tarjeta Basys2, compile y
verifique su funcionamiento. La asignación de pines se muestra en el
recuadro de código 7.3
# PlanAhead Generated physical constraints
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
NET
"Dato_A[0]" LOC = P11;
"Dato_A[1]" LOC = L3;
"Dato_A[2]" LOC = K3;
"Dato_B[0]" LOC = B4;
"Dato_B[1]" LOC = G3;
"Dato_B[2]" LOC = F3;
"Salida[0]" LOC = M5;
"Salida[1]" LOC = M11;
"Salida[2]" LOC = P7;
"Salida[3]" LOC = P6;
"Salida[4]" LOC = N5;
"Salida[5]" LOC = N4;
"Sel[0]" LOC = E2;
"Sel[1]" LOC = N3;
"anodos[0]" LOC = F12;
"anodos[1]" LOC = J12;
"anodos[2]" LOC = M13;
"anodos[3]" LOC = K14;
"reloj_tarjeta" LOC = B8;
"reset" LOC = G12;
"segmentos[0]" LOC = M12;
"segmentos[1]" LOC = L13;
"segmentos[2]" LOC = P12;
"segmentos[3]" LOC = N11;
"segmentos[4]" LOC = N14;
"segmentos[5]" LOC = H12;
"segmentos[6]" LOC = L14;
"segmentos[7]" LOC = N13;
Código 7.3 – Asignación de pines ALU
Nota: En algunos casos con la utilización de la librería
IEEE.NUMERIC_STD.ALL se requiere convertir variables, señales o
constantes de tipo integer, real, natural, etc a unsiged o signed e incluso a
std_logic_vector.
Para realizar estas conversiones tomese como referencia el siguiente
ejemplo: Se requiere desplegar en los leds de la Tarjeta Basys2 una señal de
tipo natural la cual se sumará con una señal de tipo unsigned.
Leds : out std_logic_vector (7 downto 0);
pág. 104
Signal a : natural;
Signal a_aux : unsigned (7 downto 0);
Signal b : unsigned (7 downto 0);
Primero se convierte de natural a unsigned y se asigna a una señal
auxiliar a_aux
a_aux <= to_unsigned (a, 8);
señal_destino <= to_unsigned (señal_natural, #
número_bits_destino)
Después se puede hacer la suma entre 2 señales de tipo unsigned y
después convertirla a std_logic_vector para desplegarla en la salida Leds.
Leds <= std_logic_vector (a_aux + b);
Practica 8 – Elementos de Memoria (Flip-Flops) Pulsador
Un elemento de memoria es un componente que es capaz de
memorizar (guardar) un valor. Un biestable (flip-flop o latch), es un
multivibrador capaz de permanecer en uno de dos estados posibles durante
un tiempo indefinido en ausencia de perturbaciones.
El paso de un estado a otro se realiza variando sus entradas.
Dependiendo del tipo de dichas entradas los biestables se dividen en:
-Asíncronos: sólo tienen entradas de control. El más empleado es el
biestable RS.
-Síncronos: además de las entradas de control posee una entrada de
sincronismo o de reloj. Por lo general, las entradas de control asíncronas
prevalecen sobre las síncronas.
En la siguiente práctica se encenderá un Led de la Tarjeta Basys2 con
un solo Push Button; por lo tanto cuando el Led se encuentre apagado y se
pulse el Push Button este se encenderá y por el contrario cuando el Led se
encuentre encendido este se apagará.
Para hacer esto se utilizará un Biestable T (Toggle) el cual cambia de
estado cada vez que la entrada de sincronismo de reloj se dispara mientras
la entrada T está a nivel alto. Si la entrada T está a nivel bajo, el biestable
retiene el nivel previo. El símbolo del Biestable T se muestra en la figura 8.1
pág. 105
Figura 8.1 – Flip-Flop T
Con un biestable T es suficiente para esta aplicación, pero el dedo
humano no es tan rápido como la frecuencia de reloj de la Tarjeta Basys2 de
50Mhz, por lo tanto al presionar el Push Button el tiempo de pulsación durará
muchos ciclos de reloj, y por lo tanto, el estado del biestable (Q) cambiará en
todos los ciclos de reloj que se deje presionado el botón; al soltar el Push
Button el estado final del biestable será aleatorio según se haya mantenido
pulsado el botón durante un número par o impar de ciclos de reloj.
Para solucionar este problema se debe implementar un Circuito
Detector de Flancos el cual será útil cada vez que se necesite hacer
interfaces humanas con diseños síncronos. En una señal digital, se
denomina flanco a la transición del nivel bajo al alto (flanco de subida) o de
nivel alto al bajo (flanco de bajada).
El circuito Detector de Flancos se puede realizar mediante 2 registros
de desplazamiento (Biestables D). Cuando se pulse el Push Button de la
Tarjeta Basys2 la señal será almacenada por el primer Biestable D (Reg1) y
su salida pasa al segundo Biestable D (Reg2) cuya salida es negada e
ingresada junto con la salida del Primer Biestable D (Reg1) a una compuerta
AND. Como resultado se obtendrá una salida que durará un ciclo de reloj que
servirá como entrada al Biestable T (Figura 8.2) que en vez de recibir el pulso
directamente de los Push Buttons de la Tarjeta Basys2 obtendrá una señal
filtrada de 1 ciclo de reloj que encenderá o apagará el Led según sea el caso.
Figura 8.2 – Detector de Flancos conectado a Biestable T
pág. 106
Observe la simulación del circuito Detector de flancos. Cuando la
entrada btn0 pasa de bajo a alto btn0_reg1 y btn0_reg2 lo hacen también.
Recuerde que estas 2 señales ingresan a una compuerta AND por lo tanto se
tiene una salida pulso_btn0 de 1 ciclo de reloj (Figura 8.3)
Figura 8.3 – Simulación Detector de Flancos
El código VHDL del circuito es mostrado en el recuadro de código 8.1
donde se puede observar la implementación del circuito detector de flancos
basado en Biestables tipo D y la “memoria” Biestable tipo T.
entity Pulsador_Memoria is
Port ( BTN0 : in STD_LOGIC;
Clk : in STD_LOGIC;
Reset : in STD_LOGIC;
LD0 : out STD_LOGIC);
end Pulsador_Memoria;
architecture Behavioral of Pulsador_Memoria is
signal BTN0_REG1, BTN0_REG2, PULSO_BTN0, Q_T : std_logic;
begin
--==================================================================
-- Detector de Flancos
--==================================================================
Process (Reset, Clk)
begin
if Reset = '1' then
pág. 107
BTN0_REG1
BTN0_REG2
elsif Clk'event
BTN0_REG1
BTN0_REG2
end if;
end process;
<= '0';
<= '0';
and Clk='1' then
<= BTN0;
<= BTN0_REG1;
PULSO_BTN0 <= '1' when (BTN0_REG1 = '1' and (not BTN0_REG2='1'))
else '0';
--==================================================================
-- Biestable T
--==================================================================
biest_T: Process (Reset, Clk)
begin
if Reset = '1' then
Q_T <= '0';
elsif Clk'event and Clk='1' then
if PULSO_BTN0 = '1' then –- Si el pulso del boton = ‘1’
Q_T <= NOT Q_T;
-- Enciende o Apaga.
End if;
end if;
end process;
LD0 <= Q_T;
end Behavioral;
Código 8.1 – Pulsador_Memoria
Para probar el programa Pulsador_Memoria asigne los pines a la
Tarjeta Basys2 con Plan Ahead, compile y baje el programa al FPGA para
verificar su funcionamiento.
Practica 9 – Maquinas de Estados Finitos (FSM)
Se denomina máquina de estados a un modelo de comportamiento de
un sistema con entradas y salidas, en donde las salidas dependen no solo de
las señales de entrada actuales sino también de las anteriores. Una maquina
de estados Finitos es usada para modelar sistemas que transitan a través de
un numero finito de estados internos.
El diagrama a bloques básico de una FMS (Figura 9.1) consiste de un
Registro de estado, Lógica de Estado Siguiente y Lógica de Salida. Una FSM
pág. 108
es conocida como Maquina de Moore si su salida esta en función solo del
Estado actual, y es conocida como Maquina de Mealy si su salida esta en
función del Estado Actual y una Entrada externa.
Figura 9.1 - Diagrama a Bloques de FSM
De ahora en adelante para la comprensión de los programas que
utilicen Máquinas de estados, Registros de Estado y lógica de Estado
Siguiente se utilizará:
Estado Actual => State_reg
Estado Siguiente => State_next
Para representar una FSM generalmente se utiliza un Diagrama de
Estados (State diagram) o una Tabla ASM (ASM chart – Algorithmic State
Machine chart). Ambos capturan las entradas, salidas, estados y transiciones
de la FSM en una representación gráfica.
Practica 9.1 – Encendido de Led Basado en FSM con Pulsador
En esta práctica se encenderá un Led de la Tarjeta Basys2 por medio
de un PushButton de igual forma que en la práctica 10 pero esta vez
utilizando Maquinas de Estados Finitos (FSM)
Para comprender mejor el funcionamiento observe el Diagrama de
Estados del FSM_Led
pág. 109
Push = ‘1’
Push = ‘0’
Led0 <= ‘0’
Push = ‘0’
Led_O
N
Led_
OFF
Led0 <= ‘1’
Push = ‘1’
Figura 9.2 – Diagrama de Estados FSM_Led
Como claramente se observa en el Diagrama de Estados, al
encontrarse en el Estado LED_OFF (state_reg) y obtener un ‘1’ desde el
PushButton de la Tarjeta Basys2 se pasa al siguiente estado (state_next)
LED_ON encendiendo el Led, por el contrario si se encuentra en el estado
LED_OFF y se obtiene un ‘0’ desde el PushButton, se permanece en el
mismo estado y el Led no se enciende. Al encontrarse en el estado LED_ON
y obtener un ‘0’ desde el PushButton, el Estado siguiente permanece en
LED_ON; por el contrario, si el PushButton envía un ‘1’ se cambia al estado
LED_OFF apagando el Led.
En otras palabras el Led enciende con un pulso del botón y se apaga
con otro pulso del mismo botón.
El diagrama a bloques del circuito se muestra en la Figura 9.3
Figura 9.3 – Diagrama a bloques FSM_Led
Por lo tanto basado en la figura 9.3 la entidad del programa quedaría
de la siguiente manera:
pág. 110
entity FSM_Led is
Port ( Push: in STD_LOGIC;
Clk : in STD_LOGIC;
Reset : in STD_LOGIC;
Led0 : out STD_LOGIC);
end FSM_Led;
Código 9.1 – Entidad FSM_Led
Para representar los estados de la FSM se utiliza una enumeración de
Tipo de Datos TYPE, en donde se asigna un nombre a la enumeración
seguido de los estados que se utilizarán.
TYPE nombre_de_la_enumeración is (Estado1, Estado2, EstadoN);
TYPE estados_led is (LED_OFF, LED_ON);
De este modo se crean 2 estados LED_OFF y LED_ON mostrados en
el Diagrama de la Figura 9.2
Teniendo la enumeración se crean las señales del registro de Estados
las cuales serán un componente de la enumeración creada.
Signal state_reg, state_next : estados_led;
Para que la FSM funcione se necesitan de dos procesos, un proceso
que actualice y guarde el Estado del Registro cada pulso de Reloj de la
Tarjeta Basys2 (Código 9.2 State Register) y un proceso que obtenga el
estado siguiente y mande la acción de control hacia las salidas (Código 9.3
Next-State logic and output logic).
--==========================================================
-- Proceso que actualiza y guarda el estado del registro
--==========================================================
P_SEQ_FSM: Process (Reset, Clk)
begin
if Reset = '1' then
state_reg <= LED_OFF;
elsif Clk'event and Clk='1' then
state_reg <= state_next;
end if;
end process;
Código 9.2 - State Register
-=====================================================================
--Proceso que obtiene el estado siguiente y salidas (next-state
logic)
-=====================================================================
pág. 111
P_COMB_ESTADO: Process (state_reg, Push_tick)
begin
state_next <= state_reg; -- condicion de inicio y regreso a
estado actual
Led0 <= '0';
case state_reg is
when LED_OFF =>
if Push_tick = '1' then
state_next <= LED_ON;
Led0 <= '1';
else
state_next <= LED_OFF;
Led0 <= '0';
end if;
when LED_ON =>
if Push_tick = '1' then
state_next <= LED_OFF;
Led0 <= '0';
else
state_next <= LED_ON;
Led0 <= '1';
end if;
end case;
end process;
Código 9.3 – Next-State Logic and Output Logic
Las condiciones del cambio de estado se implementan por medio de
un CASE que depende del estado actual del Registro (State_reg). Es una
buena práctica de programación inicializar los estados y mandar a su
condición predeterminada las salidas (en este caso el Led apagado) dentro
del proceso de cambio de Estados.
state_next <= state_reg;
Led0 <= '0';
No olvide el circuito Detector de Flancos necesario para las interfaces
humanas el cual solo entregará un pulso cada que se presione el botón.
El código completo de la arquitectura es mostrado en el recuadro de
código 9.4. (Observe el circuito detector de flancos y la creación de las
señales auxiliares). Compile y pruebe su funcionamiento.
architecture Behavioral of FSM_Led is
-- Enumeración Type para la FSM ... (Enumeracion de los Estados)
-- El tipo enumerado siguiente nos permite asignar los valores
pág. 112
LED_OFF y LED_ON a
-- las señales que se declaren del tipo estados_led.
type estados_led is (LED_OFF, LED_ON);
-- Señales para el programa (ojo que
enumeración XD)
signal state_reg, state_next : estados_led;
signal btn_reg : std_logic;
signal Push_tick : std_logic;
begin
son
componente
de
la
--===================================
--Detector de Flancos
--===================================
process(clk)
begin
if (clk'event and clk='1') then
btn_reg <= Push;
end if;
end process;
Push_tick <= (not btn_reg) and Push;
--==========================================================
-- Proceso que actualiza y guarda el estado del registro
--==========================================================
P_SEQ_FSM: Process (Reset, Clk)
begin
if Reset = '1' then
state_reg <= LED_OFF;
elsif Clk'event and Clk='1' then
state_reg <= state_next;
end if;
end process;
-=====================================================================
--Proceso que obtiene el estado siguiente y salidas (next-state
logic)
-=====================================================================
P_COMB_ESTADO: Process (state_reg, Push_tick)
begin
state_next <= state_reg; -- condicion de inicio y regreso a
estado actual
Led0 <= '0';
case state_reg is
when LED_OFF =>
if Push_tick = '1' then
state_next <= LED_ON;
pág. 113
Led0 <= '1';
else
state_next <= LED_OFF;
Led0 <= '0';
end if;
when LED_ON =>
if Push_tick = '1' then
state_next <= LED_OFF;
Led0 <= '0';
else
state_next <= LED_ON;
Led0 <= '1';
end if;
end case;
end process;
end Behavioral;
Código 9.4 – Arquitectura FSM_Led
Practica 9.2 – Rotación de Leds Basado en FSM con Pulsador
En esta práctica se pretende que los Leds de la tarjeta Basys2 se
enciendan 1 tras otro y roten en ambos sentidos (Izquierda o Derecha).
Con un pulso de un PushButton de la tarjeta se cambiará el sentido de
rotación de Izquierda a Derecha y al presionar de nuevo se cambiará el
sentido de Derecha a Izquierda. Además con otro PushButton se podrá
Pausar o Continuar la rotación.
Para hacer esto hay que basarse en el Programa anterior de la
Práctica 9.1 donde los PushButtons dejan “Memorizado” su pulso, esto
significa que con un pulso se obtiene un ‘1’ y al volver a presionar un ‘0’.
Nuevamente es necesario el diseño estructural para poder Mapear y Castear
los módulos. El Diagrama a bloques del circuito es mostrado en la figura 9.4
pág. 114
Figura 9.4 – Diagrama a Bloques Esquemático FSM_Rot_Led
Para comprender el funcionamiento de la FSM observe el Diagrama
de estados de la figura 9.5
Pause
0
1
2
3
4
5
6
7
Dir
Figura 9.5 – Diagrama de estados FSM_Rot_Led
Dependiendo del valor de Dir los Leds rotarán hacia la Izquierda o
hacia la Derecha. Dependiendo del valor de Pause el Led permanecerá
quieto en el estado en el que se encuentre. El estado en donde se encuentre
será el Led que encenderá de la tarjeta Basys2.
Cabe mencionar que los Leds rotarán a la velocidad del Reloj de la
tarjeta Basys2, por lo cual todos los Leds se verán encendidos al mismo
tiempo. Esto es debido a que correrán a una frecuencia de 50Mhz (50
millones de pulsos por segundo) la cual no es visible al ojo humano.
Para solucionar este problema es necesario un divisor de frecuencia
el cual genera un Tick con un periodo de 20 ns (F = 50 Mhz) cada 0.33
segundos. (*ESTO ES MUY IMPORTANTE PARA NO GENERAR
PROBLEMAS CON LOS TIEMPOS YA QUE NO SE PUEDE UTILIZAR LA
FUNCION clk’event and clk=’1’ CON UNA SEÑAL DIFERENTE QUE NO
SEA LA DEL RELOJ DE LA TARJETA BASYS)
Para calcular la división de la Frecuencia utilise la siguiente ecuación:
pág. 115
Donde:
N = Constante de tipo Integer
T = Tiempo Deseado
De este modo se crea una Constante con un valor de 24 para obtener
un Tiempo de 0.33 segundos lo cual equivale a F = 1/T = 3 Hz. (3 Pulsos por
segundo).
El código para lograr esta División de Frecuencia queda como se
muestra en el Recuadro de Código 9.5
constant N: integer:=24; -- 2^N * 20ns = reloj
signal q_reg, q_next: unsigned (N-1 downto 0);
signal Tick : std_logic;
begin
--===================================
--Contador que genera ticks de 0.3 seg
--===================================
process (clk)
begin
if (Clk'event and Clk='1') then
q_reg <= q_next;
end if;
end process;
-- next-state logic
q_next <= q_reg + 1;
-- tick de salida
Tick <= '1' when q_reg=0 else '0';
Código 9.5 – Divisor de Frecuencia
Como se puede apreciar, el divisor de Frecuencia no es más que un
Contador que incrementa en 1 un registro hasta el número 16777216 = 2 24.
Cuando el registro vuelve a ser 0 genera un Tick que vale ‘1’ durante 20 ns.
El código que muestra el programa completo (FSM_Rot_Led) se
muestra en el recuadro de Código 9.6. Nótese el uso del diseño estructural
para el Casteo del programa FSM_Led.
entity FSM_Rot_Led is
Port ( Clk : in STD_LOGIC;
Reset : in STD_LOGIC;
Dir_ent : in STD_LOGIC;
pág. 116
Led : out
end FSM_Rot_Led;
Pause_ent: in STD_LOGIC;
STD_LOGIC_VECTOR (7 downto 0));
architecture Behavioral of FSM_Rot_Led is
signal Led_aux : unsigned (7 downto 0);
constant N: integer:=24; -- 2^N * 20ns = reloj
signal q_reg, q_next: unsigned (N-1 downto 0);
signal Tick : std_logic;
signal Dir, Pause : std_logic;
type estados_led is (s0,s1,s2,s3,s4,s5,s6,s7);
signal state_reg, state_next : estados_led;
COMPONENT FSM_Led
PORT(
Push : IN std_logic;
Clk : IN std_logic;
Reset : IN std_logic;
Led0 : OUT std_logic
);
END COMPONENT;
begin
--==================================
--Mapeo para Pause y Direccion
--==================================
Inst_FSM_Led_Dir: FSM_Led PORT MAP(
Push => Dir_ent,
Clk => Clk,
Reset => Reset,
Led0 => Dir
);
Inst_FSM_Led_Pause: FSM_Led PORT MAP(
Push => Pause_ent,
Clk => Clk,
Reset => Reset,
Led0 => Pause
);
--===================================
--Contador que genera ticks de 0.3 seg
--===================================
process (clk)
begin
if (Clk'event and Clk='1') then
pág. 117
q_reg <= q_next;
end if;
end process;
-- next-state logic
q_next <= q_reg + 1;
-- tick de salida
Tick <= '1' when q_reg=0 else '0';
--==========================================================
-- Proceso que actualiza y guarda el estado del registro
--==========================================================
P_SEQ_FSM: Process (Reset, Clk, Pause)
begin
if Reset = '1' then
state_reg <= s0;
elsif Pause = '1' then
state_reg <= state_reg;
elsif Clk'event and Clk='1' then
state_reg <= state_next;
end if;
end process;
-=====================================================================
--Proceso que obtiene el estado siguiente y salidas (next-state
logic)
-=====================================================================
P_COMB_ESTADO: Process (state_reg, Tick, Dir, Pause)
begin
state_next <= state_reg; -- 118 ondición de inicio y regreso a
estado actual
case state_reg is
when s0 =>
Led_aux <= “00000001”;
if Tick = ‘1’ then
if Dir = ‘1’ then
state_next <= s1;
else
state_next <= s7;
end if;
end if;
when s1 =>
Led_aux <= “00000010”;
if Tick = ‘1’ then
if Dir = ‘1’ then
state_next <= s2;
else
pág. 118
state_next <= s0;
end if;
end if;
when s2 =>
Led_aux <= “00000100”;
if Tick = ‘1’ then
if Dir = ‘1’ then
state_next <= s3;
else
state_next <= s1;
end if;
end if;
when s3 =>
Led_aux <= “00001000”;
if Tick = ‘1’ then
if Dir = ‘1’ then
state_next <= s4;
else
state_next <= s2;
end if;
end if;
when s4 =>
Led_aux <= “00010000”;
if Tick = ‘1’ then
If Dir = ‘1’ then
state_next <= s5;
else
state_next <= s3;
end if;
end if;
when s5 =>
Led_aux <= “00100000”;
if Tick = ‘1’ then
if Dir = ‘1’ then
state_next <= s6;
else
state_next <= s4;
end if;
end if;
when s6 =>
Led_aux <= “01000000”;
if Tick = ‘1’ then
if Dir = ‘1’ then
state_next <= s7;
else
state_next <= s5;
end if;
end if;
when s7 =>
Led_aux <= “10000000”;
if Tick = ‘1’ then
if Dir = ‘1’ then
state_next <= s0;
pág. 119
else
state_next <= s6;
end if;
end if;
end case;
end process;
Led <= std_logic_vector (Led_aux);
end Behavioral;
Código 9.6 – FSM_Rot_Led
Para lograr que la rotación se Detenga hay que hacer que
permanezca en el mismo estado cuando Pause tenga un valor de ‘1’. Dentro
del Proceso que controla la actualización del Registro de estado se puede
agregar esta condición.
elsif Pause = '1' then
state_reg <= state_reg;
Compile y Pruebe el funcionamiento del Programa con la Tarjeta
Basys2.
Práctica 10 – Circuito Anti rebotes (Debounce Circuit)
Existe un problema con los switches mecánicos de la Tarjeta Basys2 y
sensores diseñados por uno mismo, al ser activados presentan más de un
pulso en su señal. Esto se debe a que “rebota” de arriba hacia abajo la señal
hasta que se estabiliza en un pulso positivo o negativo. En algunos casos
estos “rebotes” duran hasta 20 ms y tomando en cuenta que la Tarjeta
Basys2 tiene una velocidad de reloj de 20 ns ocasiona comportamientos no
deseados en los diseños como saltos de cuentas, cambio a estados
indeterminados o activación de actuadores en momentos erróneos.
Un circuito detector de flancos no siempre es suficiente así que al
combinarlo con un circuito anti rebotes se obtiene una señal limpia (filtrada)
que elimina esos rebotes innecesarios en las transiciones de los switches o
sensores.
En la figura 10.1 se representa lo que pasa al accionar un switch
mecánico, observe las pequeñas variaciones que se eliminarán antes de
estabilizarse.
pág. 120
Figura 10.1 – Toma de osciloscopio de un Switch
Se basará el circuito anti rebotes en una Maquina de Estados la cual
tendrá un generador de ticks de 10 ms para los estados de espera y dos
estados principales (Zero y One); de esta forma se tendrá un valor de ‘0’ o ‘1’
respectivamente.
Asumiendo que la FSM esta inicialmente en el estado Zero, esta se
mueve al primer estado de espera Wait1_1 cuando el switch cambia a ‘1’. En
el estado Wait1_1 la FSM espera recibir un Tick de 10 ms para pasar al
siguiente estado, si dentro de este tiempo el Switch toma un valor de ‘0’,
implica que la duración del ‘1’ no tardó lo demasiado y regresa al estado Zero
(Hubo un rebote). La acción se repite 2 veces mas para los estados Wait1_2
y Wait1_3. La operación desde el estado One es similar excepto que la señal
del switch debe ser ‘0’.
El diagrama a bloques esquemático del circuito anti rebotes se
observa en la Figura 10.2
Figura 10.2 – Diagrama Esquemático Debounce_FSM
Para entender mejor el funcionamiento observe el diagrama de
estados Debounce_FSM de la Figura 10.3.
pág. 121
Figura 10.3 – Diagrama de Estados Debounce_FSM
El código VHDL que implementa el Debounce_FSM (Código 10.1) es
similar a las maquinas de estados creadas en la práctica 9, observe la
implementación del generador de ticks de 10ms y la salida filtrada db que se
utilizará en prácticas posteriores.
entity Debounce_fsm is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
sw : in STD_LOGIC;
db : out STD_LOGIC);
end Debounce_fsm;
architecture Behavioral of Debounce_fsm is
constant N: integer:=19; -- 2^N * 20ns = 10 ms reloj
signal q_reg, q_next: unsigned (N-1 downto 0);
signal m_tick: std_logic;
--enumeración estados
type eg_state_type is (zero, wait1_1, wait1_2, wait1_3,
one, wait0_1, wait0_2, wait0_3);
signal state_reg, state_next: eg_state_type;
begin
--===================================
pág. 122
--Contador que genera ticks de 10 ms
--===================================
process (clk,reset)
begin
if (clk'event and clk='1') then
q_reg <= q_next;
end if;
end process;
-- next-state logic
q_next <= q_reg + 1;
-- tick de salida
m_tick <= '1' when q_reg=0 else '0';
--===================================
-- Debounce FMS
--===================================
-- Registro de Estado
process (clk, reset)
begin
if (reset = '1') then
state_reg <= zero;
elsif (clk'event and clk='1') then
state_reg <= state_next;
end if;
end process;
-- logica de estados y salidas
process (state_reg, sw, m_tick)
begin
state_next <= state_reg; -- parametro default
db <= '0'; -- default 0
case state_reg is
when zero =>
if sw = '1' then
state_next <= wait1_1;
end if;
when wait1_1 =>
if sw = '0' then
state_next <= zero;
else
if m_tick = '1' then
state_next <= wait1_2;
end if;
end if;
when wait1_2 =>
if sw = '0' then
state_next <= zero;
else
pág. 123
if m_tick = '1' then
state_next <= wait1_3;
end if;
end if;
when wait1_3 =>
if sw = '0' then
state_next <= zero;
else
if m_tick = '1' then
state_next <= one;
end if;
end if;
when one =>
db <= '1';
if sw = '0' then
state_next <= wait0_1;
end if;
when wait0_1 =>
db <= '1';
if sw = '1' then
state_next <= one;
else
if m_tick = '1' then
state_next <= wait0_2;
end if;
end if;
when wait0_2 =>
db <= '1';
if sw = '1' then
state_next <= one;
else
if m_tick = '1' then
state_next <= wait0_3;
end if;
end if;
when wait0_3 =>
db <= '1';
if sw = '1' then
state_next <= one;
else
if m_tick = '1' then
state_next <= zero;
end if;
end if;
end case;
end process;
end Behavioral;
Código 10.1 – Debounce_FSM
pág. 124
Practica 11 - Generación de una señal PWM
En la siguiente practica se realizará un código en VHDL con el que la
tarjeta Basys2 proporcionará una señal PWM, la cual como se sabe es útil en
el control de motores de CD.
La modulación por ancho de pulso (Pulse Width Modulation PWM) de
una señal o fuente de energía es una técnica en la que se modifica el ciclo
de trabajo de una señal periódica (una senoidal o una cuadrada, por
ejemplo), ya sea para transmitir información a través de un canal de
comunicaciones o para controlar la cantidad de energía que se envía a una
carga.
El ciclo de trabajo de una señal periódica es el ancho relativo de su
parte positiva en relación con el período. Expresado matemáticamente:
Donde:
D es el ciclo de trabajo
es el tiempo en que la función es positiva (ancho del pulso)
T es el período de la función
Figura 11.1 – Ciclo de Trabajo
La construcción típica de un circuito PWM se lleva a cabo mediante un
comparador con dos entradas y una salida.
Algunos parámetros importantes de un PWM son:


La relación de amplitudes entre la señal portadora y la moduladora,
siendo recomendable que la última no supere el valor pico de la
portadora y esté centrada en el valor medio de ésta.
La relación de frecuencias, donde en general se recomienda que la
relación entre la frecuencia de la portadora y la de señal sea de 10 a
1.
pág. 125
En la figura 11.2 se muestra un primer esquema para la generación de
la señal PWM. El diseño es muy simple, mediante el módulo interfaz, el
software envía la posición deseada que es almacenada en un registro, que
se denominará registro de posición. El reloj del sistema incrementa un
contador, de manera que se lleva la cuenta de cuántos tics de reloj han
transcurrido desde que inicialmente se encontraba a cero.
Mediante un comparador se comprueba si el número de tics recibidos
es menor que la posición especificada. Esta posición, que es en realidad el
ancho del pulso de la señal PWM, se expresa también en tics de reloj, por lo
que mientras los tics contados sean menores que los tics del ancho del
pulso, la señal de salida del comparador, L, permanecerá a nivel alto. En
cuanto los tics superen este valor, la señal L se pone a cero.
F
Posición
I
Figura 11.2 Diagrama a bloques generación de una señal PWM en VHDL
Como se puede observar en el diagrama a bloques, se necesitan dos
módulos: un contador y un comparador, los cuales posteriormente serán
mapeados para así crear un solo modulo que contendrá los dos módulos
anteriores y la señal PWM de salida.
El módulo del contador es mostrado en el recuadro de código 11.1
notese la creación de la variable cuenta y su uso.
entity Contador is
port (
clk : in std_logic; -- Reloj
reset : in std_logic;
q : out std_logic_vector (7 downto 0)); --Salida
pág. 126
end Contador;
architecture Behavioral of Contador is
begin
output: process(clk,reset)
variable cuenta : std_logic_vector(7 downto 0);
begin
-- Actualizar la cuenta
if (reset='1') then -- Reset asíncrono
cuenta:=(others=>'0'); -- Inicializar contador
q<=cuenta;
elsif (clk'event and clk='1') then -- Flanco de subida en reloj
cuenta:=(cuenta+1); -- Incrementar contador
q<=cuenta;
end if;
end process;
end Behavioral;
Código 11.1 – Módulo contador
Es recomendado utilizar la librería unsigned para poder utilizar el
signo de (+) en el código, sin esta librería marcará un error al momento de
checar la sintaxis del código.
Lo siguiente es diseñar un módulo de Comparación de 2 entradas de 8
bits. El código es mostrado en el recuadro de código 11.2
entity Comparador is
port (opa : in std_logic_vector(7 downto 0); -- Operador A
opb : in std_logic_vector(7 downto 0); -- Operador B
G : out std_logic);
end Comparador;
architecture Behavioral of Comparador is
begin
process (opa, opb)
begin
if (opa<opb) then
G <= '1';
else
G <= '0';
end if;
end process;
end Behavioral;
Codigo 11.2 Módulo comparador
pág. 127
Como se observa se tiene dos entradas de 8 bits de las cuales la
primera será la salida del módulo contador y la segunda será la posición
deseada por el usuario. Para hacer esta comparación solo se necesita un
proceso el cual dependerá de las entradas opa y opb; cuando opa sea
menor que opb entonces la señal de salida G, tomará el valor de “1”, por el
contrario tomará el valor de “0”.
Por último se crea el Top Module en el cual se agregan los dos
modulos anteriores (comparador y contador) y asi se obtiene la señal PWM.
A este nuevo módulo se le asignará el nombre de PWM_OUT, a continuación
se muestra el código del módulo PWM_OUT (código 11.3).
entity PWM_OUT is
port (pwm_pos : in std_logic_vector (7 downto 0); -- Posicion
pwm_clk : in std_logic; -- Reloj
pwm_reset: in std_logic; -- Reset.
pwm_o : out std_logic); -- Señal PWM
end PWM_OUT;
architecture Behavioral of PWM_OUT is
component contador is
port (
clk : in std_logic; -- Reloj
reset : in std_logic;
q : out std_logic_vector (7 downto 0)); --Salida
end component;
component comparador is
port (
opa : in std_logic_vector(7 downto 0); -- Operador A
opb : in std_logic_vector(7 downto 0); -- Operador B
G : out std_logic);
end component;
signal ntic : std_logic_vector (7 downto 0); -- Numero de tics de
reloj
signal sg : std_logic; -- Señal G
begin
CONT1: contador port map (clk=>pwm_clk, q=>ntic, reset=>pwm_reset);
COMP1: comparador port map (opa=>ntic, opb=>pwm_pos, G=>sg);
-- Señal PWM de salida
pwm_o<= sg;
end Behavioral;
Código 11.3 - Módulo PWM_OUT.
pág. 128
Observe que en el módulo PWM_OUT se cuenta con una señal de
posición (pwm_pos), la cual es una de las entradas del comparador (Ciclo de
Trabajo que el usuario desea para la señal PWM), tiene una señal de reloj
(pwm_clk) con la misma frecuencia de reloj que el contador, un reset
(pwm_reset) que será el mismo que el del contador y una salida (pwm_o) la
cual es la salida del comparador, y en su defecto será la señal PWM
deseada.
Asigne la entrada pwm_pos a los switches de la tarjeta Basys2 y la
salida pwm_o a un led. Se debe notar la variación de intensidad luminosa en
el led de la tarjeta.
Envie la salida de la señal PWM a un motor haciendo las
consideraciones de acondicionamiento de señal necesarias. El resultado se
observa en el siguiente video a través del enlace:
http://youtu.be/Y4YPefPjxqY
Practica 12 - PWM con salida a display.
En esta práctica se generará una señal PWM como en el proyecto
anterior, pero ahora el porcentaje al que se encuentra el ancho de pulso de la
señal (duty cycle) será mostrado en los displays de la tarjeta, dicho ancho de
pulso será manipulado por medio del usuario a través de los bits de posición.
Observese el diagrama a bloques del proyecto (figura 12.1) para
comprender mejor su funcionamiento.
Figura 12.1 Diagrama a bloques de PWM con display
Como se puede observar se necesita un módulo PWM, para ello se
reutilizará el de la práctica anterior (Código 11.1, 11.2, 11.3); además, se
pág. 129
necesita un módulo que se encarge de multiplexear y sacar el resultado
hacia los displays, para ello se reutilizará el modulo diseñado en la práctica
de la ALU (Código 7.1 – disp_hex_mux)
Con la ayuda del diseño estructural se facilita el trabajo reutilizando
pedazos de código prefabricados, cree un módulo que se encarge de la
conversión de código binario de la entrada a un porcentaje proporcional que
será desplegado en la salida del display. Emplee la función bin-a-bcd
utilizada anteriormente para este paso. Observese el código del módulo
Porcentaje
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Porcentaje is
Port ( Entrada : in STD_LOGIC_VECTOR (5 downto 0);
clk : in STD_LOGIC;
an: out std_logic_vector (3 downto 0);
sseg: out std_logic_vector (7 downto 0));
end Porcentaje;
architecture Behavioral of Porcentaje is
--=======================
--sEÑALES
--=======================
Signal Porcentaje_aux : unsigned (15 downto 0);
Signal Porcentaje : unsigned (6 downto 0);
Signal hex : unsigned(15 downto 0);
-===========================================================================
========
-- Función que recibe un valor binario de 16 bits y devuelve
su representación
-- BCD de cuatro dígitos (16 bits).
-- Usa el algoritmo de corrimiento y suma 3.
-===========================================================================
========
function bin_a_bcd( bin : unsigned(15 downto 0)) return unsigned is
variable i : integer := 0;
variable
resultado
:
unsigned(
15
downto
0
)
:=
"0000000000000000";
variable copiabin : unsigned( 15 downto 0 ) := bin;
begin
-- Aquí va el código de la función
for i in 0 to 15 loop
pág. 130
resultado( 15 downto 1 ) := resultado( 14 downto 0 );
resultado( 0 ) := copiabin( 15 );
copiabin( 15 downto 1 ) := copiabin( 14 downto 0 );
copiabin( 0 ) := '0';
-- unidades
if i < 15 and resultado( 3 downto 0 ) > "0100" then
resultado( 3 downto 0 ) := resultado( 3 downto 0
) + "0011";
end if;
-- decenas
if i < 15 and resultado( 7 downto 4 ) > "0100" then
resultado( 7 downto 4 ) := resultado( 7 downto 4
) + "0011";
end if;
-- centenas
if i < 15 and resultado( 11 downto 8 ) > "0100" then
resultado( 11 downto 8 ) := resultado( 11 downto
8 ) + "0011";
end if;
-- millares
if i < 15 and resultado (15 downto 12) > "0100" then
resultado ( 15 downto 12 ) := resultado ( 15
downto 12 ) + "0011";
end if;
end loop;
return resultado;
end bin_a_bcd;
--============================================
--Instantiation Display_Mux
--============================================
COMPONENT Dis_hex_mux
PORT(
clk : IN std_logic;
reset : IN std_logic;
hex3 : IN std_logic_vector(3 downto 0);
hex2 : IN std_logic_vector(3 downto 0);
hex1 : IN std_logic_vector(3 downto 0);
hex0 : IN std_logic_vector(3 downto 0);
dp_in : IN std_logic_vector(3 downto 0);
an : OUT std_logic_vector(3 downto 0);
sseg : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--==================================
--Inicio de Arquitectura
--==================================
pág. 131
begin
--=============================================================
-- Conversión de los Porcentajes de la Entrada de los Switches
--=============================================================
process (Entrada) begin
case Entrada is
when "000000" => Porcentaje
when "000001" => Porcentaje
when "000010" => Porcentaje
when "000011" => Porcentaje
when "000100" => Porcentaje
when "000101" => Porcentaje
when "000110" => Porcentaje
when "000111" => Porcentaje
when "001000" => Porcentaje
when "001001" => Porcentaje
when "001010" => Porcentaje
when "001011" => Porcentaje
when "001100" => Porcentaje
when "001101" => Porcentaje
when "001110" => Porcentaje
when "001111" => Porcentaje
when "010000" => Porcentaje
when "010001" => Porcentaje
when "010010" => Porcentaje
when "010011" => Porcentaje
when "010100" => Porcentaje
when "010101" => Porcentaje
when "010110" => Porcentaje
when "010111" => Porcentaje
when "011000" => Porcentaje
when "011001" => Porcentaje
when "011010" => Porcentaje
when "011011" => Porcentaje
when "011100" => Porcentaje
when "011101" => Porcentaje
when "011110" => Porcentaje
when "011111" => Porcentaje
when "100000" => Porcentaje
when "100001" => Porcentaje
when "100010" => Porcentaje
when "100011" => Porcentaje
when "100100" => Porcentaje
when "100101" => Porcentaje
when "100110" => Porcentaje
when "100111" => Porcentaje
when "101000" => Porcentaje
when "101001" => Porcentaje
when "101010" => Porcentaje
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
"0000000" ; -- 0 0%
"0000001" ; -- 1 1%
"0000011" ; -- 2 3%
"0000100" ; -- 3 4%
"0000101"
; -- 4 6%
"0000111"
; -- 5 7%
"0001001"
; -- 6 9%
"0001011"; -- 7 11%
"0001100"
; -- 8 12%
"0001110"
; -- 9 14%
"0001111"
; -- 10 15%
"0010001"
; -- 11 17%
"0010011"
; -- 12 19%
"0010100"
; -- 13 20%
"0010110"
; -- 14 22%
"0010111"
; -- 15 23%
"0011001"
; -- 16 25%
"0011010"
; -- 17 26%
"0011100"
; -- 18 28%
"0011110"
; -- 19 30%
"0011111"
; -- 20 31%
"0100001"
; -- 21 33%
"0100010"
; -- 22 34%
"0100100"
; -- 23 36%
"0100110"
; -- 24 38%
"0100111"
; -- 25 39%
"0101001"
; -- 26 41%
"0101010"
; -- 27 42%
"0101100"
; -- 28 44%
"0101110"
; -- 29 46%
"0101111"
; -- 30 47%
"0110001"
; -- 31 49%
"0110010"
; -- 32 50%
"0110100"
; -- 33 52%
"0110101"
; -- 34 53%
"0110111"
; -- 35 55%
"0111001"
; -- 36 57%
"0111011"
; -- 37 58%
"0111100"
; -- 38 60%
"0111101"
; -- 39 61%
"0111111"
; -- 40 63%
"1000001"
; -- 41 65%
"1000010"
; -- 42 66%
pág. 132
when "101011" => Porcentaje <= "1000100"
; -- 43 68%
when "101100" => Porcentaje <= "1000110"
; -- 44 69%
when "101101" => Porcentaje <= "1000111"; -- 45 71%
when "101110" => Porcentaje <= "1001001"
; -- 46 73%
when "101111" => Porcentaje <= "1001010"
; -- 47 74%
when "110000" => Porcentaje <= "1001100"
; -- 48 76%
when "110001" => Porcentaje <= "1001101"
; -- 49 77%
when "110010" => Porcentaje <= "1001111"
; -- 50 79%
when "110011" => Porcentaje <= "1010000"
; -- 51 80%
when "110100" => Porcentaje <= "1010010" ; -- 52 82%
when "110101" => Porcentaje <= "1010100"
; -- 53 84%
when "110110" => Porcentaje <= "1010101"
; -- 54 85%
when "110111" => Porcentaje <= "1010111"
; -- 55 87%
when "111000" => Porcentaje <= "1011000"
; -- 56 88%
when "111001" => Porcentaje <= "1011010"
; -- 57 90%
when "111010" => Porcentaje <= "1011100"
; -- 58 92%
when "111011" => Porcentaje <= "1011101"
; -- 59 93%
when "111100" => Porcentaje <= "1011111"
; -- 60 95%
when "111101" => Porcentaje <= "1100000"
; -- 61 96%
when "111110" => Porcentaje <= "1100010"
; -- 62 98%
when "111111" => Porcentaje <= "1100100"
; -- 63 100%
when others => Porcentaje <= "0000000"
; -- 64
end case;
end process;
--============================================
-- Mapeo Display_Mux
--============================================
Inst_disp_hex_mux: Dis_hex_mux
clk => clk,
reset => '0',
hex3 => std_logic_vector
hex2 => std_logic_vector
hex1 => std_logic_vector
hex0 => "1110",
dp_in => "1111",
an => an,
sseg => sseg
);
PORT MAP(
(hex (11 downto 8)),
(hex (7 downto 4)),
(hex (3 downto 0)),
--================================
-- Salida a Display
--================================
Porcentaje_aux (6 downto 0) <= Porcentaje;
hex <= bin_a_bcd(Porcentaje_aux);
end Behavioral;
Código 12.1 - Módulo Porcentaje.
Como se observa el código anterior es útil para mostrar el porcentaje
de ancho de pulso de la señal PWM, dicho porcentaje es introducido por el
pág. 133
usuario por medio de los 6 bits de la señal entrada (El cálculo se realizó por
simple regla de tres).
Ahora solo queda mapear este componente dentro del módulo PWM
para que el proyecto quede terminado, el código del proyecto ya terminado
se muestra en el recuadro de código 12.2.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity PWM is
port (pwm_pos : in std_logic_vector (5 downto 0); -- Posicion
pwm_clk : in std_logic; -- Reloj
pwm_reset: in std_logic; -- Reset.
pwm_o : out std_logic; -- Señal PWM
an: out std_logic_vector (3 downto 0);
sseg: out std_logic_vector (7 downto 0));
end PWM;
architecture Behavioral of PWM is
--==================================
-- Instalacion de Contador
--==================================
component contador is
port (clk : in std_logic; -- Reloj
reset : in std_logic;
q : out std_logic_vector (5 downto 0)); --Salida
end component;
--==================================
-- Instalacion de Comparador
--==================================
component comparador is
port (opa : in std_logic_vector(5 downto 0); -- Operador A
opb : in std_logic_vector(5 downto 0); -- Operador B
G : out std_logic);
end component;
--==================================
-- Instalacion Displays a porcentaje
--================================== o algo asi?
COMPONENT Porcentaje
PORT(
Entrada : IN std_logic_vector(5 downto 0);
clk : IN std_logic;
an : OUT std_logic_vector(3 downto 0);
sseg : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
pág. 134
signal ntic : std_logic_vector (5 downto 0); -- Numero de tics de
reloj
signal sg : std_logic; -- Señal G
begin
--=================================================
--Mapeo del contador y comparador
--=================================================
CONT1: contador port map (clk=>pwm_clk, q=>ntic, reset=>pwm_reset);
COMP1: comparador port map (opa=>ntic, opb=>pwm_pos, G=>sg);
-- Señal PWM de salida
pwm_o<= sg;
--===================================================
--Mapeo salida a display porcentaje PWM
--===================================================
Inst_Porcentaje: Porcentaje PORT MAP(
Entrada => pwm_pos,
clk => pwm_clk,
an => an,
sseg => sseg
);
end Behavioral;
Código 12.2 – Módulo PWM
Como se observa solo fue mapeado el módulo de Porcentaje dentro
del módulo PWM para que este pueda mostrar el porcentaje del ancho de
pulso en el display.
Finalmente Compile y Pruebe el funcionamiento del Programa con la
Tarjeta Basys2.
Practica 13 – Señal PWM con Potenciómetro.
En esta práctica se generará una señal PWM la cúal será variada a
través de un potenciómetro y se mostrará el porcentaje del ciclo de trabajo
en los displays.
La señal eléctrica analógica proporcional proveniente del
potenciómetro, necesita ser previamente convertida a una señal digital que
sea entendible para la tarjeta Basys2. Para ello se utilizará un convertidor
analógico digital (ADC0820) de 8 bits; aunque solo se utilizarán los 6 bits
pág. 135
más significativos por cuestiones de comodidad. En la figura 13.1 se muestra
el diagrama del convertidor ADC0820 y en la figura 13.2 su conexión hacia la
Tarjeta Basys2
Figura 13.1 – Diagrama convertidor ADC0820
El funcionamiento es sencillo; se hace variar el potenciómetro con lo
cual varia su resistencia y a su vez por ley de ohm obtenemos una variación
de voltaje de 0 a 5 V. El ADC0820 se encarga de transformar ese voltaje a
un valor binario (‘0’ o ‘1’) el cual es leído por la tarjeta Basys2. Dependiendo
del valor binario obtenido hacemos la comparación para sacar el valor PWM
deseado y el porcentaje del ciclo de trabajo que se mostrará en los displays.
Cabe mencionar que para que el ADC0820 funcione correctamente
necesita una señal de reloj. La señal de reloj de la tarjeta Basys2 es
demasiado rápida para el convertidor por lo que crearemos pulsos de menor
frecuencia a través de la tarjeta.
El procedimiento del generador de pulsos se muestra en el recuadro
de código 13.1. Notesé el uso de un generador de ticks de 10ms basado en
el reloj de 50Mhz de la tarjeta y una FSM que manda la salida a ‘0’ o ‘1’
dependiendo del tick generado. Por lo tanto se tendrán pulsos de una
duración de 100hz.
pág. 136
Figura 13.2 – Conversión y Acondicionamiento de Señal
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Contador_Ticks_10ms is
Port ( clk : in STD_LOGIC;
Pulso : out STD_LOGIC);
end Contador_Ticks_10ms;
architecture Behavioral of Contador_Ticks_10ms is
constant N: integer:=19; -- 2^N * 20ns = 10 ms reloj
signal q_reg, q_next: unsigned (N-1 downto 0);
signal Tick : std_logic;
type Sreg0_type is (Pulso_OFF, Pulso_ON);
signal state_reg, state_next: Sreg0_type;
begin
--===================================
--Contador que genera ticks de 10 ms
--===================================
process (clk)
begin
pág. 137
if (clk'event and clk='1') then
q_reg <= q_next;
state_reg <= state_next;
end if;
end process;
-- next-state logic
q_next <= q_reg + 1;
-- tick de salida
Tick <= '1' when q_reg=0 else '0';
Sreg0_machine: process (state_reg, Tick)
begin
state_next <= state_reg; -- Estado Inicial
Pulso <= '0'; -- Señal Default
case state_reg is
when Pulso_OFF =>
if Tick = '1' then
state_next <=
Pulso <= '1';
else
state_next <=
Pulso <= '0';
end if;
when Pulso_ON =>
if Tick = '1' then
state_next <=
Pulso <= '0';
else
state_next <=
Pulso <= '1';
end if;
end case;
end process;
Pulso_ON;
Pulso_OFF;
Pulso_OFF;
Pulso_ON;
end Behavioral;
Código 13.1 Generador de pulsos
Reutilizando todos los módulos de la práctica 12 se mapea el
generador de pulsos como se muestra en el recuadro de código 13.2.
entity PWM is
port (pwm_pos : in std_logic_vector (5 downto 0); -- Posicion
pwm_clk : in std_logic; -- Reloj
pág. 138
pwm_reset: in std_logic; -- Reset.
pwm_o : out std_logic; -- Señal PWM
an: out std_logic_vector (3 downto 0);
sseg: out std_logic_vector (7 downto 0));
end PWM;
architecture Behavioral of PWM is
--==================================
-- Instalacion de Contador
--==================================
component contador is
port (clk : in std_logic; -- Reloj
reset : in std_logic;
q : out std_logic_vector (5 downto 0)); --Salida
end component;
--==================================
-- Instalacion de Comparador
--==================================
component comparador is
port (opa : in std_logic_vector(5 downto 0); -- Operador A
opb : in std_logic_vector(5 downto 0); -- Operador B
G : out std_logic);
end component;
--==================================
-- Instalacion Displays a porcentaje
--================================== o algo asi?
COMPONENT Porcentaje
PORT(
Entrada : IN std_logic_vector(5 downto 0);
clk : IN std_logic;
an : OUT std_logic_vector(3 downto 0);
sseg : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
signal ntic : std_logic_vector (5 downto 0); -- Numero de tics de
reloj
signal sg : std_logic; -- Señal G
begin
--=================================================
--Mapeo del contador y comparador
--=================================================
CONT1: contador port map (clk=>pwm_clk, q=>ntic, reset=>pwm_reset);
COMP1: comparador port map (opa=>ntic, opb=>pwm_pos, G=>sg);
-- Señal PWM de salida
pwm_o<= sg;
--===================================================
pág. 139
--Mapeo salida a display porcentaje PWM
--===================================================
Inst_Porcentaje: Porcentaje PORT MAP(
Entrada => pwm_pos,
clk => pwm_clk,
an => an,
sseg => sseg
);
--===================================================
--Mapeo Generador 10 ms
--===================================================
Inst_Contador_Ticks_10ms: Contador_Ticks_10ms PORT MAP(
clk => pwm_clk,
Pulso => Pulso
);
end Behavioral;
Código 13.2 – Señal PWM con Generador de Pulsos de 10ms
Finalmente cheque sintaxis, compile y asigne los pines necesarios
tomando en cuenta que esta vez se utilizan 6 entradas de los conectores
PMod que representan los 6 bits anteriormente utilizados por los switches.
Además de una salida que será utilizada por el ADC0820, la cual debe ser
debidamente acondicionada.
El resultado de la práctica es mostrado en el siguiente enlace:
Practica 14 - Control de un motor debido a la señal de un sensor.
En la siguiente práctica se simulará el Control de una banda
transportadora la cual detendrá o activará el motor que la hace girar una vez
que el sensor que cuenta las piezas llegue a 15. Además se integra un botón
de reset que regresa a 0 la cuenta y un Stop de Emergencia que detiene el
proceso en cualquier momento. El número de piezas contadas se muestra en
los displays de la tarjeta Basys2
Como sensor de presencia se utilizará un fotorresistor, el cual es un
componente electrónico cuya resistencia disminuye con el aumento de
intensidad de luz incidente. Sus siglas son: LDR y se originan de su nombre
en inglés light-dependent resistor. Su cuerpo está formado por una célula o
celda y dos patillas (figura 14.1).
pág. 140
Figura 14.1 - Fotorresistor
A través de un CI LM555 conectado al fotorresistor se obtendrán
señales de ‘0’ o ‘1’ cuando haya o no incidencia de luz. Esto será útil al pasar
un objeto el cuál evitará el paso de luz hacia el sensor lo que indicará
presencia de pieza que será contada por la tarjeta Basys2.
El diseño del sensor de presencia es mostrado en la figura 14.2
notese el uso de resistores y capacitores extras. El potenciómetro utilizado
en el sensor de presencia sirve para variar la sensibilidad.
Figura 14.2 – Sensor de presencia
La señal proporcionada por el sensor debe ser acondicionada por lo
que se agrega un optoacoplador para proteger a la Tarjeta Basys2 y unos
pág. 141
resistores de 1KΩ para disminuir el voltaje a 3.3V. El circuito se muestra en
la figura 14.3.
Figura 14.3 Circuito para el acondicionamiento de señal, con salida hacia el FPGA.
Para comprender el código utilizado en el proyecto observe el
diagrama a bloques que se muestra en la figura 14.4
Figura 14.4 Diagrama a bloques del Proyecto
pág. 142
Existe un problema con el sensor de presencia, el cual envia pulsos
parasitos que afectan la cuenta. Será necesario implementar un circuito
antirrebotes (debounce) como el del módulo debounce_fsm del recuadro de
código 10.1 de la Práctica 10. Observe la diferencia en el recuadro de código
14.1 donde se ha agregado un detector de flancos extra llamado
Flanco_Enable que será de utilidad en el siguiente módulo.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Debounce_fsm is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
sw : in STD_LOGIC;
Flanco_Enable : out STD_LOGIC);
end Debounce_fsm;
architecture Behavioral of Debounce_fsm is
constant N: integer:=19; -- 2^N * 20ns = 10 ms reloj
signal q_reg, q_next: unsigned (N-1 downto 0);
signal m_tick: std_logic;
signal db, db_reg: std_logic;
--enumeración estados
type eg_state_type is (zero, wait1_1, wait1_2, wait1_3,
one, wait0_1, wait0_2, wait0_3);
signal state_reg, state_next: eg_state_type;
begin
--===================================
--Contador que genera ticks de 10 ms
--===================================
process (clk,reset)
begin
if (clk'event and clk='1') then
q_reg <= q_next;
end if;
end process;
-- next-state logic
q_next <= q_reg + 1;
-- tick de salida
m_tick <= '1' when q_reg=0 else '0';
--===================================
-- Debounce FMS
--===================================
pág. 143
-- Registro de Estado
process (clk, reset)
begin
if (reset = '1') then
state_reg <= zero;
elsif (clk'event and clk='1') then
state_reg <= state_next;
end if;
end process;
-- logica de estados y salidas
process (state_reg, sw, m_tick)
begin
state_next <= state_reg; -- parametro default
db <= '0'; -- default 0
case state_reg is
when zero =>
if sw = '1' then
state_next <= wait1_1;
end if;
when wait1_1 =>
if sw = '0' then
state_next <= zero;
else
if m_tick = '1' then
state_next <= wait1_2;
end if;
end if;
when wait1_2 =>
if sw = '0' then
state_next <= zero;
else
if m_tick = '1' then
state_next <= wait1_3;
end if;
end if;
when wait1_3 =>
if sw = '0' then
state_next <= zero;
else
if m_tick = '1' then
state_next <= one;
end if;
end if;
when one =>
db <= '1';
if sw = '0' then
state_next <= wait0_1;
end if;
when wait0_1 =>
db <= '1';
pág. 144
if sw = '1' then
state_next <= one;
else
if m_tick = '1' then
state_next <= wait0_2;
end if;
end if;
when wait0_2 =>
db <= '1';
if sw = '1' then
state_next <= one;
else
if m_tick = '1' then
state_next <= wait0_3;
end if;
end if;
when wait0_3 =>
db <= '1';
if sw = '1' then
state_next <= one;
else
if m_tick = '1' then
state_next <= zero;
end if;
end if;
end case;
end process;
--====================================
--Detector de Flancos
--====================================
process(clk)
begin
if (clk'event and clk='1') then
db_reg <= db;
end if;
end process;
--db_reg <= db when m_tick = '1' else db_reg;
Flanco_Enable <= ((not db_reg) and db);
end Behavioral;
Código 14.1 Modulo debounce_FSM con Flanco_Enable.
Se reutilizará el módulo disp_hex_mux (Código 7.1) utilizado en la
ALU y prácticas anteriores, el cual se encarga de multiplexear y mandar la
salida a los displays.
pág. 145
A continuación se mapean los módulos debounce_FSM y
disp_hex_mux al módulo Sensor_Prox el cual generará un pulso cada que
el sensor de presencia detecte 15 piezas. Observe el uso de la función
bin_a_bcd y el diseño de un contador de 4 bits necesario para la cuenta de
las piezas.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Sensor_Prox is
Port ( Sensor : in STD_LOGIC;
reset: in STD_LOGIC;
clk : in STD_LOGIC;
Cuenta : out STD_LOGIC_VECTOR (3 downto 0);
an : out STD_LOGIC_VECTOR (3 downto 0);
cuenta_max: out STD_LOGIC;
sseg : out STD_LOGIC_VECTOR (7 downto 0)
);
end Sensor_Prox;
architecture Behavioral of Sensor_Prox is
--============================================
--Instantiation Antirrebotes
--============================================
COMPONENT Debounce_fsm
PORT(
clk : IN std_logic;
reset : IN std_logic;
sw : IN std_logic;
Flanco_Enable : OUT std_logic
);
END COMPONENT;
--============================================
--Instantiation Display_Mux
--============================================
COMPONENT disp_hex_mux
PORT(
clk : IN std_logic;
reset : IN std_logic;
hex3 : IN std_logic_vector(3 downto 0);
hex2 : IN std_logic_vector(3 downto 0);
hex1 : IN std_logic_vector(3 downto 0);
hex0 : IN std_logic_vector(3 downto 0);
dp_in : IN std_logic_vector(3 downto 0);
an : OUT std_logic_vector(3 downto 0);
sseg : OUT std_logic_vector(7 downto 0)
pág. 146
);
END COMPONENT;
-===========================================================================
========
-- Función que recibe un valor binario de 4 bits y devuelve su
representación
-- BCD de tres dígitos (8 bits).
-- Usa el algoritmo de corrimiento y suma 3.
-===========================================================================
========
function
bin_a_bcd(
bin
:
unsigned(3
downto
0))
return
unsigned is
variable i : integer := 0;
variable resultado : unsigned(
7
downto
0
)
:=
"00000000";
variable copiabin : unsigned( 3 downto 0 ) := bin;
begin
-- Aquí va el código de la función
for i in 0 to 3 loop
resultado( 7 downto 1 ) := resultado( 6 downto 0
);
resultado( 0 ) := copiabin( 3 );
copiabin( 3 downto 1 ) := copiabin( 2 downto 0 );
copiabin( 0 ) := '0';
-- unidades
if i < 3 and resultado( 3 downto 0 ) > "0100"
then
resultado( 3 downto 0 ) := resultado( 3
downto 0 ) + "0011";
end if;
-- decenas
if i < 3 and resultado( 7 downto 4 ) > "0100"
then
resultado( 7 downto 4 ) := resultado( 7
downto 4 ) + "0011";
end if;
-- centenas
--if i < 7 and resultado( 11 downto 8 ) > "0100"
then
--
resultado( 11 downto 8 ) := resultado( 11
downto 8 ) + "0011";
--end if;
end loop;
return resultado;
pág. 147
end bin_a_bcd;
--============================================
--Señales Auxiliares (Reg Reloj y cuenta)
--============================================
constant N: integer:=4; -- 2^N * 20ns = 10 ms reloj
signal q_reg, q_next: unsigned (N-1 downto 0);
signal sensor_enable : STD_LOGIC;
-- Señales Display
signal hex0: unsigned (7 downto 0);
begin
--============================================
--Mapeo Antirrebotes
--============================================
Inst_Debounce_fsm: Debounce_fsm PORT MAP(
clk => clk ,
reset => reset,
sw => Sensor,
Flanco_Enable => sensor_enable
);
--============================================
-- Mapeo Display_Mux
--============================================
Inst_disp_hex_mux: disp_hex_mux PORT MAP(
clk => clk,
reset => reset,
hex3 => "0000",
hex2 => "0000",
hex1 => std_logic_vector (hex0 (7 downto 4)),
hex0 => std_logic_vector (hex0 (3 downto 0)),
dp_in => "1111",
an => an,
sseg => sseg
);
--===================================
--Contador que genera ticks de 10 ms
--===================================
process (clk,reset)
begin
if reset = '1' then
q_reg <= (others => '0');
elsif(clk'event and clk='1') then
q_reg <= q_next;
end if;
end process;
pág. 148
-- next-state logic
q_next <= q_reg + 1 when (sensor_enable = '1') else
q_reg;
--================
--Cast de salida
--================
Cuenta <= std_logic_vector (q_reg);
Cuenta_max <= '1' when q_reg = 15 else '0';
--====================================
-- Salida a Displays y conversión
--====================================
hex0 <= bin_a_bcd(q_reg);
end Behavioral;
Código 14.2 – Módulo Sensor_Prox.
Finalmente cree un módulo llamado Motor_Sensor en el cual se
agregarán el módulo Sensor_Prox. Una vez mas el diseño estructural con
VHDL demuestra ser un arma escencial para el desarrollo de este proyecto y
de igual forma viable para el diseño del control de procesos complejos.
El módulo Motor_Sensor se encargará por medio de una FSM de
encender y apagar el motor dependiendo de la cuenta proporcionada por el
módulo Sensor_Prox; a su vez controla el stop de emergencia que detendrá
el proceso cuando sea activado. Observe el cuadro de código 14.3
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Motor_Sensor is
port (
CLK: in STD_LOGIC;
Sensor: in STD_LOGIC;
reset: in STD_Logic;
Cuenta: out std_logic_vector (3 downto 0);
an: out std_logic_vector (3 downto 0);
sseg: out std_logic_vector (7 downto 0);
Stop_emerg: in STD_LOGIC;
Motor: out STD_LOGIC);
end;
architecture motor_on_arch of Motor_Sensor is
-- SYMBOLIC ENCODED state machine: Sreg0
pág. 149
type Sreg0_type is (Motor_OFF, Motor_ON);
signal state_reg, state_next: Sreg0_type;
signal cuenta_reg: std_logic;
signal cuenta_flanco: std_logic;
signal cuenta_max: std_logic;
--==========================================
--Inst Sensor_Prox
--==========================================
COMPONENT Sensor_Prox
PORT(
Sensor : IN std_logic;
reset : IN std_logic;
clk : IN std_logic;
Cuenta : OUT std_logic_vector(3 downto 0);
an : OUT std_logic_vector(3 downto 0);
cuenta_max : OUT std_logic;
sseg : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
begin
--========================================
-- Mapeo Sensor_Prox
--========================================
Inst_Sensor_Prox: Sensor_Prox PORT MAP(
Sensor => Sensor,
reset => reset,
clk => CLK,
Cuenta => Cuenta,
an => an,
cuenta_max => cuenta_max,
sseg => sseg
);
--=========================================
--Detector de Flancos
--=========================================
process(CLK)
begin
if (CLK'event and CLK='1') then
cuenta_reg <= cuenta_max;
end if;
end process;
--db_reg <= db when m_tick = '1' else db_reg;
cuenta_flanco <= ((not cuenta_reg) and cuenta_max);
--==========================================
pág. 150
-- Estado del Registro
--==========================================
Process (CLK, Stop_emerg)
begin
if (Stop_emerg = '1') then
state_reg <= Motor_OFF;
elsif CLK'event and CLK = '1' then
state_reg <= state_next;
end if;
end process;
--==========================================
-- Lógica de Estado Siguiente y Salidas
--==========================================
Sreg0_machine: process (state_reg, cuenta_flanco)
begin
state_next <= state_reg; -- Estado Inicial
Motor <= '0'; -- Señal Default
case state_reg is
when Motor_OFF =>
if cuenta_flanco = '1' then
state_next <= Motor_ON;
Motor <= '1';
else
state_next <= Motor_OFF;
Motor <= '0';
end if;
when Motor_ON =>
if cuenta_flanco = '1' then
state_next <= Motor_OFF;
Motor <= '0';
else
state_next <= Motor_ON;
Motor <= '1';
end if;
end case;
end process;
end motor_on_arch;
Código 14.3 – Módulo Motor_Sensor.
Por último haga un chequeo de sintaxis, compile y asigne los pines
necesarios. Recuerde hacer el acondicionamiento de señal necesario para la
entrada del sensor de presencia y la salida que controla el motor (Figura 4.1)
pág. 151
Práctica 15 - Señal PWM controlada con Pushbuttons
Señal PWM que varía su ciclo de trabajo pulsando los pushbuttons de
la tarjeta basys2.
-
Módulos Necesarios:
Contador – Código 11.1
Comparador – Código 11.2
Disp_hex_mux – Código 7.1
Contador_UP_DOWN – Código 15.2
entity pwm_unit is
Port ( --pwm_pos : in
STD_LOGIC_VECTOR (5 downto 0); -- BITS DE
ENTRADA SWITCHES
pwm_clk : in STD_LOGIC;
P_up : in STD_LOGIC;
P_down : in STD_LOGIC;
--sal: out std_logic;
--Pulso: out std_logic;
--led_enable: out std_logic;
--start: in std_logic;
pwm_motor: out std_logic;
pwm_led:out std_logic;
an: out std_logic_vector (3 downto 0);
sseg: out std_logic_vector (7 downto 0));
end pwm_unit;
architecture Behavioral of pwm_unit is
COMPONENT Contador_UP_DOWN
PORT(
P_up1 : IN std_logic;
P_down1 : IN std_logic;
clk : IN std_logic;
reset : IN std_logic;
cuenta : OUT std_logic_vector(7 downto 0);
an : OUT std_logic_vector(3 downto 0);
sseg : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
COMPONENT contador
PORT(
clk : IN std_logic;
reset : IN std_logic;
q : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
component comparador is
pág. 152
port (opa : in std_logic_vector(7 downto 0);
opb : in std_logic_vector(7 downto 0);
G
: out std_logic);
end component;
-- Operador A
-- Operador B
signal ntic
: std_logic_vector (7 downto 0); -- Numero de tics de
reloj
--signal ntic_ms: std_logic_vector (3 downto 0); -- 8 bits menos peso
de ntic
--signal sg
: std_logic; -- Señal G
signal pwm_o : std_logic;
signal pwm_pos : std_logic_vector (7 downto 0);
--Inicio de Arquitectura
begin
--enable<= not start;
--led_enable<= start;
CONT1: contador
port map (clk=>pwm_clk, q=>ntic, reset=> '0');
COMP1: comparador port map (opa=>ntic, opb=>pwm_pos, G=> pwm_o);
Inst_Contador_UP_DOWN: Contador_UP_DOWN PORT MAP(
P_up1 => P_up,
P_down1 => P_down,
clk => pwm_clk,
reset => '0',
cuenta => pwm_pos,
an => an,
sseg => sseg
);
-- Obtener los 8 bits menos significativos del contador
-- Señal PWM de salida
--pwm_o <= sg; --(not ntic(8)) and (not ntic(9)) and (not ntic(10))
--and (not sg);
--sal <= pwm_o;
pwm_led <= pwm_o;
pwm_motor <= pwm_o;
end Behavioral;
Código 15.1 – Pwm_unit
pág. 153
El código 15.2 es mapeado hacia el top module Pwm_unit. El
contador_UP_DOWN se encarga de incrementar o disminuir una cuenta
cada que obtengamos un tick de reloj y un pulso filtrado a través de un
detector de flancos de los push buttons. Observe el mapeo de los demás
módulos para mostrar la cuenta de 0 a 100 equivalente al porcentaje de la
señal PWM en los displays y el uso de la función bin_a_bcd.
entity Contador_UP_DOWN is
Port ( P_up1 : in STD_LOGIC;
P_down1 : in STD_LOGIC;
clk : in STD_LOGIC;
reset : in STD_LOGIC;
cuenta: out std_logic_vector (7 downto 0);
an: out std_logic_vector (3 downto 0);
sseg: out std_logic_vector (7 downto 0));
end Contador_UP_DOWN;
architecture Behavioral of Contador_UP_DOWN is
--signal db_reg_up1, db_reg_down1 : std_logic;
--signal db_up1, db_down1 : std_logic;
signal conta : natural;
signal hex : unsigned (11 downto 0);
constant N: integer:=22; -- 2^N * 20ns = 0.6 s reloj
signal q_reg, q_next: unsigned (N-1 downto 0);
signal Tick : std_logic;
-===========================================================================
========
-- Función que recibe un valor binario de 12 bits y devuelve su
representación
-- BCD de tres dígitos (12 bits).
-- Usa el algoritmo de corrimiento y suma 3.
-===========================================================================
========
function bin_a_bcd( bin : unsigned(11 downto 0)) return unsigned is
variable i : integer := 0;
variable resultado : unsigned( 11 downto 0 ) := "000000000000";
variable copiabin : unsigned( 11 downto 0 ) := bin;
begin
-- Aquí va el código de la función
for i in 0 to 11 loop
resultado( 11 downto 1 ) := resultado( 10 downto 0 );
resultado( 0 ) := copiabin( 11 );
copiabin( 11 downto 1 ) := copiabin( 10 downto 0 );
pág. 154
copiabin( 0 ) := '0';
-- unidades
if i < 11 and resultado( 3 downto 0 ) > "0100" then
resultado( 3 downto 0 ) := resultado( 3 downto 0 ) +
"0011";
end if;
-- decenas
if i < 11 and resultado( 7 downto 4 ) > "0100" then
resultado( 7 downto 4 ) := resultado( 7 downto 4 ) +
"0011";
end if;
-- centenas
if i < 11 and resultado( 11 downto 8 ) > "0100" then
resultado( 11 downto 8 ) := resultado( 11 downto 8 ) +
"0011";
end if;
-- millares
--if i < 15 and resultado (15 downto 12) > "0100" then
-resultado ( 15 downto 12 ) := resultado ( 15 downto 12
) + "0011";
--end if;
end loop;
return resultado;
end bin_a_bcd;
--==============================================
--Display instansiación
--==============================================
COMPONENT disp_hex_mux
PORT(
clk : IN std_logic;
reset : IN std_logic;
hex3 : IN std_logic_vector(3 downto 0);
hex2 : IN std_logic_vector(3 downto 0);
hex1 : IN std_logic_vector(3 downto 0);
hex0 : IN std_logic_vector(3 downto 0);
dp_in : IN std_logic_vector(3 downto 0);
an : OUT std_logic_vector(3 downto 0);
sseg : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
begin
--====================================
--Detector de Flancos
pág. 155
--====================================
--process(clk)
--begin
-if (clk'event and clk='1') then
-db_reg_up1 <= P_up1;
-db_reg_down1 <= P_down1;
-end if;
--end process;
--db_up1 <= ((not db_reg_up1) and P_up1);
--db_down1 <= ((not db_reg_down1) and P_down1);
--=============================================
-- Generador de Ticks de 0.6 s
--=============================================
process (clk)
begin
if (clk'event and clk='1') then
q_reg <= q_next;
end if;
end process;
-- next-state logic
q_next <= q_reg + 1;
-- tick de salida
Tick <= '1' when q_reg=0 else '0';
--=============================================
-- Contador Up / Down
--=============================================
P_conta: Process (reset, clk)
begin
if reset = '1' then
conta <= 0;
elsif clk'event and clk='1' then
if Tick = '1' and P_up1 = '1' then
if conta /= 100 then
conta <= conta + 1;
end if;
elsif Tick = '1' and P_down1 = '1' then
if conta /= 0 then
conta <= conta - 1;
end if;
end if;
end if;
end process;
pág. 156
hex <= bin_a_bcd(to_unsigned (conta,12));
cuenta <= std_logic_vector ( to_unsigned (conta, 8));
--==============================================
-- Mapeo Display
--==============================================
Inst_disp_hex_mux: disp_hex_mux PORT MAP(
clk => clk,
reset => reset,
hex3 => std_logic_vector (hex (11 downto 8)),
hex2 => std_logic_vector (hex (7 downto 4)),
hex1 => std_logic_vector (hex (3 downto 0)),
hex0 => "1110",
dp_in => "1101",
an => an ,
sseg => sseg
);
end Behavioral;
Código 15.2 – Contador_UP_DOWN
Compile y Pruebe el funcionamiento del Programa con la Tarjeta
Basys2.
Práctica 16 - Contador Parametrizable (Mod_m_Counter)
En la siguiente práctica se diseñará un contador parametrizable que
cuenta desde 0 a m-1 y vuelve a iniciar.
El código VHDL necesario es mostrado en el recuadro de código 16.1.
Observe el uso de los parámetros genéricos los cuales pueden ser
modificados en futuras instanciaciones al determinar un valor en la
inicialización de componentes.
Library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
-- A mod-m counter counts from 0 to m – 1 and wraps around.
-- One is M, which specifies the limit, m, and the other is N, which
specifies the
-- number of bits needed and should be equal to (log2*M) .
pág. 157
-===========================================================================
=======
entity mod_m_counter is
generic (
N: integer := 6; -- numero de bits
M: integer := 40 – MOD-M
);
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
max_tick : out STD_LOGIC);
--q : out STD_LOGIC_VECTOR (N-1 downto 0));
end mod_m_counter;
architecture Behavioral of mod_m_counter is
signal r_reg: unsigned (N-1 downto 0);
signal r_next: unsigned (N-1 downto 0);
begin
-===========================================================================
=======
--Registro cambio de estado
-===========================================================================
=======
process (clk, reset)
begin
if (reset = ‘1’) then
r_reg <= (others => ‘0’);
elsif (clk’event and clk = ‘1’) then
r_reg <= r_next;
end if;
end process;
-===========================================================================
========
--Logica de cambio de estado
-===========================================================================
========
r_next <= (others => ‘0’) when r_reg = (M-1) else
r_reg + 1;
-===========================================================================
pág. 158
========
--Salida
-===========================================================================
========
--q <= std_logic_vector (r_reg);
max_tick <= ‘1’ when r_reg = (M-1) else ‘0’;
end Behavioral;
Código 16.1 – Módulo mod_m_counter
Práctica 17 - FIFO Buffer
Un FIFO (first-in-first-out) buffer es un almacen “elastico” entre dos
subsitemas, como se muestra en el diagrama conceptual de la figura 17.1.
Cuenta con dos señales de control wr y rd, para escribir y leer
respectivamente. Cuando wr se encuentra en alto, la entrada de datos es
escrita en el buffer. La cabeza del FIFO buffer esta siempre disponible y
puede ser leida en cualquier momento. La señal de rd funciona como una
señal de “borrado”. Cuando la señal de rd se encuentra en alto, el primer
dato (la cabeza) del FIFO buffer es removida y el siguiente dato se queda
disponible.
La descripción del FIFO Buffer que será utilizado en prácticas
siguientes se muestra en el recuadro de código 17.1.
Figura 17.1 – Diagrama Conceptual FIFO Buffer
entity fifo is
generic (
B: natural :=8 ; -- 8 Numero de Bits
W: natural :=4 -- 4 Number of Address Bits
);
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
pág. 159
rd : in STD_LOGIC;
wr : in STD_LOGIC;
w_data : in STD_LOGIC_VECTOR (B-1 downto 0);
empty : out STD_LOGIC;
full : out STD_LOGIC;
r_data : out STD_LOGIC_VECTOR (B-1 downto 0));
end fifo;
architecture Behavioral of fifo is
type reg_file_type is array (2**W-1 downto 0) of
std_logic_vector (B-1 downto 0);
signal array_reg: reg_file_type;
signal w_ptr_reg, w_ptr_next, w_ptr_succ:
std_logic_vector (W-1 downto 0);
signal r_ptr_reg, r_ptr_next, r_ptr_succ:
std_logic_vector (W-1 downto 0);
signal full_reg, empty_reg, full_next, empty_next: std_logic;
signal wr_op: std_logic_vector (1 downto 0);
signal wr_en: std_logic;
begin
--=================================================================
--registro
--=================================================================
process (clk, reset)
begin
if (reset = '1') then
array_reg <= (others =>(others => '0'));
elsif (clk'event and clk='1') then
if wr_en='1' then
array_reg(to_integer(unsigned(w_ptr_reg)))
<= w_data;
end if;
end if;
end process;
-- Lectura del puerta
r_data <= array_reg(to_integer(unsigned(r_ptr_reg)));
-- Write Enabled solo cuando FIFO no esta lleno
wr_en <= wr and (not full_reg);
--==================================================================
-- FIFO control logic
--==================================================================
-- registro para leer y escribir punteros (pointers)
process(clk, reset)
begin
if (reset = '1') then
w_ptr_reg <= (others => '0');
pág. 160
r_ptr_reg <= (others => '0');
full_reg <= '0';
empty_reg <= '1';
elsif (clk'event and clk='1') then
w_ptr_reg <= w_ptr_next;
r_ptr_reg <= r_ptr_next;
full_reg <= full_next;
empty_reg <= empty_next;
end if;
end process;
-- successive pointer values
w_ptr_succ <= std_logic_vector(unsigned(w_ptr_reg)+1);
r_ptr_succ <= std_logic_vector(unsigned(r_ptr_reg)+1);
--===================================================================
--Logica de estado siguiente
--===================================================================
wr_op <= wr & rd;
process (w_ptr_reg, w_ptr_succ, r_ptr_reg, r_ptr_succ, wr_op,
empty_reg, full_reg)
begin
w_ptr_next <= w_ptr_reg;
r_ptr_next <= r_ptr_reg;
full_next <= full_reg;
empty_next <= empty_reg;
case wr_op is
when "00" => -- no op
when "01" => -- read
if (empty_reg /= '1') then -- not empty
r_ptr_next <= r_ptr_succ;
full_next <= '0';
if (r_ptr_succ = w_ptr_reg) then
empty_next <= '1';
end if;
end if;
when "10" => -- write
if (full_reg /= '1') then -- not full
w_ptr_next <= w_ptr_succ;
empty_next <= '0';
if (w_ptr_succ = r_ptr_reg) then
full_next <= '1';
end if;
end if;
when others => -- write /read
w_ptr_next <= w_ptr_succ;
r_ptr_next <= r_ptr_succ;
end case;
end process;
pág. 161
--salidas
full <= full_reg;
empty <= empty_reg;
end Behavioral;
Código 17.1 – Módulo FIFO
Práctica 18 – Comunicación Serial Puerto PS2 – Teclado
A través de los siguientes módulos se logra la comunicación del puerto
PS2 de la tarjeta Basys2; se conecta un teclado para probarlo. El código
enviado por el teclado es mostrado en los leds de la tarjeta.
-
Módulos:
FIFO – Código 17.1
Mod_m_couter – Código 16.1
Kb_code – Código 18.1
Kb_monitor – Código 18.2
Key2ascii – Código 18.3
PS2_RX – Código 18.4
Kb_led – Código 18.5
El diagrama del conector PS2 y su conexión hacia la tarjeta Basys2 se
muestra en la figura 18.1.
Figura 18.1 – Conector PS2 Tarjeta Basys2
-===========================================================================
==
-- PS2 keyboard last-releases key circuit
-===========================================================================
==
entity kb_code is
pág. 162
generic (W_SIZE: integer := 2); -- 2^W_SIZE words in FIFO
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
ps2d : in STD_LOGIC;
ps2c : in STD_LOGIC;
rd_key_code : in STD_LOGIC;
key_code : out STD_LOGIC_VECTOR (7 downto 0);
kb_buf_empty : out STD_LOGIC);
end kb_code;
architecture Behavioral of kb_code is
constant BRK: std_logic_vector (7 downto 0):= "11110000";
-- F0 (Break Code)
type statetype is (wait_brk, get_code);
signal state_reg, state_next: statetype;
signal scan_out, w_data: std_logic_vector (7 downto 0);
signal scan_done_tick, got_code_tick: std_logic;
begin
-===========================================================================
===
-- Instantiation PS2_RX_unit
-===========================================================================
===
PS2_RX_unit: entity work.PS2_RX (Behavioral)
port map ( clk => clk, reset => reset, rx_en => '1',
ps2d => ps2d, ps2c => ps2c,
rx_done_tick => scan_done_tick,
dout => scan_out);
--=================================================================
-- Instantiation FIFO Buffer
--=================================================================
fifo_key_unit: entity work.fifo (Behavioral)
generic map (B => 8, W => W_SIZE)
PORT MAP (clk => clk, reset => reset, rd => rd_key_code,
wr => got_code_tick, w_data => scan_out,
empty => kb_buf_empty, full => open,
r_data => key_code);
--=====================================================================
-- FSM to get the scan code after F0 received
--=====================================================================
process (clk, reset)
begin
if reset = '1' then
pág. 163
state_reg <= wait_brk;
elsif (clk'event and clk='1') then
state_reg <= state_next;
end if;
end process;
process (state_reg, scan_done_tick, scan_out)
begin
got_code_tick <= '0';
state_next <= state_reg;
case state_reg is
when wait_brk => -- wait for F0 of Break Code
if scan_done_tick = '1' and scan_out = BRK then
state_next <= get_code;
end if;
when get_code => -- get the following scan code
if scan_done_tick = '1' then
got_code_tick <= '1';
state_next <= wait_brk;
end if;
end case;
end process;
end Behavioral;
Código 18.1 – Módulo kb_code
entity kb_monitor is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
ps2d : in STD_LOGIC;
ps2c : in STD_LOGIC;
tx : out STD_LOGIC);
end kb_monitor;
architecture Behavioral of kb_monitor is
constant SP: std_logic_vector (7 downto 0) := "00100000";
-- blank space in ASCII
type statetype is (idle, send1, send0, sendb);
signal state_reg, state_next: statetype;
signal scan_data, w_data: std_logic_vector (7 downto 0);
signal scan_done_tick, wr_uart: std_logic;
signal ascii_code: std_logic_vector (7 downto 0);
signal hex_in: std_logic_vector (3 downto 0);
begin
--====================================================================
-- Inicializacion PS2 RECEIVER
--====================================================================
PS2_RX_unit: entity work.PS2_RX (Behavioral)
pág. 164
port map (clk => clk, reset => reset, rx_en => '1',
ps2d => ps2d, ps2c => ps2c,
rx_done_tick => scan_done_tick,
dout => scan_data);
--====================================================================
-- Inicializacion UART
--====================================================================
UART_unit: entity work.UART (Behavioral)
port map (clk => clk, reset => reset, rd_uart => '0',
wr_uart => wr_uart, rx => '1', w_data =>
w_data,
tx_full => open, rx_empty => open, r_data =>
open,
tx => tx);
--====================================================================
-- FSM para enviar 3 Caracteres ASCII
--====================================================================
-- REGISTROS DE ESTADO
process (clk, reset)
begin
if reset = '1' then
state_reg <= idle;
elsif (clk'event and clk = '1') then
state_reg <= state_next;
end if;
end process;
-- next state logic
process (state_reg, scan_done_tick, ascii_code)
begin
wr_uart <= '0';
w_data <= SP;
state_next <= state_reg;
case state_reg is
when idle => -- start when a scan code received
if scan_done_tick = '1' then
state_next <= send1;
end if;
when send1 => -- send higher hex char
w_data <= ascii_code;
wr_uart <= '1';
state_next <= send0;
when send0 => -- send lower hex char
w_data <= ascii_code;
wr_uart <= '1';
state_next <= sendb;
when sendb => -- send blank space char
pág. 165
w_data <= SP;
wr_uart <= '1';
state_next <= idle;
end case;
end process;
--========================================================================
-- Scan code to ASCII display
--========================================================================
-- se parte el codigo escaneado en 2 4-bit hex
hex_in <= scan_data (7 downto 4) when state_reg = send1 else
scan_data (3 downto 0);
-- hex digit a Codigo ASCII
with hex_in select
ascii_code <=
"00110000"
"00110001"
"00110010"
"00110011"
"00110100"
"00110101"
"00110110"
"00110111"
"00111000"
"00111001"
"01000001"
"01000010"
"01000011"
"01000100"
"01000101"
"01000110"
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
"0000",
"0001",
"0010",
"0011",
"0100",
"0101",
"0110",
"0111",
"1000",
"1001",
"1010",
"1011",
"1100",
"1101",
"1110",
others;
-----------------
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
end Behavioral;
Código A.9 – Módulo Kb_monitor
entity key2ascii is
Port ( key_code : in STD_LOGIC_VECTOR (7 downto 0);
ascii_code : out STD_LOGIC_VECTOR (7 downto 0));
end key2ascii;
architecture Behavioral of key2ascii is
begin
with key_code select
ascii_code <=
"00110000" when "01000101", -- 0
"00110001" when "00010110", -- 1
pág. 166
"00110010"
"00110011"
"00110100"
"00110101"
"00110110"
"00110111"
"00111000"
"00111001"
when
when
when
when
when
when
when
when
"00011110",
"00100110",
"00100101",
"00101110",
"00110110",
"00111101",
"00111110",
"01000110",
---------
2
3
4
5
6
7
8
9
"01000001"
"01000010"
"01000011"
"01000100"
"01000101"
"01000110"
"01000111"
"01001000"
"01001001"
"01001010"
"01001011"
"01001100"
"01001101"
"01001110"
"01001111"
"01010000"
"01010001"
"01010010"
"01010011"
"01010100"
"01010101"
"01010110"
"01010111"
"01011000"
"01011001"
"01011010"
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
when
"00011100",
"00110010",
"00100001",
"00100011",
"00100100",
"00101011",
"00110100",
"00110011",
"01000011",
"00111011",
"01000010",
"01001011",
"00111010",
"00110001",
"01000100",
"01001101",
"00010101",
"00101101",
"00011011",
"00101100",
"00111100",
"00101010",
"00011101",
"00100010",
"00110101",
"00011010",
---------------------------
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
"01100000"
"00101101"
"00111101"
"01011011"
"01011101"
"01011100"
"00111011"
"00100111"
"00101100"
"00101110"
"00101111"
when
when
when
when
when
when
when
when
when
when
when
"00001110",
"01001110",
"01010101",
"01010100",
"01011011",
"01011101",
"01001100",
"01010010",
"01000001",
"01001001",
"01001010",
------------
'
=
{
}
\
;
´
,
.
/
"00100000"
"00001101"
"00001000"
"00101010"
when
when
when
when
"00101001", -- (space)
"01011010", -- (enter, cr)
"01100110", -- (backspace)
others; -- *
pág. 167
end Behavioral;
Código 18.2 – Módulo key2ascii
entity PS2_RX is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
ps2d : in STD_LOGIC; -- key data
ps2c : in STD_LOGIC; -- key clock
rx_en : in STD_LOGIC;
rx_done_tick : out STD_LOGIC;
dout : out STD_LOGIC_VECTOR (7 downto 0));
end PS2_RX;
architecture Behavioral of PS2_RX is
type statetype is (idle, dps, load);
signal state_reg, state_next: statetype;
signal filter_reg, filter_next: std_logic_vector(7 downto 0);
signal f_ps2c_reg, f_ps2c_next: std_logic;
signal b_reg, b_next: std_logic_vector (10 downto 0);
signal n_reg, n_next: unsigned (3 downto 0);
signal fall_edge: std_logic;
begin
-=========================================================================
-- Filtro y detector de flancos --- ticks generados para ps2c
-=========================================================================
process(clk, reset)
begin
if reset = '1' then
filter_reg <= (others => '0');
f_ps2c_reg <= '0';
elsif (clk'event and clk = '1') then
filter_reg <= filter_next;
f_ps2c_reg <= f_ps2c_next;
end if;
end process;
filter_next <= ps2c & filter_reg(7 downto 1);
f_ps2c_next <= '1' when filter_reg = "11111111" else
'0' when filter_reg = "00000000" else
f_ps2c_reg;
fall_edge <= f_ps2c_reg and (not f_ps2c_next);
-=========================================================================
-- FSMD to extract the 8 - bit data
--
pág. 168
=========================================================================
process (clk, reset)
begin
if reset = '1' then
state_reg <= idle;
n_reg <= (others => '0');
b_reg <= (others => '0');
elsif (clk'event and clk = '1') then
state_reg <= state_next;
n_reg <= n_next;
b_reg <= b_next;
end if;
end process;
-- next state logic
process (state_reg, n_reg, b_reg, fall_edge, rx_en, ps2d)
begin
rx_done_tick <= '0';
state_next <= state_reg;
n_next <= n_reg;
b_next <= b_reg;
case state_reg is
when idle =>
if fall_edge = '1' and rx_en = '1' then
-- shift in start bit
b_next <= ps2d & b_reg (10 downto 1);
n_next <= "1001";
state_next <= dps;
end if;
when dps => -- 8 data + 1 parity + 1 stop
if fall_edge = '1' then
b_next <= ps2d & b_reg (10 downto 1);
if n_reg = 0 then
state_next <= load;
else
n_next <= n_reg - 1;
end if;
end if;
when load =>
-- 1 extra clock to complete the last shift
state_next <= idle;
rx_done_tick <= '1';
end case;
end process;
-- salidas
dout <= b_reg (8 downto 1); -- data bits
end Behavioral;
Código 18.3 – Módulo PS2_RX
pág. 169
El teclado manda un código a través de los canales de datos del
puerto PS2. Los códigos hexadecimales de cada tecla son mostrados en la
figura 18.2.
Figura 18.2 – Códigos enviados por el teclado
Mapeamos el módulo PS2_RX (Código 18.3) hacia el top module
KB_Led el cual se encargará de enviar hacia los leds de la tarjeta Basys2 el
código hexadecimal de la tecla del teclado pulsada. Serán necesarios los 8
leds de la tarjeta.
entity KB_Led is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
ps2d : in STD_LOGIC;
ps2c : in STD_LOGIC;
leds : out STD_LOGIC_VECTOR (7 downto 0));
end KB_Led;
architecture Behavioral of KB_Led is
signal kb_not_empty, kb_buf_empty : std_logic;
signal key_code : std_logic_vector(7 downto 0);
begin
kb_code_unit : entity work.kb_code(Behavioral)
port map (clk => clk, reset => reset, ps2d => ps2d, ps2c => ps2c,
rd_key_code => kb_not_empty, key_code =>
key_code,
kb_buf_empty => kb_buf_empty );
kb_not_empty <= not kb_buf_empty;
leds <= key_code;
end Behavioral;
Código 18.4 – Módulo KB_Led
pág. 170
CONCLUSIONES Y RECOMENDACIONES
Tarjeta Basys2 Viable en el control de Procesos.
Gracias al diseño e implementación de las prácticas expuestas en este
documento quedó demostrado que la Tarjeta Basys2 basada en el FPGA
Spartan-3E 100 K de la marca Xilinx es un opción viable para controlar
procesos.
Cabe destacar que la Tarjeta Basys2 cuenta con entradas y salidas
limitadas y el proceso a implementar debe estar pensado en las capacidades
de la tarjeta. Para proyectos de un volumen alto se recomienda utilizar una
tarjeta de desarrollo con mayor capacidad y basada en una arquitectura
FPGA superior. De igual manera se puede optar por comprar únicamente el
dispositivo FPGA y hacer el PCB necesario para la producción en masa.
El diseño estructural con VHDL permite conectar módulos
prefabricados. Los alcances del FPGA Spartan-3E aun no han llegado al
límite con estas prácticas y el uso de procesadores embebidos diseñados por
el fabricante Xilinx como los son PicoBlaze de 8 bits y MicroBlaze de 32 bits
abren un avanico de posibilidades para el manejo de datos de forma paralela
y aplicaciones innovadoras de adquisición y procesamiento a gran velocidad.
El tiempo de diseño de un prototipo con la Tarjeta Basys2 es reducido
y ofrece ventajas tales como la reprogramación y reasignación de pines para
hacer pruebas que permitan llegar al producto final.
Se recomienda ampliamente a los diseñadores tomar las precauciones
pertinentes respecto al acondicionamiento de las señales para no dañar la
tarjeta; recuerde que los puertos PMod de E/S están protegidos contra corto
circuito, pero al trabajar con valores altos de voltaje y corriente se corren
riesgos importantes y no hay garantía de que no sufra daños.
La tendencia actual demuestra que el uso de FPGA’s se ha ido
incrementando con el paso de los años y las capacidades de estos aumentan
de manera exponencial. A la fecha de este documento se ha roto la barrera
de los 2 Tb/s de ancho de banda con un transmisor basado en los modernos
Virtex-7 X690T FPGA’s. Imaginemos las posibilidades.
pág. 171
REFERENCIAS BIBLIOGRÁFICAS
1
Norman S. Nise, Sistemas de Control para Ingeniería. (1a Edición),
Compañía Editorial Continental, Mexico: 2004
2
Pong P. Chu, FPGA Prototyping by VHDL Examples XILINX Spartan-3
Version. (1a Edición), John Wiley & Sons Inc, Hoboken, New Jersey: 2008
3
Menéndez Ortiz María Alejandra, Arquitectura FPGA para la adquisición de
Datos Térmicos. Universidad del Mar Campus Puerto Escondido Oaxaca
México: 2010.
4
www.xilinx.com/support/documentation/data_sheets/ds312.pdf
5
http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,400,790&Prod=B
ASYS2
6
Urquía Alfonso, Martín Villalba Carla, Casos prácticos de diseño de circuitos
digitales con VHDL, Universidad Nacional de Educación a Distancia (UNED)
Departamento de Informática y Automática, Madrid, España: 2008
7
Machado Sánchez Felipe, Borromeo López Susana, Diseño de circuitos
digitales con VHDL, (Version 1.01) Departamento de Tecnología Electrónica
Universidad Rey Juan Carlos; Madrid, España: 2010
8
http://www.mexchip.com/categor%C3%ADas/tutoriales/vhdl/
pág. 172
Descargar