Generador de Funciones para Sensores Basados en Óxidos Metálicos AUTOR: Marcial Rosado Farré . DIRECTORES: Nicolau Cañellas, Xavier Vilanova . FECHA: Febrero/ 2002. Bibliografía Bibliografía Recomendada Para aprender a utilizar el lenguaje de programación VHDL se recomienda consultar el libro: Título: VHDL Lenguaje Estándar de Diseño Electrónico Editorial: Mc Graw Hill Para obtener información sobre el funcionamiento y estructuras de las FPGA se puede consultar el libro: Título: The Programable Lógic Data Book Autor: XILINX El funcionamiento de la placa de uso genérico de Xilinx se describe en: Título: FPGA Design Demonstration Board Hardware User Guide Autor: XILINX También se puede encontrar diversa información en la dirección de internet siguiente: http://www.xilinx.com Índice 1. MEMORIA DESCRIPTIVA ............................................................................. 5 1.1 INTRODUCCIÓN ............................................................................................. 5 1.2 DESCRIPCIÓN GENERAL ................................................................................ 8 1.2.1 Sensores de Semiconductor óxido......................................................... 8 1.2.2 Introducción al VHDL .......................................................................... 9 1.2.3 Introducción a la FPGA ..................................................................... 13 1.2.4 Descripción del Diseño ...................................................................... 15 1.2.5 Descripción Detallada........................................................................ 17 1.2.6 Convertidor DA .................................................................................. 43 1.2.8 Placa de Pruebas................................................................................ 44 1.2.9 Programación de la FPGA ................................................................. 47 2 MEMORIA DE CÁLCULO ............................................................................ 49 2.1 2.2 2.3 2.4 2.6 3 CÁLCULO DE LA FRECUENCIA DEL RELOJ EXTERNO ................................... 49 FRECUENCIA DEL RELOJ EXTERNO PARA LA VERIFICACIÓN DEL DISEÑO .... 49 CÁLCULO DE LOS VALORES DE LA ROM..................................................... 50 CÁLCULO DE COMPONENTES PARA EL CONVERTIDOR DA .......................... 52 CONVERTIDOR DA EN LA PLACA DE PRUEBAS ............................................ 52 MEMORIA DE PLANOS................................................................................ 53 3.1 PLACA DE PRUEBAS..................................................................................... 53 3.1.1 Situación de Componentes.................................................................. 53 3.1.2 Esquema Eléctrico de ORCAD. .......................................................... 54 3.1.3 Listado de Componentes..................................................................... 55 3.2 FPGA DESIGN DEMONSTRATION BOARD.................................................... 56 3.2.1 Situación de Componentes.................................................................. 56 3.2.2 Esquema Eléctrico.............................................................................. 57 3.3 DIAGRAMA DE CONEXIÓN GENERAL ........................................................... 58 4 ANEXOS ........................................................................................................... 59 4.1 CÓDIGO VHDL Y SIMULACIÓN CON VERIBEST ........................................ 59 4.1.1 clk ....................................................................................................... 59 4.1.2 Divisor por 8 ...................................................................................... 60 4.1.3 Divisor de frecuencia.......................................................................... 61 4.1.4 Contador i_d_desp ............................................................................. 62 4.1.5 Diente de sierra .................................................................................. 73 4.1.6 Rectangular ........................................................................................ 74 4.1.7 Triangular .......................................................................................... 75 4.1.8 Senoidal .............................................................................................. 76 4.1.9 ROM ................................................................................................... 77 4.1.10 Inversor .............................................................................................. 79 4.1.11 Conjunto ............................................................................................. 80 4.1.12 Multiplexor ......................................................................................... 84 3 Índice 4.1.13 Amplificador_ofsset ............................................................................ 85 4.1.14 Generador de funciones...................................................................... 94 4.1.15 Diferencias entre el generador simulado y el sintetizado .................. 97 4.2 SINTETIZACIÓN DEL CÓDIGO VHDL ........................................................... 98 4 Memoria Descriptiva 1. 1.1 Memoria Descriptiva Introducción El objetivo del proyecto es realizar un generador de funciones. Este generador proporcionará cuatro tipo de señales: diente de sierra, rectangular, triangular y senoidal, y podrán ser reguladas en frecuencia, amplitud y offset. Aunque el generador podría utilizarse en multitud de aplicaciones, el proyecto se centrará en el uso de sensores de gases, concretamente sensores de semiconductor óxido. Estos sensores están conectados a unas resistencias donde se debe aplicar intensidad con diferentes formas de onda para provocar variaciones de la temperatura en función del tiempo. Para conseguir el objetivo se ha decidido diseñar el generador mediante un lenguaje de descripción de hardware. El código generado se sintetizará y grabará en un dispositivo programable FPGA. Este dispositivo generará una salida digital que será convertida a analógica con un convertidor digital-analógico con salida de corriente. Después esta corriente se amplificará con un amplificador para adecuar la potencia que necesitan las resistencias. El lenguaje de programación elegido para la implementación del generador digital ha sido el VHDL (lenguaje de descripción del hardware) debido al amplio abanico de posibilidades que ofrece, así como su sencillez para hacer modificaciones del diseño final, permitiendo ampliar los bits de entrada o de salida modificando únicamente unas lineas de código. Para simular el código VHDL se utilizará el paquete informático VERIBEST. Posteriormente, para sintetizar el código y programarlo en la FPGA se utilizará el paquete informático FOUNDATION, debido a que se trabajará con dispositivos del fabricante XILINX. A continuación se puede observar un esquema de las partes principales de este diseño: Figura 1. Esquema En la FPGA se implementará un generador con las siguientes características: 5 Memoria Descriptiva Figura 2. Generador de funciones La señal de reloj clk será introducida externamente mediante un circuito oscilador. - periodo: Controla el periodo, y por tanto la frecuencia de la señal. Por especificaciones del diseño se deben generar periodos comprendidos entre 0.1 y 10 s. Se ha de ajustar el diseño para conseguir un periodo mínimo de 0.1s y a partir de aquí poderlo ampliar. Con 8 bits se podrán generar periodos desde 0.1 s hasta 255·0.1 = 25.5 s, ya que Tseñal = periodo·0,1. Cuando periodo sea cero no se obtendrá señal. - desplazamiento: La señal a generar debe permitir intervalos de reposo para permitir el enfriamiento de las resistencias. Este intervalo estará comprendido entre 0.05 s y 255·0.05 = 12.75 s, ya que tdesplazamiento=desplazamiento·0.05. - amplificación: controlará la amplitud de la señal, la cual debe permitir amplitudes máximas de 150 mA. Con 8 bits por tanto se podrá conseguir una amplitud mínima de ∆ = 150 mA/2n bits. La amplitud de la señal se calcula con la expresión amplitud = amplificación· ∆ - offset: Controlará el offset a aplicar en la señal. Esta tendrá una amplitud máxima de 150 mA, por tanto con 8 bits se podrá introducir un offset mínimo de ∆ = 150 mA/2n bits. El offset de la señal se calcula con la expresión offsetseñal = offset·∆. También se contará con una variable externa de 2 bits que controlará que tipo de señal se quiere seleccionar selec: - “00” Diente de sierra - “01” Rectangular 6 Memoria Descriptiva - “10” Triangular - “11” Senoidal La parte más importante del diseño consistirá en crear la señal triangular, a partir de la cual se podrá generar el resto de señales. El proyecto se centrará en la generación de la señal digital y su posterior conversión a analógica. Para verificar el funcionamiento del diseño se trabajará con la placa de XILINX FPGA Design Demonstration Board. Se diseñará una placa con el convertidor digital analógico y con los interruptores necesarios para implementar las entradas del generador. 7 Memoria Descriptiva 1.2 Descripción General 1.2.1 Sensores de semiconductor óxido Estos sensores están compuestos de las siguientes partes: Figura 3. Sensor de semiconductor óxido En la resistencia Heater se inyecta una corriente con una forma de onda determinada. Esta corriente provoca una variación de la temperatura en función del tiempo que se mide en el termistor, donde R = Ro·(1+α∆T). Midiendo la resistencia se puede determinar la temperatura. Este tipo de sensor de gases basado en óxido metálico responde en presencia de gases reductores/oxidantes variando la ρ del óxido, fenómeno motivado por la reacción de reducción/oxidación que tiene lugar entre el gas y el óxido. El problema que se plantea es que cuando se observa una variación de resistencia no se puede saber a priori cual ha sido el gas responsable del cambio (baja selectividad). Una manera de afrontar el problema es utilizar el hecho que las reacciones químicas antes mencionadas tienen una temperatura óptima, en principio diferente para cada gas. Por tanto, si se varía de forma controlada la temperatura del sensor y se procesa de forma adecuada su respuesta, se puede llegar a identificar los gases responsables de tal respuesta, ya sean gases simples o mezclas gaseosas. En presencia de gases la variación de la temperatura provoca una variación de conductancia en el sensor de SnO2. La variación de la conductancia implica una variación de la resistencia del sensor, ya que Rsensor = ρ·L/s. Se hace que la superficie sea grande, ya que la conductancia tiene un valor elevado, y de esta forma se consiguen resistencias que se pueden medir, con valores comprendidos entre 100 kΩ y 1 MΩ aproximadamente. Midiendo esta resistencia se puede analizar la respuesta dinámica de ρ en función de la temperatura. Con un análisis exhaustivo de la respuesta mediante redes neuronales se puede realizar una discriminación del tipo de gas y de su concentración. 8 Memoria Descriptiva El objetivo del proyecto es suministrar corriente a la resistencia Heater cuyo valor es de 200 Ω .Esta corriente podrá tener forma triangular, rectangular, de diente de sierra o senoidal con amplitudes de hasta 150 mA, y frecuencias desde 0,1 Hz hasta 10 Hz. La frecuencia debe ser baja debido a que las fluctuaciones de temperatura son lentas. 1.2.2 Introducción al VHDL En esta sección se pretende hacer una pequeña aproximación al VHDL (lenguaje de programación del hardware). Los lenguajes HDL se asemejan bastante a un lenguaje de programación convencional, salvo por algunas diferencia: - Los HDLs describen sistemas concurrentes, en cambio los lenguajes de programación especifican habitualmente sistemas secuenciales. - Los HDLs han comportamiento. - Los HDLs han de permitir la especificación de características y restricciones temporales del sistema. de permitir descripciones estructurales y de 1.2.2.1 Partes Fundamentales En general la descripción de un sistema mediante el lenguaje VHDL se puede considerar constituida por dos partes fundamentales: la declaración del sistema (entity body) y la definición de la arquitectura del sistema (architecture body). La declaración del sistema consiste básicamente en la definición de la interconexión del sistema con otros módulos (puertos de comunicación) y en la declaración de los bloques básicos que componen su estructura. Una vez definida la declaración del sistema, es posible especificar una o diversas implementaciones del mismo mediante la definición de architecture bodies. Es posible definir diversos architecture bodies para un mismo entity bodie, cada uno de los cuales puede reflejar un tipo diferente de descripción del sistema. Un ejemplo de bloque modular descrito por un par entidad/arquitecura podría ser un sumador: entity sumador_1bit is Port( a: in bit; b:in bit; carry_entrada: in bit; suma:out bit; carry_out: out bit ); 9 Memoria Descriptiva architecture dataflow of sumador is begin suma<=a xor b xor carry_entrada; carry_sortida<=a and b or ((a or b) or carry_entrada); end dataflow; La definición estructural de la arquitectura de un sistema se lleva a término mediante dos primitivas básicas: señales(signals) y componentes (component). 1.2.2.2 Componentes Un componente es un elemento funcional básico, que puede estar contenido y descrito en una librería de diseño específica (o, por ejemplo, puede corresponder a un sistema definido previamente mediante las correspondientes definiciones entity y architecture). Un componente se puede declarar de la siguiente manera: component nand3 port(a,b,c:in logic_level; y:out lgic_level); end component; 1.2.2.3 Procesos Dentro de una arquitectura podemos encontrar secuenciales: - procesos y procesos Procesos: Son una serie de sentencias secuenciales que se ejecutan en un orden concreto y son similares a los lenguajes de programación. Se ejecutan de forma concurrente y repetitiva. Process sensitivity list declaration begin stament part part (Lista de señales que activan el proceso) (Declaraciones locales del proceso) (Órdenes secuenciales a ejecutar cada vez que se activa el proceso) end process; La lista de sensibilidad es equivalente a una sentencia wait al final del proceso. No todas las sentencias secuenciales son sintetizables. - Procesos combinacionales: Modelan lógica combinacional y son sensibles a las señales leídas en el proceso. El proceso se reejecuta cada 10 Memoria Descriptiva vez que hay cambios en alguna entrada. Si no es sensible a todas las entradas no es sintetizable. 1.2.2.4 Señales Posibilitan la comunicación entre procesos. El simulador alterna entre actualización de señales y la ejecución de procesos activados por cambios de señales de su lista de sensibilidad. El valor de las señales se mantiene constante durante la ejecución de un proceso. - Una asignación en un proceso genera un ‘event’ que se pone en la cola de eventos de la señal correspondiente. - El simulador no procesa la cola de eventos hasta que todos los procesos se han parado. - Las asignaciones llevan asociadas un retardo. 1.2.2.5 Primitivas de Control Secuencial - Primitiva wait: wait [until condición;] [on nom_senyal1, nom_senyal2, ...;] [for expresión_temporal;] - Primitiva if: If [condición] then [acciones] elsif [acciones] ... end if; - Primitiva case: case [expresión] is when [selección] =>[acciones]; end case; 11 Memoria Descriptiva 1.2.2.6 Ciclo de Diseño con VHDLs A grandes rasgos el ciclo de diseño en este proyecto será el siguiente: Es pecificación VHDL Simulador No ¿ Funciona bien? Si Sintetizador Si ¿ Hay errores ? No Place & Rout FPGA Gravar FPGA Placa de pruebas No ¿ Funciona bien? Si FINAL 12 Memoria Descriptiva 1.2.3 Introducción a la FPGA En este apartado se hará una breve descripción de que es y como está estructurada una FPGA. 1.2.3.1 ¿Qué es una FPGA? FPGA (Field Programable Gate Array) es el nombre genérico que se da a los dispositivos lógicos programables por el usuario que presentan vías de interconexión para conectar bloques internos. Se trata entonces de pequeños bloques funcionales que se interconectan entre ellos a través de una red de interconexiones llamada switch matrix. Los bloques funcionales no tienen relación directa con los pins y se puede conectar cualquier bloque con cualquier pin u otros bloques a través de las vías de conexión. 1.2.3.2 ¿Para qué puede servir? Las FPGA disponen de la posibilidad de hacer funciones lógicas y combinar los resultados con registros con no mucho más límite que el número de recursos libres que queden. Estos resultados se pueden utilizar para hacer otras funciones que se pueden encadenar mientras queden recursos. A diferencia de algunas PALs o PLDs, donde se pueden realizar cierto número limitado de funciones lógicas, ya que a menudo hay un número limitado de suma de productos para cada función y los registros de que disponen están muy ligados a los pins de salida, las FPGA disponen de más flexibilidad y gran capacidad. Por tanto en una FPGA no trataremos de poner cierta parte de nuestro circuito digital, sino que se mirará de poner diseños digitales completos. Las FPGA pueden utilizarse en diseños donde el hardware cambie dinámicamente, o donde se debe adaptar a diferentes aplicaciones del usuario. El hecho de ser programables permite hacer un cambio en su función de manera rápida sin necesidad de cambiar el hardware. Permiten el método de prueba y error, tiempos pequeños para hacer prototipos. No precisan tiempo de espera elevados como puede ser el caso de los ASICs y el coste del software es también mucho más reducido que el diseño con ASICs. 1.2.3.3 ¿Cómo funcionan? A continuación se hará una descripción de los bloques internos de que dispone la familia de FPGA utilizadas. Las FPGA que fabrica XILINX se clasifican en familias, cada familia tiene unos bloques internos comunes, y entre los diferentes integrados de la misma familia sólo varía el número de bloques que tiene cada integrado o la velocidad de este, pero el bloque básico, a nivel funcional, es común para todos los integrados de una misma familia. IOBs: (Input/output Bloc) Son los bloques que sirven de interficie entre los pins del integrado y las CLBs. Estos bloques controlan si el pin es de entrada o salida o si es bidireccional. Permite poner el pin en alta impedancia, hacer un Pullup o 13 Memoria Descriptiva Pulldown o incluso determinar el Slew Rate que se quiere dar al pin. También incluye registros con tal de reducir el número de registros que se utilizan en las CLBs, por si se quiere realizar un latch de los datos del pin. CLBs: (Configurable Logic Bloc) Este es el bloque que permite realizar las funciones lógicas y actuar sobre los registros. Es por tanto aquí donde estará la mayor parte del diseño. En la familia que se utiliza en este proyecto (XC4000) la configuración interna de cada CLB está formada por: - Dos generadores de funciones de cuatro variables. Cada función puede hacer cualquier función lógica de las cuatro variables de entrada. Por tanto es una pequeña PLA. Estas funciones se llaman F y G. - Un generador de funciones de tres variables que permite combinar los resultados de los generadores F y G con otra variable. De esta manera, con una CLB podemos hacer cualquier función de cinco variables combinando las dos de cuatro más la de tres. Pero podemos hacer también algunas funciones de hasta nueve variables (4+4+1). El generador que combina las funciones F y G con la tercera variable se llama función H. - Dos registros, donde podemos guardar el valor de las funciones o conectarlos con otros registros. Estos registros permiten la carga por flanco ascendente o descendente (es programable), tienen una señal de reloj común y también un clock enable común. Además tienen una señal asíncrona que les permite hacer un Set o un Reset al activar esta señal. Los registros son de tipo D y no disponen de salida negada. Estos registros se llaman X i Y. - Generadores de FCL (Fast Carry Logic), esta es una circuitería dedicada que permite hacer la generación de señales de acarreo en operaciones aritméticas de mucha velocidad. - Dos Buffers de alta impedancia, que permiten dejar nodos en alta impedancia y también realizar determinadas funciones, como multiplexores combinando diversos buffers. (Estructuras Wired And). Las CLBs se encuentran dispuestas en forma de matriz (normalmente cuadrada). En la FPGA utilizada la matriz es de 10 x 10. Interconexiones: Estos son los recursos que nos permiten interconectar las CLBs entre ellas y con los IOBs. Básicamente hay de tres tipos. Las cercanas que permiten conectar dos bloques vecinos, las medianas que permiten conectar dos bloques saltándose uno. Finalmente las largas que atraviesan toda la matriz de CLBs y que permiten dividir en dos mitades si se quiere. 14 Memoria Descriptiva 1.2.4 Descripción del Diseño La señal generada (triangular en este caso) tendrá las siguientes características: Figura 4. Señal La amplitud, offset, periodo y desplazamiento serán controladas externamente mediante entradas de 8 bits cada una por especificaciones del diseño. La salida será un valor de 8 bits. Desplazamiento es una característica particular de este generador, y es el tiempo que la señal debe mantenerse en reposo por requerimientos del diseño. Se puede observar que generar esta señal (triangular en este caso) digitalmente equivale a una cuenta ascendente y descendente, por tanto el sistema será secuencial y síncrono donde cada pulso de reloj provocará un incremento o decremento de este contador. Es decir el contador adquirirá valores de 0 a 255 (28 bits) y de 255 a 0: Figura 5. Señal digital Para variar el periodo de la señal existen dos posibles soluciones: 15 Memoria Descriptiva Para hacer la señal más rápida sin variar el periodo del reloj sería necesario hacer el incremento de la cuenta más rápido, es decir, contar de dos en dos, cuatro en cuatro (siempre múltiplos de 2). Es decir pasaríamos por ejemplo del valor “00000000” al “00000010”, “00000100” y así sucesivamente. Contra más rápida sea la cuenta más deformada quedará la señal. La otra solución consiste en generar otro reloj mediante software a partir de la señal de reloj que nos sirve de base de tiempo, en el cual se pueda controlar el periodo de los pulsos. De esta manera se aseguraría siempre una cuenta de 0 a 255. La deformación de la señal se producirá en el eje temporal. Con este sistema se consigue hacer la señal más lenta (periodos más grandes). Se ha optado por la segunda solución. La señal triangular será la señal base y a partir de aquí se obtendrán el resto de señales, rectangular, diente de sierra y senoidal. Los cuatro tipos de señales se generan a la vez, añadiéndose un sistema de multiplexación para seleccionar la señal. Para variar la amplitud de la señal se implementará un multiplicador secuencial de valores de 8 bits, para aplicar a la señal un factor de ganancia entre 0 y 1. La multiplicación de 2 números de 8 bits requiere de 8 ciclos de reloj. Una vez regulada la amplitud se deberá aplicar un offset a la señal. El diseño contendrá los siguientes bloques: - Un contador programable (cont/i/d/desp), que permita mantener a cero durante un tiempo la señal (lo que se ha denominado desplazamiento). Este bloque generará directamente la señal triangular, pero como será el contador principal del generador a partir del cual se generarán todas las señales se le ha denominado de otra forma. Este contador variará su valor a cada flanco ascendente de clk512. - Un bloque divisor por 8, que generará una señal de reloj clk8 a partir de la señal de reloj externa clk. Este bloque permitirá que se produzcan un mínimo de 8 ciclos de clk antes de que se produzca un flanco de clk512, para que durante este tiempo se calcule la multiplicación. - Un divisor de frecuencia que nos permitirá variar la amplitud a voluntad de los pulsos de clk512 generado a partir de clk8. A partir del bloque contador incremental decremental (onda triangular) se generan los cuatro tipos de señal: diente de sierra, rectangular, triangular y senoidal. Además de los bloques mencionados necesitaremos: - Un multiplexor para seleccionar un tipo de señal. - Un bloque amplificador y que permita introducir offset a la señal. El esquema de bloques es el siguiente: 16 Memoria Descriptiva Figura 6. Bloques del generador 1.2.5 Descripción Detallada La entidad en VHDL que engloba todo el esquema es: entity generador is port ( clk,reset:in std_logic; periodo:in std_logic_vector(7 downto 0); amplificacion:in std_logic_vector(7 downto 0); selec:in std_logic_vector(1 downto 0); desplazamiento: in std_logic_vector(7 downto 0); offset:in std_logic_vector(7 downto 0); salidagen:out std_logic_vector(7 downto 0) ); end generador; Código 1: Generador Nota: Todos las entidades síncronas estarán conectadas a la entrada de reset externa, que permitirá dar un valor inicial a los registros para que el sistema arranque adecuadamente. A continuación se explica detalladamente el funcionamiento de cada uno de los bloques anteriores. 17 Memoria Descriptiva 1.2.5.1 Bloque Divisor por 8 Este bloque genera un segundo reloj clk8 a partir de la señal de reloj externa clk. Consiste en un contador de 3 bits con el bit de más peso conectado a la salida. Cada flanco de clk se incrementa en 1 el valor del registro que actúa como contador. Durante 4 ciclos de clk el bit permanece a cero por tanto clk8 = ‘0’. Durante los 4 restantes el bit permanece a uno clk8 = ‘1’. Es decir dividimos por 8 la frecuencia de clk (multiplicamos por 8 su periodo): Tclk8 = 8·Tclk (1) Figura 7. Divisor por 8 Figura 8. Clk8 En el código VHDL corresponderá a la siguiente entidad: entity divisor8 is port ( reset:in std_logic; clk:in std_logic; clk8:out std_logic ); end divisor8; Código 2: Divisor8 1.2.5.2 Bloque Divisor de Frecuencia A partir de clk8 se genera un tercer reloj clk512, donde se controlará la anchura de sus pulsos mediante la entrada periodo. 18 Memoria Descriptiva Figura 9. Divisor de frecuencia El registro de 8 bits es un contador que se va incrementando hasta que alcanza el valor de la entrada periodo. Cuando esto ocurre clk512 varía su valor. Cuando se produce un flanco ascendente de clk8 si el valor del registro es igual al de la entrada periodo se produce un cambio de estado en clk512, pasa de ‘0’ a ‘1’ o viceversa y el registro se carga al valor “00000001”. En caso que sean diferentes se incrementa el contador y clk512 no cambia. Se puede comprobar que si periodo vale “00000001” se producen dos ciclos de clk8 y uno de clk512. Si periodo vale “00000010” se producen cuatro ciclos de clk8 por dos de clk512. Y así sucesivamente. Periodo = “00000001” Figura 10. Clk512 Podemos comprobar entonces que: Tclk512 = 2·periodo·Tclk8 (2) Es decir, Tclk512 podrá variar su valor desde 2·Tclk hasta 512·Tclk. En el código VHDL corresponderá a la siguiente entidad: entity divis_frec is port ( reset:in std_logic; clk8:in std_logic; clk512:out std_logic; periodo:in std_logic_vector(7 downto 0) ); end divis_frec; Código 3: Divisor512 19 Memoria Descriptiva 1.2.5.3 Contador i/d/desp Este es el bloque principal del generador a partir del cual se generan todas las señales. Genera a la salida de 8 bits una cuenta ascendente (0 a 255) y descendente (255 a 0) y permanece a cero según el tiempo establecido por la entrada desplazamiento. Además generará una salida creciente que indicará en que estado de la cuenta se encuentra (ascendente, descendente o a cero). El esquema del bloque es el siguiente: Figura 11. contador i/d/desp Su entidad en VHDL será: entity contador is port( reset:in std_logic; clk512:in std_logic; desplazamiento:in std_logic_vector(7 downto 0); conta0:out std_logic_vector(7 downto 0); creciente:out std_logic_vector(1 downto 0) ); end contador; Código 4: Contador En el bloque generador de estado se produce la siguiente secuencia: 20 Memoria Descriptiva Figura 12. Generador de estado Cuando e1 está a nivel alto ‘1’ indica que se está produciendo una cuenta ascendente. Si es e2 la que está a nivel alto se está produciendo una cuenta descendente, y si en cambio es e3 se está produciendo el periodo en el que la señal está a cero (se está produciendo lo que hemos denominado el desplazamiento de la señal). Cuando se activa f1 indica que ha finalizado la cuenta ascendente y habilita la descendente, cuando acaba la descendente empieza el desplazamiento y cuando este termina repetimos el ciclo. La entidad VHDL es: entity bloque_estado is port( clk512:in std_logic; f1,f2,f3:in std_logic; reset:in std_logic; e1,e2,e3:out std_logic ); end bloque_estado; Código 5:Bloque_estado En el bloque Contador up/dwn como el nombre indica se genera una cuenta ascendente descendente de la siguiente manera: Figura 13. Contador up/dwn 21 Memoria Descriptiva Podemos ver que se trata de un registro de 8 bits que se incrementa o decrementa en ‘1’ según el estado de e1. Con la puerta xor habilitamos una de las cuentas ascendente o descendente cuando uno de los dos bits e1 o e2 está a uno. Las salidas f1 y f2 indican si se ha llegado al final de cuenta ascendente o descendente respectivamente. La entidad VHDL es: entity cont_up_dwn is port( clk512:in std_logic; reset:in std_logic; e1,e2:in std_logic; f1,f2:out std_logic; contupdwn:out std_logic_vector(7 downto 0) ); end cont_up_dwn; Código 6: cont_up_dwn En el bloque cont desp se mantiene la señal del contador i/d/desp a cero hasta que la cuenta alcanza el valor de la entrada exterior desplazamiento: Figura 14. Contador desp. Cuando este bloque está activo se produce una cuenta ascendente hasta que el valor del registro Reg8 es igual al de la entrada de 8 bits desplazamiento, en este momento se activa f3 y se pone a cero el registro a través de la entrada rs. Durante el periodo de tiempo que este bloque está activo la salida del contador i/d/desp estará conectada a Reg8”0” que es un registro donde todos los bits están a cero. La entidad VHDL es: 22 Memoria Descriptiva entity cont_desp is port( clk512:in std_logic; e3,reset:in std_logic; desplazamiento:in std_logic_vector(7 downto 0); reg_cero:out std_logic_vector(7 downto 0); f3:out std_logic ); end cont_desp; Código 7: cont_desp El Multiplexor selecciona a la salida del bloque up/dwn o cont desp según el valor de e3. La entidad VHDL es: entity multiplex2canales is port( e3:in std_logic; canal1,canal2:in std_logic_vector(7 downto 0); salmux:out std_logic_vector(7 downto 0) ); end multiplex2canales; Código 8: multiplex2canales El codificador genera a su salida un registro de dos bits que valdrá “01” si se está produciendo una cuenta ascendente, “10” si es descendente, y “11” cuando se está produciendo el desplazamiento (la señal se mantiene a cero). Este registro será necesario como veremos más adelante para generar todos los tipos de señales. entity codificador is port( e1,e2,e3:in std_logic; creciente:out std_logic_vector(1 downto 0) ); end codificador; Código 9: codificador La señal obtenida en el contador i/d/desp es la siguiente: 23 Memoria Descriptiva Figura 15. Salida del bloque i/d/desp. Teniendo en cuenta que no será así exactamente ya que cada valor digital se mantiene un ciclo de clk512. Con este procedimiento se consigue que el periodo de la señal sea: Tseñal = 512·clk512 (3) El tiempo durante el cual se produce el tiempo de desplazamiento será: Tdesp = desplazamiento·clk512 (4) 1.2.5.4 Diente de Sierra Para generar la señal de diente de sierra y que esta tenga el mismo periodo que la señal triangular es necesario que se produzca una cuenta ascendente en un ciclo de subida y bajada de la señal triangular, e inmediatamente pasar a cero, tal y como indica la figura: 24 Memoria Descriptiva Figura 16. Señal diente de sierra Es decir, la señal debe realizar una cuenta ascendente de 0 a 255 en 512 ciclos de reloj, por tanto se debe incrementar el valor una vez cada dos ciclos de reloj. Es posible generar la señal directamente de los valores de la triangular sin necesidad de crear un segundo contador. El contador de la señal triangular va desde “00000000” hasta “11111111” como se ha comentado anteriormente. Si se desplaza el valor un bit a la derecha la cuenta irá de “00000000” a “01111111” (de 0 a 127), y como se anula el bit de menos peso la cuenta solamente variará cada dos cambios del valor del contador de la triangular. Durante el ciclo de subida de la señal triangular el valor que se ha conseguido desplazando un bit será el valor adecuado para la señal diente de sierra. Durante el ciclo de bajada para contar de 127 a 255 (“01111111” a “11111111”) a partir del valor del contador de la señal triangular restaremos a “11111111” el valor obtenido cuando desplazamos un bit, es decir restaremos primero 127 a 255, obteniendo 128 (“10000000”), después 126 a 255 obteniendo 129 (“10000001”), y así sucesivamente hasta llegar a “11111111”. Utilizaremos el siguiente bloque: 25 Memoria Descriptiva Figura 17. Bloque diente de sierra Su entidad en VHDL es: entity diente_sierra is port ( creciente:in std_logic_vector(1 downto 0); conta0:in std_logic_vector(7 downto 0); conta1:out std_logic_vector(7 downto 0) ); end diente_sierra; Código 10: diente_sierra El bloque funciona de la siguiente manera: Mientras conta0 es creciente (creciente = “01”) asignaremos a la salida los 7 bits de más peso consiguiendo así una cuenta ascendente desde “00000000” hasta “01111111”. Ignorando el bit de menos peso de conta0 hacemos que conta1 se incremente cada dos tics de clk512. Cuando conta0 es decreciente (creciente = “10”) para conseguir que conta1 siga ascendiendo desde “011111111” hasta “11111111” restaremos a “11111111” el valor de los 7 bits de más peso de conta0. Durante el desplazamiento, creciente = “11”, la señal permanece a cero. 1.2.5.5 Rectangular Generar la señal rectangular es muy sencillo, basta con alternar valores entre el máximo y el mínimo, es decir “11111111” y “00000000”. En este diseño se ha decidido que la señal permanecerá al valor máximo mientras la señal triangular realiza un ciclo de subida y bajada, y que permanecerá a cero cuando la señal triangular esté en reposo. Sólo se tendrá que controlar en que estado se encuentra la 26 Memoria Descriptiva señal triangular (si está subiendo o bajando o en reposo) y asignar a la salida el valor “11111111” o “00000000” según el caso. El esquema del bloque será: Figura 18. Bloque rectangular En este bloque generamos una señal rectangular a partir del estado de conta0. Si conta0 es creciente o decreciente la salida estará a “11111111” y si se produce el desplazamiento la salida será “00000000”. De esta manera conseguimos controlar con la entrada desplazamiento el tiempo que está a nivel bajo. La entidad VHDL es: entity rectangular is port ( creciente:in std_logic_vector(1 downto 0); conta2:out std_logic_vector(7 downto 0) ); end rectangular; Código 11: rectangular La señal obtenida será la siguiente: 27 Memoria Descriptiva Figura 19. Salida del bloque rectangular 1.2.5.6 Triangular Como se puede intuir fácilmente la señal triangular no es más que el contador i/d/desp en sí. Por tanto lo único que debemos hacer es una asignación de conta0 a conta3. Figura 20. Bloque triangular La entidad es: entity triangular is port ( conta0:in std_logic_vector(7 downto 0); conta3:out std_logic_vector(7 downto 0) ); end triangular; Código 12: triangular 1.2.5.7 Senoide Generar la señal senoidal es un proceso más complejo que los anteriores. Si se pretende que la señal senoidal tenga el mismo periodo que la triangular y esté 28 Memoria Descriptiva comprendida entre “00000000” y “11111111” tendrá que tener las siguientes características: Figura 21. Señal senoidal El proceso más adecuado para generar una señal senoidal es crear una tabla de valores donde cada valor de la tabla tenga almacenado el correspondiente valor de la senoide. Esto se consigue utilizando una memoria ROM que se direccionará con un contador. En nuestro caso lo ideal sería tener una ROM de 256 valores comprendidos entre "00000000” y “11111111” (8 bits) para generar la mitad de la senoide en un ciclo de subida de la señal triangular y la otra mitad en un ciclo de bajada. Posteriormente sólo se debería realizar una inversión del segundo semiperiodo para que la señal fuera la adecuada. El problema está en que una ROM de 256 valores consumiría mucho espacio al ser implementada en una FPGA. La solución consiste en almacenar solamente un cuarto de la señal senoidal, así en lugar de 256 valores deberíamos almacenar sólo 128. Pero para optimizar todavía más los recursos se utilizará una ROM de 64 valores (26 bits) comprendidos entre “00000000” y “11111111”. Para direccionar la memoria se debe generar a partir del contador de la señal triangular un contador de las siguientes características: 29 Memoria Descriptiva Figura 22. Direccionamiento de la ROM Durante 128 cuentas de la señal triangular la dirección debe realizar una cuenta de 64 valores, de “000000” a “111111”. En el primer cuarto es sencillo, se deben asignar a la dirección 6 bits del contador de la triangular, del 6 al 1. No asignando el bit de menos peso (0) se conseguirá que el incremento de la dirección se produzca cada dos cuentas del contador. En el segundo cuarto la señal triangular cuenta desde “1000000” a “11111111”, por tanto los seis bits seleccionados anteriormente repiten la cuenta de “000000” a “111111”. Pero ahora necesitamos que la ROM se direccione en sentido inverso, por tanto si restamos a 127 (“111111”) la cuenta de 0 (“000000”) a 63 (“111111”) obtendremos valores desde “11111” a “000000”. En el tercer y cuarto cuadrante hemos de repetir el procedimiento, pero teniendo en cuenta que el valor de la triangular va ahora desde “11111111” a “00000000”. Por tanto en el tercer cuadrante realizaremos la misma resta descrita anteriormente y en el cuarto asignaremos a la dirección directamente los mismos 6 bits del contador de la triangular. Con el procedimiento descrito conseguiremos la siguiente señal: 30 Memoria Descriptiva Figura 23. Contenido de la ROM Sólo quedará ahora invertir el segundo semiperiodo para que la señal tenga la forma deseada. Esto es sencillo, sólo hemos de restar a “11111111” el contenido de la ROM. Se utiliza el siguiente bloque: Figura 24. Bloque Senoide El bloque senoide no tiene equivalencia en VHDL, ya que a la hora de programar se han implementado los tres bloques por separado. Para generar la señal senoidal utilizaremos una memoria ROM de 64 bytes, donde guardaremos 64 valores de salida que corresponderán a un cuarto de periodo de la señal. Estas 64 posiciones de memoria se direccionarán con 6 bits. Para obtener el semiperiodo positivo deberemos direccionar la ROM una vez ascendentemente y otra descendentemente. Direccionaremos la memoria a partir de la cuenta generada por el bloque contador (conta0). 31 Memoria Descriptiva Para obtener el semiperiodo negativo deberemos invertir los valores obtenidos de la ROM. En el bloque senoidal se generan los 6 bits que direccionarán la ROM. En el tiempo que conta0 realiza un ciclo de subida (creciente = “01”) dirección habrá realizado una cuenta ascendente y otra descendente. Cuando conta0 es decreciente (creciente = “10”) dirección repite el ciclo. Para conseguir que la señal senoidal tenga el mismo periodo que la triangular se ha de tener en cuenta que para producir un cuarto de señal senoidal se direccionan 64 valores, en cambio conta0 en un cuarto de señal triangular realiza 128 cuentas. La solución consiste en realizar un direccionamiento cada dos cuentas de conta0, y esto se consigue ignorando el bit de menos peso de conta0. El procedimiento seguido es el siguiente: Si conta0 es menor de 128, es decir, el bit de más peso es cero y creciente = “01”, o si es mayor de 128 (el bit de más peso es 1) y creciente = “10” (primero y tercer cuarto de la señal senoidal) los 6 bits de menos peso de conta0 (ignorando el último como se ha comentado antes) tienen el valor requerido, por tanto los asignamos a la salida (dirección). Si no se cumplen los casos anteriores restaremos a “111111” el valor de los seis bits de menos peso de conta0. Se puede comprobar que de esta manera direccion realiza una cuenta de “000000” a “111111” y de “111111” a “000000” cuando conta0 es creciente y otro ciclo igual cuando es decreciente. Como en los casos anteriores cuando creciente = “11” la salida permanecerá a cero (“000000”), ya que la asignamos directamente a la entrada conta0. Con este proceso conseguiremos que la señal senoidal tenga el mismo periodo que la triangular. Figura 25. Bloque Senoidal 32 Memoria Descriptiva La entidad VHDL es: entity senoidal is port ( creciente:in std_logic_vector(1 downto 0); conta0:in std_logic_vector(7 downto 0); direccion:out std_logic_vector(5 downto 0) ); end senoidal; Código 13: senoidal La salida de este bloque será entonces: Figura 26. Salida del bloque Senoidal A cada valor de dirección el bloque ROM genera a la salida el correspondiente valor de 8 bits de la memoria. Figura 27. ROM 33 Memoria Descriptiva La entidad VHDL es: entity ROM is port ( direccion:in std_logic_vector(5 downto 0); contenido:out std_logic_vector(7 downto 0) ); end ROM; Código 14: ROM A la salida de la ROM obtendremos por tanto la siguiente señal: Figura 28. Salida del bloque ROM El bloque inversor funciona de la siguiente manera: En el primer semiperiodo la salida de la ROM es la necesaria. En cambio, cuando el bloque anterior genera el segundo semiperiodo (creciente = “10”) debemos invertirlo para conseguir el semiperiodo negativo de la señal senoidal. Para ello hemos de restar al valor máximo de la señal (“11111111”) la salida generada por la ROM, como muestra el esquema : 34 Memoria Descriptiva Figura 29. Inversor La entidad VHDL es: entity inversor is port ( creciente:in std_logic_vector(1 downto 0); contenido:in std_logic_vector(7 downto 0); conta4:out std_logic_vector(7 downto 0) ); end inversor; Código 15: Inversor La salida de este bloque será: Figura 30. Salida del bloque Inversor 35 Memoria Descriptiva 1.2.5.8 Multiplexor Este componente seleccionará una los cuatro tipos de señales según el valor de la entrada selec: - “00” Diente de sierra - “01” Rectangular - “10” Triangular - “11” Senoidal Figura 31. Multiplexor Su entidad VHDL es: entity multiplexor is port( A:in std_logic_vector(7 downto 0); B:in std_logic_vector(7 downto 0); C:in std_logic_vector(7 downto 0); D:in std_logic_vector(7 downto 0); selec:in std_logic_vector(1 downto 0); salida_mult:out std_logic_vector(7 downto 0) ); end multiplexor; Código 16: Multiplexor 1.2.5.9 Amplificador-offset Para aplicar un factor de ganancia se realiza una multiplicación secuencial del valor de la señal por un factor externo amplificación. Una multiplicación de dos valores de 8 bits produce a su salida, como máximo, un valor de 16 bits y necesita 8 ciclos de reloj para realizar las sucesivas sumas que requiere. 36 Memoria Descriptiva El margen de trabajo del factor de ganancia está comprendido entre 0 y 1, es decir, el generador proporcionará un valor máximo de salida que podremos atenuar. Volviendo a las especificaciones del diseño, necesitamos 150 mA de amplitud máxima. Los 16 bits del resultado de la multiplicación podrían proporcionar intensidades comprendidas entre 2.28·10-3 mA y 65536·2.28·10-3 mA = 150 mA. No interesa una resolución tan alta de la señal, por tanto cogeremos sólo los 8 bits de más peso del resultado de la multiplicación. Este bloque está dividido en otros cuatro como se muestra en la figura 20. El amplificador se encarga de realizar la multiplicación digital iniciada por el bloque inicio. El sumador añade el offset al resultado de la multiplicación. El limitador evita que se exceda el valor máximo de salida al sumar el offset, recortando la señal cuando sea necesario. Figura 32. Amplificador_offset La entidad VHDL será: entity amplif_offset is port ( reset:in std_logic; clk,clk512:in std_logic; offset:in std_logic_vector(7 downto 0); amplificacion:in std_logic_vector(7 downto 0); multiplicando:in std_logic_vector(7 downto 0); sal_amp_off:out std_logic_vector(7 downto 0) ); end amplif_offset; Código 17: amplif_offset La multiplicación es un proceso que requerirá 8 flancos de reloj, por tanto el bloque amplificador debe trabajar con un reloj más rápido (clk) de manera que cuando se produzca un flanco del reloj principal del sistema (clk512) se hayan producido un mínimo de 8 flancos de clk para poder realizar la multiplicación. Como el nombre indica el bloque inicio se encarga de iniciar la multiplicación. 37 Memoria Descriptiva Cada vez que se produce un flanco de subida de clk512 se genera un ‘1’ en start indicando al bloque amplificador que puede iniciar la multiplicación. En cuanto se produce el primer flanco de clk la señal start vuelve a cero para evitar que se reinicie de nuevo el sistema. Como vemos en la figura está compuesto por dos biestables y una puerta xor: Figura 33. Inicio Este bloque no tiene entidad VHDL, puesto que está integrado dentro del bloque amplificador. El bloque amplificador realiza una multiplicación de dos valores de 8 bits. Al multiplicar dos valores de 8 bits pueden generar un valor de 16 bits, por tanto lo lógico sería utilizar registros de 16 bits. Para economizar recursos se utilizan registros de 10 bits, puesto que al final sólo interesarán los 8 bits de más peso. El registro de salida es el acumulador que sumará o no el valor de la entrada amplificación según el valor del bit de la entrada sal_mux. Cuando start se activa los valores a multiplicar se cargan en los registros. Amplificacion se carga en un registro rotatorio de 10 bits donde a cada flanco de clk el valor se desplaza un bit a la derecha. La salida del multiplexor se carga en un registro rotatorio de 8 bits. Este último registro se desplaza un bit a la izquierda a cada flanco de clk. Al registro acumulador de salida se le suma, o no, el valor del registro rotatorio de 10 bits, según el valor del bit de más peso del registro de 8 bits sea ‘1’ o ‘0’. 38 Memoria Descriptiva Figura 34. Amplificador La entidad VHDL es: entity amplificador is port( reset:in std_logic; clk:in std_logic; clk512:in std_logic; amplificacion:in std_logic_vector(7 downto 0); multiplicando:in std_logic_vector(7 downto 0); resultado:out std_logic_vector(9 downto 0) ); end amplificador; Código 18: amplificador Nota: La entrada multiplicando se corresponde con la entrada sal_mux del esquema. La salida resultado se corresponde con la salida1 del esquema. La entrada start no aparece en la entidad puesto que, como se ha comentado anteriormente, en el código VHDL se ha integrado el bloque inicio en el bloque amplificador. Obsérvese que la multiplicación se realiza en orden inverso, es decir, del valor más significativo al menos significativo. De esta forma se consigue no introducir error al utilizar registros de 10 bits en lugar de 16, puesto que como se ha comentado anteriormente sólo interesan los 8 bits de más peso del resultado. 39 Memoria Descriptiva En el bloque sumador se trunca el resultado de la multiplicación de 10 a 8 bits para posteriormente sumarle el offset (tal y como se ha explicado anteriormente sólo nos interesan los 8 bits de más peso). Trabajaremos con registros de 9 bits ya que la suma de dos valores de 8 bits puede generar un valor de 9. Figura 35. Sumador Este bloque se implementa en dos entidades, una para hacer la adquisición de datos y otra para realizar la suma: entity adquisicion is port( offset:in std_logic_vector(7 downto 0); sal_amp:in std_logic_vector(9 downto 0); operandoA:out unsigned(8 downto 0); operandoB:out unsigned(8 downto 0) ); end adquisicion; Código 19: adquisición entity sumador9bits is port( sumandoA:in unsigned(8 downto 0); sumandoB:in unsigned(8 downto 0); salida2:out std_logic_vector(8 downto 0) ); end sumador9bits; Código 20: sumador9bits 40 Memoria Descriptiva En el bloque limitador cuando el bit de más peso de la entrada es ‘1’ indica que al sumar el offset hemos sobrepasado el valor máximo de salida, por tanto se recorta la señal manteniéndola al valor máximo posible (“11111111”). Figura 36. Limitador La entidad VHDL es: entity limitador is port( entrada:in std_logic_vector(8 downto 0); salida3:out std_logic_vector(7 downto 0) ); end limitador; Código 21: Limitador El funcionamiento del bloque amplificador offset quedará más claro en los siguientes ejemplos: Ejemplo1: Supongamos que introducimos un valor de amplificación de “11111111”, es decir no queremos atenuar la señal y queremos que sus valores varíen entre “00000000” y “11111111” y añadimos un offset de “00000100”. En este caso la señal resultará: Figura 37. Señal recortada 41 Memoria Descriptiva Ejemplo2: Supongamos que introducimos un valor de amplificación “11100111”, es decir queremos atenuar la señal y queremos que sus valores varíen entre “00000000” y “11100111” y añadimos un offset de “00000100”. En este caso la señal resultará: Figura 38. Señal atenuada 42 Memoria Descriptiva 1.2.6 Convertidor DA Para convertir el valor de 8 bits de salida del generador digital se utilizará un convertidor DA con las siguientes características: Figura 39. Convertidor DA La salida proporcionará una corriente de Iref·n/256, donde n será un valor entre 0 y 255 proporcionado por la salida de la FPGA. Cuando la entrada digital sea “11111111” Io proporcionará el valor máximo de corriente (Iref). El convertidor elegido ha sido un DAC08Q, debido a su reducido coste y a sus características que se adecuan a las especificaciones del diseño. Proporciona velocidades de conversión de hasta 1 µs. Teniendo en cuenta los periodos con los que trabajamos, esta velocidad de conversión será más que suficiente. A la salida del convertidor DA sería necesaria una etapa de potencia que amplificara la intensidad Iref hasta los 150 mA requeridos. 43 Memoria Descriptiva 1.2.7 Placa de Pruebas Para verificar el correcto funcionamiento del generador de funciones se ha diseñado una placa que, conectada a la placa de XILINX(FPGA demonstration board), permite introducir entradas a la FPGA y recibir la salida digital para su conversión a analógica Vo que podrá ser visualizada en el osciloscopio. Figura 40. Amplificador de corriente El banco de interruptores S1 corresponde a la entrada del generador amplificacion. LO y HI indica la posición en que el interruptor proporciona un ‘0’ o un ‘1’ lógico respectivamente (+5V o 0V), en este caso cuando el interruptor está cerrado proporciona un ‘0’ y cuando está abierto proporciona un ‘1’. El interruptor marcado con un 1 corresponde al bit de más peso de la entrada. De izquierda a derecha obtenemos desde amplificación(7) hasta amplificacion(0). S2 corresponde a la entrada periodo. El primer interruptor por la izquierda corresponde también al bit de más peso. Cuando el interruptor está abierto proporciona un ‘0’ y cuando está cerrado un ‘1’. S3 es la entrada desplazamiento. Igual que en las entradas anteriores el primer interruptor de la izquierda corresponde al bit de más peso. En S4 el primer interruptor de la izquierda corresponde a la entrada de reset del generador, y los dos siguientes a la entrada de selección de señal, selec(1) y selec(0) respectivamente. Nota: La entrada de offset la proporcionará el banco de interruptores SW-3 de la placa de XILINX. El primer interruptor empezando por arriba corresponde al bit de más peso offset(7). Para localizar SW-3 remitirse al plano de situación de componentes de la placa FPGA demonstration board. 44 Memoria Descriptiva JP1,JP2, y JP3 son conectores de 22 pins que permiten la conexión mediante cable de bus con la placa de XILINX (FPGA design demonstration board). Vcc es la alimentación de 5 V que permite introducir ‘1’ y ‘0’ lógicos. Vref son los 10 V que necesita el convertidor DA para proporcionar una intensidad de referencia de 2 mA. V+ y V- corresponden a la alimentación del convertidor DA, +15 y –15 respectivamente. Vo es la salida que proporciona el convertidor. Será una tensión con la forma de onda seleccionada y comprendida entre 0 y –10 V. 1.2.7.1 Conexión del Convertidor DA Como se ha comentado anteriormente, este proyecto se centra en la generación de la señal digital y su posterior conversión a analógica, por tanto en la placa de pruebas se conecta el convertidor DA de la siguiente manera: Figura 41. Conexión del Convertidor DA Utilizando la resistencia adecuada se podrá visualizar la señal en el osciloscopio y verificar que el generador de funciones se comporta de la forma esperada. La tensión generada a la salida será negativa, puesto que la corriente es entrante al convertidor. 45 Memoria Descriptiva 1.2.7.2 Conexión de los Interruptores Los interruptores de S1 y S4 están conectados a pins de la FPGA que por defecto tienen la siguiente configuración en la placa de XILINX: Figura 42. Pin conectado a LED Cuando el pin se utiliza como salida, según si proporciona un “0” o un “1” (5 V o 0V) el diodo LED se enciende o no. Cuando se utiliza como entrada, como es el caso el pin permanece en alta impedancia, por tanto se produce un divisor de tensión entre la resistencia de 560 Ω y una resistencia de valor muy elevado, quedando a la entrada del pin aproximadamente 5 v. Es decir, por defecto el pin tiene asignado un “1” lógico. Por tanto si conectamos el interruptor de la siguiente manera: Figura 43. Conexión de S1 se consigue que cuando el interruptor está cerrado hay una conexión directa a masa. Es decir, cuando el interruptor está abierto hay un “1” lógico y cuando está cerrado un “0”. Los interruptores de S2 y S3 en cambio, están conectados a pins que no tienen por defecto asignados ningún valor de tensión. Cuando se utilizan como entrada, estos pins permanecen en alta impedancia. Para poder introducir “1” y “0” lógicos se deben utilizar resistencias de Pull Up conectadas a los interruptores, tal y como muestra la figura : 46 Memoria Descriptiva Figura 44. Conexión de S2 Cuando el interruptor esté cerrado proporcionará un “1” lógico (5V) y cuando esté abierto un “0”. 1.2.7.3 Correspondencia de Pins entre la Placa de XILINX y la Placa de Pruebas El pin 13 de la FPGA se utiliza como entrada externa de reloj. Los pins 19,20,23,24,25,26,27,28 están conectados al banco de interruptores SW-3 en la placa de XILINX. 1.2.8 Programación de la FPGA La placa de XILINX (FPGA design demonstration board) contiene dos FPGA, la XC3020A y la XC4003E. Estas pueden programarse de 4 formas diferentes: - Con el Xchecker/Parallel cable III: Este cable se conecta al ordenador y permite descargar en la FPGA el archivo con extensión .BIT generado al sintetizar el código VHDL. 47 Memoria Descriptiva - Con una PROM serie (programa único): El programa se carga en la FPGA desde una PROM que ha sido gravada previamente. - Con una PROM serie (programa múltiple): Este modo de programación permite tener gravados varios programas diferentes en la PROM y poder cargar en la FPGA cualquiera de ellos, permitiendo de esta manera alternar a la FPGA entre varias funciones diferentes. - En daisy chain: Permite utlizar ambas FPGA a la vez conectadas entre ellas en modo daisy chain. Para verificar el diseño sólo se necesita una FPGA, por tanto utilizaremos la XC4003E. La programación se realiza a través del cable Xchecker. 1.2.8.1 Configuración de la XC4003E a través del Xchecker/Parallel cable III Para gravar la FPGA a través del cable paralelo es necesario situar los pins de los interruptores SW1 y SW2 de la siguiente manera: Interruptor Nombre Posición Interruptor Nombre Posición SW1-1 INP X SW2-1 PWR X SW1-2 MPE X SW2-2 MPE OFF SW1-3 SPE X SW2-3 SPE OFF SW1-4 MO X SW2-4 MO ON SW1-5 M1 X SW2-5 M1 ON SW1-6 M2 X SW2-6 M2 ON SW1-7 MCLK OFF SW2-7 RST X SW1-8 DOUT OFF SW2-8 INIT OFF La X indica que no importa la posición. Nota: Para una información precisa del funcionamiento de la placa de demostración remitirse a la Hardware User Guide of the FPGA Design Demonstraton Board de la compañía XILINX. 48 Memoria de Cálculo 2 Memoria de Cálculo 2.1 Cálculo de la Frecuencia del Reloj Externo En el apartado 1.2.4.1 se ha obtenido la expresión (1) Tclk8 = 8·Tclk y en el apartado 1.2.4.2 la expresión (2) Tclk512 = 2·periodo·Tclk8. A partir de estas expresiones se puede comprobar que: Tclk512 = 16·periodo· Tclk8 (5) En el apartado 1.2.4.4 se han obtenido las expresiones (3) Tseñal=512·Tclk512 y (4) Tdesp = desplazamiento·Tclk512. A partir de la expresión (5) se obtiene que: Tseñal = 512·16·periodo·Tclk (6) Tdesp = desplazamiento ·16·periodo·Tclk512 (7) El diseño requiere un periodo mínimo de señal de 0.1 s, que será cuando la entrada externa periodo valga “00000001”. En este caso: 0,1 = 512·16·1·Tclk Tclk = 12.2 µs Es decir, necesitamos un reloj externo de frecuencia 81,92 kHz. La entrada externa periodo es un valor comprendido entre 0 y 255, por tanto con este reloj conseguiremos periodos de señal de: Tseñal = 0,1·periodo (8) Es decir valores comprendidos entre 0,1 s y 25.5 s. Ajustándose a las especificaciones del diseño. El tiempo durante el cual la señal permanece en reposo (Tdesp) comprenderá valores entre 0.05 s y 12.75 s. 2.2 Frecuencia del Reloj Externo para la Verificación del Diseño Con los periodos obtenidos en el apartado anterior no sería posible visualizar la señal en el osciloscopio, por tanto para realizar la comprobación del correcto funcionamiento del generador de funciones se utiliza una señal de reloj externa de 10 Mhz, es decir 10µ µs de periodo. A partir de la expresión (6) comprobamos que: Tseñal = 512·16·periodo·6·10-6 (9) Obteniendo periodos comprendidos entre 49,15 µs y 12.53 ms. O lo que es lo mismo frecuencias comprendidas entre 20,346 kHz y 79,8 Hz. Frecuencias que pueden visualizarse sin problemas en el osciloscopio. 49 Memoria de Cálculo 2.3 Cálculo de los Valores de la ROM Para conseguir los 64 valores de la onda senoidal comprendidos entre “00000000” y “11111111” (0 y 255 en decimal) calcularemos con Excel una tabla con 64 puntos significativos de una función senoidal, obteniendo los siguientes resultados: Senoide 300 250 200 150 Senoide 100 50 0 1 7 13 19 25 31 37 43 49 55 61 Figura 45. Gráfica de la senoide 50 Memoria de Cálculo 0 127 27 205 54 250 1 130 28 207 55 250 2 133 29 209 56 251 3 136 30 212 57 252 4 139 31 214 58 252 5 142 32 216 59 253 6 145 33 218 60 253 7 148 34 221 61 253 8 151 35 223 62 253 9 154 36 225 63 253 10 157 37 227 11 160 38 229 12 163 39 230 13 166 40 232 14 169 41 234 15 172 42 235 16 175 43 237 17 178 44 239 18 181 45 240 19 184 46 241 20 186 47 243 21 189 48 244 22 192 49 245 23 194 50 246 24 197 51 247 25 200 52 248 26 202 53 249 Tabla1. Valores de la ROM 51 Memoria de Cálculo 2.4 Cálculo de Componentes para el Convertidor DA En el diseño se utiliza un DAC08. Este convertidor necesita una intensidad de referencia de 2 mA que se suministra de la siguiente manera: Figura 46. Iref del cDA La tensión de referencia Vref es de 10 V, por tanto: Rref = 10 V /2 mA = 5 kΩ Ω La intensidad de salida variará por tanto entre 0 y 2 mA. Posteriormente sólo se necesitaría una etapa de potencia de ganancia 75 para proporcionar los 150 mA requeridos por el diseño. 2.5 Convertidor DA en la Placa de Pruebas Figura 47. Vo del cDA Sabiendo que Io varía entre 0 y 2 mA, utilizando una RL de 5 kΩ Ω , podremos visualizar en el osciloscopio valores de tensión comprendidos entre 0 y –10 V. 52 Memoria de Planos 3 Memoria de Planos 3.1 Placa de Pruebas 3.1.1 Situación de Componentes 53 Memoria de Planos 3.1.2 Esquema Eléctrico de ORCAD. 54 Memoria de Planos 3.1.3 Listado de Componentes Item Cantidad Referencia Parte 1 1 DAC DAC08EQ 2 3 JP1,JP2,JP3 HEADER 11x2 3 2 RN1,RN2 ARRAYS 4K7 4 1 C1 0.01 u 5 2 C2,C3 0.1 u 6 4 S1,S2,S3,S4 SW DIP-8 7 3 RG1,RG2,RG3 REGLETAS-x2 Todas las resistencias son de carbono ¼ W y 10% de tolerancia. Condensadores C1,C2,C3 de poliester. Conectores JP1 y JP2 Headers de pins machos para PCB. DAC08EQ convertidor digital analógico estándar con salida de corriente. RN1,RN2 arrays de 9 pins y 8 resistencias con masa común. RG1,RG2,RG3, regletas comunes de 2 conexiones. 55 Memoria de Planos 3.2 FPGA Design Demonstration Board 3.2.1 Situación de Componentes 56 Memoria de Planos 3.2.2 Esquema Eléctrico 57 Memoria de Planos 3.3 Diagrama de Conexión General Este diagrama está con la finalidad de facilitar la interpretación de cómo hay que unir la placa de pruebas con la placa de XILINX (FPGA demonstration board). Es necesario fijarse en la posición de los buses y los conectores que los unen. Los pins marcados en negro son los pins que nos se utilizan y que pueden servir de referencia para el conector del bus. 58 Anexos 4 Anexos 4.1 Código VHDL y simulación con VERIBEST La simulación del generador se realiza con el paquete de software VERIBEST. El VHDL tiene estructura jerárquica, es decir, una entidad no puede contener un componente que no haya sido declarado previamente. Siempre hay una entidad principal que engloba y relaciona el resto de entidades. En este caso se trata de la entidad generador: Cada una de estas entidades contiene a su vez otras como se irá viendo. A continuación se mostrará el código de cada entidad y de su correspondiente arquitectura junto con su simulación. Nota: Todas las entidades utilizan las librerías estándar del IEEE: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; 4.1.1 clk Para realizar la simulación es necesario simular una señal de reloj. En este caso se ha optado por una de 1µs, para que la simulación sea más rápida. --- Declaración del reloj --entity reloj is port ( clk:out std_logic ); end reloj; --- Temporizacion del reloj --architecture tiempo of reloj is 59 Anexos begin clock_driver:process begin clk<='0','1' after 0.5 us; wait for 1 us; end process clock_driver; end tiempo; 4.1.2 Divisor por 8 --- divisor por 8 --entity divisor8 is port ( reset:in std_logic; clk:in std_logic; clk8:out std_logic ); end divisor8; architecture clock8 of divisor8 is signal contador:unsigned(2 downto 0); begin process (clk,reset) begin if (reset='1') then contador<="000"; clk8<='0'; elsif (clk' event and clk ='1') then contador<=contador + 1; clk8<=std_logic(contador(2)); 60 Anexos end if; end process; end clock8; La simulación de esta entidad es: 4.1.3 Divisor de frecuencia --- Declaración del divisor de frecuencia --entity divis_frec is port ( reset:in std_logic; clk8:in std_logic; clk512:out std_logic; periodo:in std_logic_vector(7 downto 0) ); end divis_frec; --- divisor de frecuencia --architecture clock512 of divis_frec is signal periodo_aux: unsigned (7 downto 0); signal clk512aux:std_logic; begin process (clk8,reset) begin if (reset ='1') then periodo_aux<="00000001"; 61 Anexos clk512aux<='0'; elsif (clk8' event and clk8 ='1') then if (periodo="00000000") then clk512aux<=clk512aux; periodo_aux<="00000001"; elsif ((periodo_aux)=unsigned(periodo)) then clk512aux<=not(clk512aux); periodo_aux<="00000001"; else clk512aux<=clk512aux; periodo_aux<=periodo_aux+1; end if; end if; end process; clk512<=clk512aux; end clock512; La simulación de esta entidad con una entrada de periodo “00000001” es: 4.1.4 Contador i_d_desp Esta entidad está compuesta por otras 5: ---- conjunto (contador incremental_decremental con desplazamiento de señal entity contador is port( reset:in std_logic; 62 Anexos clk512:in std_logic; desplazamiento:in std_logic_vector(7 downto 0); conta0:out std_logic_vector(7 downto 0); creciente:out std_logic_vector(1 downto 0) ); end contador; architecture secuencia_principal of contador is signal e1,e2,e3:std_logic; signal f1,f2,f3:std_logic; signal canal1,canal2:std_logic_vector(7 downto 0); component bloque_estado port( clk512:in std_logic; f1,f2,f3:in std_logic; reset:in std_logic; e1,e2,e3:out std_logic ); end component; component cont_up_dwn port( clk512:in std_logic; reset:in std_logic; e1,e2:in std_logic; f1,f2:out std_logic; contupdwn:out std_logic_vector(7 downto 0) ); end component; component cont_desp port( clk512:in std_logic; e3,reset:in std_logic; desplazamiento:in std_logic_vector(7 downto 0); reg_cero:out std_logic_vector(7 downto 0); f3:out std_logic 63 Anexos ); end component; component multiplex2canales port( e3:in std_logic; canal1,canal2:in std_logic_vector(7 downto 0); salmux:out std_logic_vector(7 downto 0) ); end component; component codificador port( e1,e2,e3:in std_logic; creciente:out std_logic_vector(1 downto 0) ); end component; begin be:bloque_estado port map(clk512=>clk512,reset=>reset,f1=>f1, f2=>f2,f3=>f3,e1=>e1,e2=>e2,e3=>e3); cud:cont_up_dwn portmap(clk512=>clk512,reset=>reset,e1=>e1,e2=>e2,f1=>f1,f2=>f2, contupdwn=>canal1); cd:cont_desp port map(reset=>reset,clk512=>clk512,e3=>e3, f3=>f3,desplazamiento=>desplazamiento,reg_cero=>canal2); m2c:multiplex2canales port map(e3=>e3,canal1=>canal1,canal2=>canal2,salmux=>conta0); codif:codificador port map(e1=>e1,e2=>e2,e3=>e3,creciente=>creciente); end secuencia_principal; 64 Anexos La simulación de esta entidad con una entrada de desplazamiento “00000000” es: Se puede observar el momento en que el contador llega al valor máximo y comienza a decrecer. 4.1.4.1 Generador de estado ---- generador de estado ----library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity bloque_estado is port( clk512:in std_logic; f1,f2,f3:in std_logic; reset:in std_logic; e1,e2,e3:out std_logic ); end bloque_estado; architecture gen_estado of bloque_estado is begin process (reset,clk512) begin if (reset='1') then e1<='1'; e2<='0'; e3<='0'; else 65 Anexos if (clk512' event and clk512='1') then if (f1='1') then e1<='0'; e2<='1'; e3<='0'; else if (f2='1') then e1<='0'; e2<='0'; e3<='1'; else if (f3='1') then e1<='1'; e2<='0'; e3<='0'; end if; end if; end if; end if; end if; end process; end gen_estado; En la simulación de esta entidad se puede observar la transición del contador de creciente a decreciente: 66 Anexos 4.1.4.2 Contador up/dwn ---- contador incremental_decremental ----entity cont_up_dwn is port( clk512:in std_logic; reset:in std_logic; e1,e2:in std_logic; f1,f2:out std_logic; contupdwn:out std_logic_vector(7 downto 0) ); end cont_up_dwn; architecture arc_cont_up_dwn of cont_up_dwn is signal contaux: unsigned(7 downto 0); signal maximo: unsigned(7 downto 0); signal minimo: unsigned(7 downto 0); begin maximo<="11111101"; minimo<="00000010"; process (clk512,reset) begin if (reset='1') then 67 Anexos contaux<="00000000"; f1<='0'; f2<='0'; maximo<="11111101"; minimo<="00000010"; else if (clk512' event and clk512='1') then if ((e1 xor e2)='1') then case e1 is when '1' => contaux<=contaux + 1; when others => contaux<=contaux - 1; end case; if (contaux=maximo and (e1='1')) then f1<='1'; else f1<='0'; end if; if (contaux=minimo and (e2='1')) then f2<='1'; else f2<='0'; end if; end if; end if; end if; end process; contupdwn<=std_logic_vector(contaux); end arc_cont_up_dwn; 68 Anexos Se puede observar un ciclo de transición del contador. 4.1.4.3 Contador de desplazamiento ---- contador de desplazamiento ---entity cont_desp is port( clk512:in std_logic; e3,reset:in std_logic; desplazamiento:in std_logic_vector(7 downto 0); reg_cero:out std_logic_vector(7 downto 0); f3:out std_logic ); end cont_desp; architecture arc_cont_desp of cont_desp is signal contadesp:unsigned(7 downto 0); begin reg_cero<="00000000"; process(clk512,reset) begin if (reset = '1') then contadesp<="00000000"; f3<='0'; 69 Anexos else if (clk512' event and clk512='1') then if (e3='1') then if (contadesp=unsigned(desplazamiento)) then contadesp<="00000000"; f3<='1'; else contadesp<= contadesp + 1; f3<='0'; end if; else contadesp<=contadesp; f3<='0'; end if; end if; end if; end process; end arc_cont_desp; La simulación de esta entidad cuando la entrada desplazamiento es “00000001” es la siguiente : 70 Anexos 4.1.4.4 Multiplexor de dos canales entity multiplex2canales is port( e3:in std_logic; canal1,canal2:in std_logic_vector(7 downto 0); salmux:out std_logic_vector(7 downto 0) ); end multiplex2canales; architecture arc_multiplex2canales of multiplex2canales is begin process (e3,canal1,canal2) begin case e3 is when '0' => salmux<=canal1; when others => salmux<=canal2; end case; end process; end arc_multiplex2canales; Esta entidad simplemente selecciona la salida del cont up/dwn o del contador desplazamiento. 71 Anexos 4.1.4.5 Codificador ---- codificacion del estado ----entity codificador is port( e1,e2,e3:in std_logic; creciente:out std_logic_vector(1 downto 0) ); end codificador; architecture arc_codificador of codificador is begin process (e1,e2,e3) begin if e1='1' then creciente <="01"; else if e2='1' then creciente <= "10"; else creciente <= "11"; end if; end if; end process; end arc_codificador; 72 Anexos Podemos observar la transición entre creciente = “01”, el contador está en un ciclo de subida, y creciente = “10”, el contador está en un ciclo de bajada. 4.1.5 Diente de sierra --- diente de sierra --entity diente_sierra is port ( creciente:in std_logic_vector(1 downto 0); conta0:in std_logic_vector(7 downto 0); conta1:out std_logic_vector(7 downto 0) ); end diente_sierra; architecture secuencia1 of diente_sierra is signal contaux:unsigned(7 downto 0); begin process (conta0,creciente) begin case creciente is when "01" => contaux<="00000000"+unsigned(conta0(7 downto 1)); when "10" => contaux<="11111111"-unsigned(conta0(7 downto 1)); when others => contaux<=unsigned(conta0); end case; end process; conta1<=std_logic_vector(contaux); end secuencia1; 73 Anexos Se puede comprobar como conta1 evoluciona cada 2 ciclos de conta0. 4.1.6 Rectangular ---- Rectangular -----entity rectangular is port ( creciente:in std_logic_vector(1 downto 0); conta2:out std_logic_vector(7 downto 0) ); end rectangular; architecture secuencia2 of rectangular is begin process(creciente) begin if (creciente="11") then conta2<="00000000"; else conta2<="11111111"; end if; end process; end secuencia2; 74 Anexos Se puede observar como conta2 permanece a “11111111” cuando creciente es “01” o “00”, y a “00000000” cuando creciente es “11”. 4.1.7 Triangular ---- Triangular -----entity triangular is port ( conta0:in std_logic_vector(7 downto 0); conta3:out std_logic_vector(7 downto 0) ); end triangular; architecture secuencia4 of triangular is begin process(conta0) begin conta3<=conta0; end process; end secuencia4; El valor de conta3 es el mismo que el de conta0, tal y como se había explicado anteriormente. 75 Anexos 4.1.8 Senoidal ---- Senoidal -----entity senoidal is port ( creciente:in std_logic_vector(1 downto 0); conta0:in std_logic_vector(7 downto 0); direccion:out std_logic_vector(5 downto 0) ); end senoidal; architecture secuencia5 of senoidal is signal contaux:unsigned(5 downto 0); begin process (conta0,creciente) begin case creciente is when "01" => if (conta0(7)='0') then contaux<=unsigned(conta0(6 downto 1)); else contaux<="111111"-unsigned(conta0(6 downto 1)); end if; when "10" => if (conta0(7)='1') then contaux<="111111"-unsigned(conta0(6 downto 1)); else contaux<=unsigned(conta0(6 downto 1)); end if; when others => contaux<=unsigned(conta0(6 downto 1)); end case; 76 Anexos end process; direccion<=std_logic_vector(contaux); end secuencia5; En la gráfica se puede ver como evoluciona direccion en función de conta0. 4.1.9 ROM ---- ROM -----entity ROM is port ( direccion:in std_logic_vector(5 downto 0); contenido:out std_logic_vector(7 downto 0) ); end ROM; architecture acceso of ROM is begin process(direccion) begin case direccion is when when when when when when when "000000" "000001" "000010" "000011" "000100" "000101" "000110" => => => => => => => 77 contenido<="01111111"; contenido<="10000010"; contenido<="10000101"; contenido<="10001000"; contenido<="10001011"; contenido<="10001110"; contenido<="10010001"; Anexos when "000111" => contenido<="10010100"; when "001000" => contenido<="10010111"; when "001001" => contenido<="10011010"; when "001010" => contenido<="10011101"; when "001011" => contenido<="10100000"; when "001100" => contenido<="10100011"; when "001101" => contenido<="10100110"; when "001110" => contenido<="10101001"; when "001111" => contenido<="10101100"; when "010000" => contenido<="10101111"; when "010001" => contenido<="10110010"; when "010010" => contenido<="10110101"; when "010011" => contenido<="10111000"; when "010100" => contenido<="10111010"; when "010101" => contenido<="10111101"; when "010110" => contenido<="11000000"; when "010111" => contenido<="11000010"; when "011000" => contenido<="11000101"; when "011001" => contenido<="11001000"; when "011010" => contenido<="11001010"; when "011011" => contenido<="11001101"; when "011100" => contenido<="11001111"; when "011101" => contenido<="11010001"; when "011110" => contenido<="11010100"; when "011111" => contenido<="11010110"; when "100000" => contenido<="11011000"; when "100001" => contenido<="11011010"; when "100010" => contenido<="11011101"; when "100011" => contenido<="11011111"; when "100100" => contenido<="11100001"; when "100101" => contenido<="11100011"; when "100110" => contenido<="11100101"; when "100111" => contenido<="11100110"; when "101000" => contenido<="11101000"; when "101001" => contenido<="11101010"; when "101010" => contenido<="11101011"; when "101011" => contenido<="11101101"; when "101100" => contenido<="11101111"; when "101101" => contenido<="11110000"; when "101110" => contenido<="11110001"; when "101111" => contenido<="11110011"; when "110000" => contenido<="11110100"; when "110001" => contenido<="11110101"; when "110010" => contenido<="11110110"; 78 Anexos when "110011" => contenido<="11110111"; when "110100" => contenido<="11111000"; when "110101" => contenido<="11111001"; when "110110" => contenido<="11111010"; when "110111" => contenido<="11111010"; when "111000" => contenido<="11111011"; when "111001" => contenido<="11111100"; when "111010" => contenido<="11111100"; when "111011" => contenido<="11111101"; when "111100" => contenido<="11111101"; when "111101" => contenido<="11111101"; when "111110" => contenido<="11111101"; when "111111" => contenido<="11111101"; when others => contenido<="00000000"; end case; end process; end acceso; Se puede comprobar como a cada valor de direccion la ROM proporciona un valor (contenido). 4.1.10 Inversor ---- Inversor de los datos de la ROM -----entity inversor is port ( creciente:in std_logic_vector(1 downto 0); contenido:in std_logic_vector(7 downto 0); conta4:out std_logic_vector(7 downto 0) ); end inversor; architecture tratamiento of inversor is signal auxiliar:unsigned(7 downto 0); 79 Anexos begin process(contenido,creciente) begin if (creciente="10") then auxiliar<="11111111" - unsigned(contenido); else auxiliar<=unsigned(contenido); end if; end process; conta4<=std_logic_vector(auxiliar); end tratamiento; Cuando creciente = “10” conta4 invierte el contenido de la ROM. 4.1.11 Conjunto Este bloque no tiene representación en la memoria descriptiva. Se incluye simplemente para combinar la generación de los cuatro tipos de señales en una sóla entidad de manera que luego sea más sencilla su multiplexación. 80 Anexos ---conjunto--library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity conjunto is port( reset:in std_logic; clk512:in std_logic; periodo:in std_logic_vector(7 downto 0); desplazamiento:in std_logic_vector(7 downto 0); A:out std_logic_vector(7 downto 0); B:out std_logic_vector(7 downto 0); C:out std_logic_vector(7 downto 0); D:out std_logic_vector(7 downto 0) ); end conjunto; architecture arq_conjunto of conjunto is signal signal signal signal creciente:std_logic_vector(1 downto 0); conta0:std_logic_vector(7 downto 0); direccion:std_logic_vector(5 downto 0); contenido:std_logic_vector(7 downto 0); component contador port ( reset:in std_logic; clk512:in std_logic; desplazamiento:in std_logic_vector(7 downto 0); conta0:out std_logic_vector(7 downto 0); creciente:out std_logic_vector(1 downto 0) ); end component; component diente_sierra port ( creciente:in std_logic_vector(1 downto 0); conta0:in std_logic_vector(7 downto 0); 81 Anexos conta1:out std_logic_vector(7 downto 0) ); end component; component rectangular port ( creciente:in std_logic_vector(1 downto 0); conta2:out std_logic_vector(7 downto 0) ); end component; component triangular is port ( conta0:in std_logic_vector(7 downto 0); conta3:out std_logic_vector(7 downto 0) ); end component; component senoidal is port ( creciente:in std_logic_vector(1 downto 0); conta0:in std_logic_vector(7 downto 0); direccion:out std_logic_vector(5 downto 0) ); end component; component ROM is port ( direccion:in std_logic_vector(5 downto 0); contenido:out std_logic_vector(7 downto 0) ); end component; component inversor is port ( creciente:in std_logic_vector(1 downto 0); contenido:in std_logic_vector(7 downto 0); conta4:out std_logic_vector(7 downto 0) ); end component; 82 Anexos begin ct:contador port map(reset=>reset,clk512=>clk512,desplazamiento=>desplazamiento, creciente=>creciente,conta0=>conta0); sierra:diente_sierra port map(creciente=>creciente,conta0=>conta0,conta1=>A); rect:rectangular port map(creciente=>creciente,conta2=>B); triang:triangular port map(conta0=>conta0,conta3=>C); sen:senoidal port map(creciente=>creciente,conta0=>conta0, direccion=>direccion); memoria:ROM port map(direccion=>direccion,contenido=>contenido); tractament:inversor port map(creciente=>creciente,contenido=>contenido,conta4=>D); end arq_conjunto; En este gráfico se puede ver la evolución simultánea de los cuatro tipos de señales. 83 Anexos 4.1.12 Multiplexor ---multiplexor--entity multiplexor is port( A:in std_logic_vector(7 downto 0); B:in std_logic_vector(7 downto 0); C:in std_logic_vector(7 downto 0); D:in std_logic_vector(7 downto 0); selec:in std_logic_vector(1 downto 0); salida_mult:out std_logic_vector(7 downto 0) ); end multiplexor; architecture seleccion of multiplexor is begin process(selec,A,B,C,D) begin case selec is when when when when "00" => salida_mult<=A; "01" => salida_mult<=B; "10" => salida_mult<=C; others => salida_mult<=D; end case; end process; end seleccion; 84 Anexos Se puede comprobar que cuando selec = “10” a la salida del multiplexor se obtiene la señal triangular. Si fuera “00” se obtendría la de diente de sierra y así sucesivamente. 4.1.13 Amplificador_ofsset Esta entidad tiene cuatro componentes como se observa a continuación: --- Bloque amplificador offset ----entity amplif_offset is port ( reset:in std_logic; clk,clk512:in std_logic; offset:in std_logic_vector(7 downto 0); amplificacion:in std_logic_vector(7 downto 0); multiplicando:in std_logic_vector(7 downto 0); sal_amp_off:out std_logic_vector(7 downto 0) ); end amplif_offset; 85 Anexos architecture arc_amplif_offset of amplif_offset is signal signal signal signal sal_amp:std_logic_vector(9 downto 0); operandoA:unsigned(8 downto 0); operandoB:unsigned(8 downto 0); salida2:std_logic_vector(8 downto 0); component amplificador port( reset:in std_logic; clk:in std_logic; clk512:in std_logic; amplificacion:in std_logic_vector(7 downto 0); multiplicando:in std_logic_vector(7 downto 0); resultado:out std_logic_vector(9 downto 0) ); end component; component adquisicion port( offset:in std_logic_vector(7 downto 0); sal_amp:in std_logic_vector(9 downto 0); operandoA:out unsigned(8 downto 0); operandoB:out unsigned(8 downto 0) ); end component; component sumador9bits port( sumandoA:in unsigned(8 downto 0); sumandoB:in unsigned(8 downto 0); salida2:out std_logic_vector(8 downto 0) ); end component; component limitador port( entrada:in std_logic_vector(8 downto 0); salida3:out std_logic_vector(7 downto 0) ); end component; begin amp:amplificador port map(reset=>reset,clk=>clk,clk512=>clk512, amplificacion=>amplificacion,multiplicando=>multiplicando, resultado=>sal_amp); 86 Anexos adq:adquisicion port map(offset=>offset,sal_amp=>sal_amp, operandoA=>operandoA,operandoB=>operandoB); sum:sumador9bits port map(sumandoA=>operandoA, sumandoB=>operandoB,salida2=>salida2); lim:limitador port map(entrada=>salida2,salida3=>sal_amp_off); end arc_amplif_offset; A cada flanco de clk512 se le aplica un factor de atenuación a la entrada multiplicando. Se puede comprobar que el proceso requiere de varios flancos de clk. 4.1.13.1 Amplificador El amplificador necesita para funcionar una puerta XOR que se muestra a continuación: ---- Puerta XOR ---entity puerta_xor is port( s1:in std_logic; s2:in std_logic; start:out std_logic ); end puerta_xor; 87 Anexos architecture set_multiplic of puerta_xor is begin process (s1,s2) begin start<=s1 xor s2; end process; end set_multiplic; ---- Amplificacion ------entity amplificador is port( reset:in std_logic; clk:in std_logic; clk512:in std_logic; amplificacion:in std_logic_vector(7 downto 0); multiplicando:in std_logic_vector(7 downto 0); resultado:out std_logic_vector(9 downto 0) ); end amplificador; architecture arc_amplificador of amplificador is component puerta_xor is port( s1:in std_logic; s2:in std_logic; start:out std_logic ); end component; signal signal signal signal signal signal s1:std_logic; s2:std_logic; start:std_logic; registro:unsigned(9 downto 0); amplif_aux:unsigned(9 downto 0); multiplicando_aux:unsigned(7 downto 0); 88 Anexos begin p_xor:puerta_xor port map(s1=>s1,s2=>s2,start=>start); process (clk512,reset) begin if (reset='1') then s1<='0'; elsif (clk512' event and clk512='1') then s1<=not(s1); end if; end process; process (clk,reset) begin if (reset='1') then s2<='0'; registro<="0000000000"; amplif_aux<="0000000000"; multiplicando_aux<="00000000"; elsif (clk' event and clk='1') then if (start='1') then multiplicando_aux<=unsigned(multiplicando); amplif_aux(8 downto 1)<=unsigned(amplificacion); amplif_aux(9)<='0'; amplif_aux(0)<='0'; registro<="0000000000"; s2<=not(s2); else s2<=s2amplif_aux(8 downto 0)<=amplif_aux (9 downto 1); 89 Anexos amplif_aux(9)<='0'; if (multiplicando_aux(7)='1') then registro<=registro + amplif_aux; else registro<=registro; end if; multiplicando_aux(7 downto 1)<=multiplicando_aux(6 downto 0); multiplicando_aux(0)<='0'; end if; end if; end process; resultado<=std_logic_vector(registro); end arc_amplificador; En el gráfico se puede observar como a cada flanco de clk512 se activa la señal start, iniciándose una multiplicación secuencial entre amplificación y multiplicando, generando un valor de 10 bits. 90 Anexos 4.1.13.2 Sumador El sumador consta de dos entidades. Una que realiza la adquisición de valores y la otra que realiza la suma: ---- Adquisición ------entity adquisicion is port( offset:in std_logic_vector(7 downto 0); sal_amp:in std_logic_vector(9 downto 0); operandoA:out unsigned(8 downto 0); operandoB:out unsigned(8 downto 0) ); end adquisicion; architecture arc_adquisicion of adquisicion is begin process(offset,sal_amp) begin operandoA(7 downto 0)<=unsigned(sal_amp(9 downto 2)); operandoA(8)<='0'; operandoB(7 downto 0)<=unsigned(offset); operandoB(8)<='0'; end process; end arc_adquisicion; ---- Sumador de dos entradas de 9 bits ------- entity sumador9bits is port( sumandoA:in unsigned(8 downto 0); sumandoB:in unsigned(8 downto 0); salida2:out std_logic_vector(8 downto 0) ); end sumador9bits; 91 Anexos architecture arc_sumador9bits of sumador9bits is signal salida2_aux:unsigned(8 downto 0); begin process(sumandoA,sumandoB) begin salida2_aux<= sumandoA + sumandoB; end process; salida2<=std_logic_vector(salida2_aux); end arc_sumador9bits; Se puede comprobar como se convierte la salida del amplificador a un valor de 9 bits (sumandoA) y se le suma el offset, tal y como se había explicado en la memoria descriptiva. 4.1.13.3 Limitador ---- Control de desbordamiento ------entity limitador is port( entrada:in std_logic_vector(8 downto 0); salida3:out std_logic_vector(7 downto 0) ); end limitador; 92 Anexos architecture arc_limitador of limitador is begin process(entrada) begin if (entrada(8)='1') then salida3<="11111111"; else salida3<=entrada(7 downto 0); end if; end process; end arc_limitador; Mientras entrada supera el valor “0FF”, es decir “011111111”, salida3 se mantiene a “FF”, es decir “11111111”. 93 Anexos 4.1.14 Generador de funciones Como se ha comentado anteriormente esta es la entidad principal que engloba todas las entidades vistas hasta ahora. --- generador de funciones ----entity generador is port ( reset:in std_logic; periodo:in std_logic_vector(7 downto 0); amplificacion:in std_logic_vector(7 downto 0); selec:in std_logic_vector(1 downto 0); desplazamiento: in std_logic_vector(7 downto 0); offset:in std_logic_vector(7 downto 0); salidagen:out std_logic_vector(7 downto 0) ); end generador; architecture final of generador is signal signal signal signal clk,clk8,clk512:std_logic; multiplicando:std_logic_vector(7 downto 0); sal_amp_off: std_logic_vector(7 downto 0); A,B,C,D:std_logic_vector(7 downto 0); component reloj port ( clk:out std_logic ); end component; component divisor8 port ( reset:in std_logic; clk:in std_logic; clk8:out std_logic ); end component; component divis_frec port ( reset:in std_logic; clk8:in std_logic; clk512:out std_logic; periodo:in std_logic_vector(7 downto 0) ); end component; 94 Anexos component conjunto port( reset:in std_logic; clk512:in std_logic; periodo:in std_logic_vector(7 downto 0); desplazamiento:in std_logic_vector(7 downto 0); A:out std_logic_vector(7 downto 0); B:out std_logic_vector(7 downto 0); C:out std_logic_vector(7 downto 0); D:out std_logic_vector(7 downto 0) ); end component; component multiplexor port( A:in std_logic_vector(7 downto 0); B:in std_logic_vector(7 downto 0); C:in std_logic_vector(7 downto 0); D:in std_logic_vector(7 downto 0); selec:in std_logic_vector(1 downto 0); salida_mult:out std_logic_vector(7 downto 0) ); end component; component amplif_offset port( reset:in std_logic; clk,clk512:in std_logic; offset:in std_logic_vector(7 downto 0); amplificacion:in std_logic_vector(7 downto 0); multiplicando:in std_logic_vector(7 downto 0); sal_amp_off:out std_logic_vector(7 downto 0) ); end component; begin temp:reloj port map(clk=>clk); divisor:divisor8 port map(reset=>reset,clk=>clk,clk8=>clk8); 95 Anexos frecuencia:divis_frec port map(reset=>reset,clk8=>clk8, clk512=>clk512,periodo=>periodo); conjunt:conjunto port map(reset=>reset,clk512=>clk512, periodo=>periodo,desplazamiento=>desplazamiento, A=>A,B=>B,C=>C,D=>D); mux:multiplexor port map(A=>A,B=>B,C=>C,D=>D,selec=>selec, salida_mult=>multiplicando); amplif:amplif_offset port map(reset=>reset,clk=>clk,clk512=>clk512, offset=>offset,amplificacion=>amplificacion, multiplicando=>multiplicando,sal_amp_off=>sal_amp_off); process (clk512,reset) begin if (reset='1') then salidagen<="00000000"; elsif (clk512' event and clk512='1') then salidagen<=sal_amp_off; end if; end process; end final; La salida de este bloque no es necesario simularla, puesto que coincide con la salida del componente amplificador_offset visto anteriormente. 96 Anexos 4.1.15 Diferencias entre el generador simulado y el sintetizado en la FPGA Es necesario remarcar que para simular el sistema se ha simulado internamente una señal de reloj. En el diseño final ésta será introducida externamente, por tanto la arquitectura del generador no contendrá el componente reloj. Se define en la entidad una entrada externa clk: --- generador de funciones ----entity generador is port ( clk,reset:in std_logic; periodo:in std_logic_vector(7 downto 0); amplificacion:in std_logic_vector(7 downto 0); selec:in std_logic_vector(1 downto 0); desplazamiento: in std_logic_vector(7 downto 0); offset:in std_logic_vector(7 downto 0); salidagen:out std_logic_vector(7 downto 0) ); end generador; architecture final of generador is signal signal signal signal clk8,clk512:std_logic; multiplicando:std_logic_vector(7 downto 0); sal_amp_off: std_logic_vector(7 downto 0); A,B,C,D:std_logic_vector(7 downto 0); component divisor8 port ( reset:in std_logic; clk:in std_logic; clk8:out std_logic ); end component; El resto del código permanece igual. 97 Anexos 4.2 Sintetización del Código VHDL Una vez simulado el código se sintetiza con el paquete de softtware FOUNDATION de XILINX. Se genera un archivo con extensión .BIT que será cargado en la FPGA. Al sintetizar se genera un archivo PLACE&ROUT.PAR que indica el porcentaje de ocupación de la FPGA. El código se ha optimizado al máximo hasta conseguir una ocupación del 58% de CLBS. Release 4.1i - Par E.30 Copyright (c) 1995-2001 Xilinx, Inc. All rights reserved. Sun Jan 27 11:18:02 2002 par -w -ol 2 -d 0 map.ncd gen1.ncd gen1.pcf Constraints file: gen1.pcf Loading design for application par from file map.ncd. "generador" is an NCD, version 2.36, device xc4005e, package pc84, speed -1 Loading device for application par from file '4005e.nph' in environment C:/Xilinx. Device speed data version: x1_0.96 PRELIMINARY. Resolved that IOB <amplificacion<0>> must be placed at site P57. Resolved that IOB <amplificacion<1>> must be placed at site P58. Resolved that IOB <amplificacion<2>> must be placed at site P59. Resolved that IOB <amplificacion<3>> must be placed at site P60. Resolved that IOB <amplificacion<4>> must be placed at site P61. 98 Anexos Resolved that IOB <amplificacion<5>> must be placed at site P62. Resolved that IOB <amplificacion<6>> must be placed at site P65. Resolved that IOB <amplificacion<7>> must be placed at site P66. Resolved that CLKIOB <clk> must be placed at site P13. Resolved that IOB <desplazamiento<0>> must be placed at site P84. Resolved that IOB <desplazamiento<1>> must be placed at site P83. Resolved that IOB <desplazamiento<2>> must be placed at site P82. Resolved that IOB <desplazamiento<3>> must be placed at site P81. Resolved that IOB <desplazamiento<4>> must be placed at site P80. Resolved that IOB <desplazamiento<5>> must be placed at site P79. Resolved that IOB <desplazamiento<6>> must be placed at site P78. Resolved that IOB <desplazamiento<7>> must be placed at site P77. Resolved that IOB <offset<0>> must be placed at site P28. Resolved that IOB <offset<1>> must be placed at site P27. Resolved that IOB <offset<2>> must be placed at site P26. Resolved that IOB <offset<3>> must be placed at site P25. Resolved that IOB <offset<4>> must be placed at site P24. Resolved that IOB <offset<5>> must be placed at site P23. Resolved that IOB <offset<6>> must be placed at site P20. Resolved that IOB <offset<7>> must be placed at site P19. Resolved that IOB <periodo<0>> must be placed at site P10. Resolved that IOB <periodo<1>> must be placed at site P9. Resolved that IOB <periodo<2>> must be placed at site P8. Resolved that IOB <periodo<3>> must be placed at site P7. Resolved that IOB <periodo<4>> must be placed at site P6. Resolved that IOB <periodo<5>> must be placed at site P5. Resolved that IOB <periodo<6>> must be placed at site P4. Resolved that IOB <periodo<7>> must be placed at site P3. Resolved that IOB <reset> must be placed at site P38. Resolved that IOB <salidagen<0>> must be placed at site P37. Resolved that IOB <salidagen<1>> must be placed at site P39. 99 Anexos Resolved that IOB <salidagen<2>> must be placed at site P41. Resolved that IOB <salidagen<3>> must be placed at site P35. Resolved that IOB <salidagen<4>> must be placed at site P45. Resolved that IOB <salidagen<5>> must be placed at site P47. Resolved that IOB <salidagen<6>> must be placed at site P49. Resolved that IOB <salidagen<7>> must be placed at site P51. Resolved that IOB <selec<0>> must be placed at site P40. Resolved that IOB <selec<1>> must be placed at site P44. Resolved that PRI-CLK <C961> must be placed at site BUFGP_TL. Device utilization summary: Number of External IOBs Flops: Latches: 44 out of 112 72% 8 0 Number of IOBs driving Global Buffers 1 out of 8 Number of CLBs 114 out of 196 Total CLB Flops: 64 out of 392 4 input LUTs: 209 out of 392 3 input LUTs: 36 out of 196 58% 16% 53% 18% Number of PRI-CLKs 1 out of 4 25% Number of SEC-CLKs 2 out of 4 50% Number of STARTUPs 1 out of 1 100% Overall effort level (-ol): 2 (set by user) Placer effort level (-pl): 2 (set by user) 100 12% Anexos Placer cost table entry (-t): 1 Router effort level (-rl): 2 (set by user) Extra effort level (-xe): 0 (default) Starting initial Placement phase. REAL time: 0 secs Finished initial Placement phase. REAL time: 0 secs Starting Constructive Placer. REAL time: 0 secs Placer score = 127064 Placer score = 92408 Placer score = 87174 Placer score = 78780 Placer score = 73838 Placer score = 69036 Placer score = 64474 Placer score = 62400 Placer score = 60578 Placer score = 59316 Placer score = 57876 Placer score = 55584 Placer score = 54490 Placer score = 53884 Placer score = 53758 Placer score = 53098 Placer score = 53054 Placer score = 52992 Placer score = 52978 Placer score = 52922 Finished Constructive Placer. REAL time: 4 secs Dumping design to file gen1.ncd. 101 Anexos Starting Optimizing Placer. REAL time: 4 secs Optimizing Swapped 16 comps. Xilinx Placer [1] 52198 REAL time: 5 secs Finished Optimizing Placer. REAL time: 5 secs Dumping design to file gen1.ncd. Total REAL time to Placer completion: 5 secs Total CPU time to Placer completion: 5 secs 0 connection(s) routed; 759 unrouted active, 24 unrouted PWR/GND. Starting router resource preassignment Completed router resource preassignment. REAL time: 5 secs Starting iterative routing. Routing active signals. End of iteration 1 759 successful; 0 unrouted active, 24 unrouted PWR/GND; (0) REAL time: 6 secs Routing PWR/GND nets. Power and ground nets completely routed. Dumping design to file gen1.ncd. Starting cleanup Improving routing. End of cleanup iteration 1 783 successful; 0 unrouted; (0) REAL time: 9 secs Dumping design to file gen1.ncd. Total REAL time: 9 secs Total CPU time: 9 secs 102 Anexos End of route. 783 routed (100.00%); 0 unrouted. No errors found. Completely routed. This design was run without timing constraints. It is likely that much better circuit performance can be obtained by trying either or both of the following: - Enabling the Delay Based Cleanup router pass, if not already enabled - Supplying timing constraints in the input design Total REAL time to Router completion: 9 secs Total CPU time to Router completion: 9 secs Generating PAR statistics. The Delay Summary Report The Score for this design is: 452 The Number of signals not completely routed for this design is: 0 The Average Connection Delay for this design is: 2.863 ns The Maximum Pin Delay is: 11.534 ns The Average Connection Delay on the 10 Worst Nets is: 8.301 ns Listing Pin Delays by value: (ns) d < 2.00 < d < 4.00 < d < 6.00 < d < 8.00 < d < 12.00 d >= 12.00 --------- --------- --------- --------- --------- --------- 103 Anexos 417 162 114 41 49 Dumping design to file gen1.ncd. All signals are completely routed. Total REAL time to PAR completion: 9 secs Total CPU time to PAR completion: 9 secs Placement: Completed - No errors found. Routing: Completed - No errors found. PAR done. Release 3.3.06i – Par D 25 Tue Dec 11 09:57:24 2001 Xilinx PAD Specification File ************************ Input file: map.ncd Output file generador.ncd Part Type: Xc4005e Speed grade -1 Package: pc84 104 0 Anexos Tambien se genera un archivo con extensión .PAD que indica la asignación de cada un delos pins de la FPGA: Release 4.1i - Par E.30 Copyright (c) 1995-2001 Xilinx, Inc. All rights reserved. Sun Jan 27 11:18:11 2002 Xilinx PAD Specification File ***************************** Input file: map.ncd Output file: gen1.ncd Part type: xc4005e Speed grade: Package: -1 pc84 Pinout by Signal Name: -------------------------------|----------------------|--------|-----------| Signal Name | Pin Name | | Pin | Direction | | Number | | -------------------------------|----------------------|--------|-----------| amplificacion<0> | | P57 | INPUT | amplificacion<1> | | P58 | INPUT | amplificacion<2> | | P59 | INPUT | amplificacion<3> | | P60 | INPUT | amplificacion<4> | | P61 | INPUT | amplificacion<5> | | P62 | INPUT | amplificacion<6> | | P65 | INPUT | amplificacion<7> | | P66 | INPUT | clk | | P13 | INPUT | desplazamiento<0> | | P84 | INPUT | 105 Anexos desplazamiento<1> | | P83 | INPUT | desplazamiento<2> | | P82 | INPUT | desplazamiento<3> | | P81 | INPUT | desplazamiento<4> | | P80 | INPUT | desplazamiento<5> | | P79 | INPUT | desplazamiento<6> | | P78 | INPUT | desplazamiento<7> | | P77 | INPUT | offset<0> | | P28 | INPUT | offset<1> | | P27 | INPUT | offset<2> | | P26 | INPUT | offset<3> | | P25 | INPUT | offset<4> | | P24 | INPUT | offset<5> | | P23 | INPUT | offset<6> | | P20 | INPUT | offset<7> | | P19 | INPUT | periodo<0> | | P10 | INPUT | periodo<1> | | P9 | INPUT | periodo<2> | | P8 | INPUT | periodo<3> | | P7 | INPUT | periodo<4> | | P6 | INPUT | periodo<5> | | P5 | INPUT | periodo<6> | | P4 | INPUT | periodo<7> | | P3 | INPUT | reset | | P38 | INPUT salidagen<0> | | P37 | OUTPUT | salidagen<1> | | P39 | OUTPUT | salidagen<2> | | P41 | OUTPUT | salidagen<3> | | P35 | OUTPUT | salidagen<4> | | P45 | OUTPUT | salidagen<5> | | P47 | OUTPUT | salidagen<6> | | P49 | OUTPUT | 106 | Anexos salidagen<7> | | P51 | OUTPUT | selec<0> | | P40 | INPUT | selec<1> | | P44 | INPUT | -------------------------------|----------------------|--------|-----------| Pinout by Pin Number: --------|-------------------------------|----------------------|-----------| Pin | Signal Name Number | | Pin Name | | | Direction | | --------|-------------------------------|----------------------|-----------| P1 | | GND | | P2 | | VCC | | P3 | periodo<7> | | INPUT | P4 | periodo<6> | | INPUT | P5 | periodo<5> | | INPUT | P6 | periodo<4> | | INPUT | P7 | periodo<3> | | INPUT | P8 | periodo<2> | | INPUT | P9 | periodo<1> | | INPUT | P10 | periodo<0> | | INPUT | P11 | | VCC | | P12 | | GND | | P13 | clk | | INPUT P14 | | | UNUSED | | | P15 | | TDI P16 | | TCK | | P17 | | TMS | | P18 | | | UNUSED P19 | offset<7> | | INPUT | P20 | offset<6> | | INPUT | P21 | | GND | | 107 | | Anexos P22 | | VCC | P23 | offset<5> | | INPUT | P24 | offset<4> | | INPUT | P25 | offset<3> | | INPUT | P26 | offset<2> | | INPUT | P27 | offset<1> | | INPUT | P28 | offset<0> | | INPUT | P29 | | | UNUSED P30 | | M1 P31 | | GND P32 | | M0 P33 | | VCC P34 | | M2 P35 | salidagen<3> | | OUTPUT | P36 | | | UNUSED | P37 | salidagen<0> | | OUTPUT | P38 | reset | | INPUT P39 | salidagen<1> | | OUTPUT P40 | selec<0> | | INPUT P41 | salidagen<2> | | OUTPUT P42 | | VCC | | P43 | | GND | | P44 | selec<1> | | INPUT | P45 | salidagen<4> | | OUTPUT | P46 | | | UNUSED | P47 | salidagen<5> | | OUTPUT | P48 | | | UNUSED | P49 | salidagen<6> | | OUTPUT | P50 | | | UNUSED | P51 | salidagen<7> | | OUTPUT | P52 | | GND | | | | | | | | | | | | | 108 | | | | | Anexos P53 | | DONE | P54 | | VCC P55 | | /PROG P56 | | | UNUSED P57 | amplificacion<0> | | INPUT | P58 | amplificacion<1> | | INPUT | P59 | amplificacion<2> | | INPUT | P60 | amplificacion<3> | | INPUT | P61 | amplificacion<4> | | INPUT | P62 | amplificacion<5> | | INPUT | P63 | | VCC | | P64 | | GND | | P65 | amplificacion<6> | | INPUT | P66 | amplificacion<7> | | INPUT | P67 | | | UNUSED | P68 | | | UNUSED | P69 | | | UNUSED | P70 | | | UNUSED | P71 | | | UNUSED | P72 | | | UNUSED | P73 | | CCLK P74 | | VCC | | P75 | | TDO | | P76 | | GND | | P77 | desplazamiento<7> | | INPUT | P78 | desplazamiento<6> | | INPUT | P79 | desplazamiento<5> | | INPUT | P80 | desplazamiento<4> | | INPUT | P81 | desplazamiento<3> | | INPUT | P82 | desplazamiento<2> | | INPUT | P83 | desplazamiento<1> | | INPUT | | | | | | | 109 | | Anexos P84 | desplazamiento<0> | | INPUT | --------|-------------------------------|----------------------|-----------| * Default value. ** This default Pullup/Pulldown value can be overridden in Bitgen. *** The default IOB Delay is determined by how the IOB is used. # # To preserve the pinout above for future design iterations, # simply invoke PIN2UCF from the command line or issue this command in the GUI. # For Foundation ISE/Project Navigator - Run the process "Implement Design" -> "Place-and-Route" -> "Back-annotate Pin Locations" # For Design Manager - In the Design menu select "Lock Pins... # The location constraints above will be written into your specified UCF file. (The constraints # listed below are in PCF format and cannot be directly used in the UCF file). # COMP "amplificacion<0>" LOCATE = SITE "P57" ; COMP "amplificacion<1>" LOCATE = SITE "P58" ; COMP "amplificacion<2>" LOCATE = SITE "P59" ; COMP "amplificacion<3>" LOCATE = SITE "P60" ; COMP "amplificacion<4>" LOCATE = SITE "P61" ; COMP "amplificacion<5>" LOCATE = SITE "P62" ; COMP "amplificacion<6>" LOCATE = SITE "P65" ; COMP "amplificacion<7>" LOCATE = SITE "P66" ; COMP "clk" LOCATE = SITE "P13" ; COMP "desplazamiento<0>" LOCATE = SITE "P84" ; COMP "desplazamiento<1>" LOCATE = SITE "P83" ; COMP "desplazamiento<2>" LOCATE = SITE "P82" ; COMP "desplazamiento<3>" LOCATE = SITE "P81" ; COMP "desplazamiento<4>" LOCATE = SITE "P80" ; 110 Anexos COMP "desplazamiento<5>" LOCATE = SITE "P79" ; COMP "desplazamiento<6>" LOCATE = SITE "P78" ; COMP "desplazamiento<7>" LOCATE = SITE "P77" ; COMP "offset<0>" LOCATE = SITE "P28" ; COMP "offset<1>" LOCATE = SITE "P27" ; COMP "offset<2>" LOCATE = SITE "P26" ; COMP "offset<3>" LOCATE = SITE "P25" ; COMP "offset<4>" LOCATE = SITE "P24" ; COMP "offset<5>" LOCATE = SITE "P23" ; COMP "offset<6>" LOCATE = SITE "P20" ; COMP "offset<7>" LOCATE = SITE "P19" ; COMP "periodo<0>" LOCATE = SITE "P10" ; COMP "periodo<1>" LOCATE = SITE "P9" ; COMP "periodo<2>" LOCATE = SITE "P8" ; COMP "periodo<3>" LOCATE = SITE "P7" ; COMP "periodo<4>" LOCATE = SITE "P6" ; COMP "periodo<5>" LOCATE = SITE "P5" ; COMP "periodo<6>" LOCATE = SITE "P4" ; COMP "periodo<7>" LOCATE = SITE "P3" ; COMP "reset" LOCATE = SITE "P38" ; COMP "salidagen<0>" LOCATE = SITE "P37" ; COMP "salidagen<1>" LOCATE = SITE "P39" ; COMP "salidagen<2>" LOCATE = SITE "P41" ; COMP "salidagen<3>" LOCATE = SITE "P35" ; COMP "salidagen<4>" LOCATE = SITE "P45" ; COMP "salidagen<5>" LOCATE = SITE "P47" ; COMP "salidagen<6>" LOCATE = SITE "P49" ; COMP "salidagen<7>" LOCATE = SITE "P51" ; COMP "selec<0>" LOCATE = SITE "P40" ; COMP "selec<1>" LOCATE = SITE "P44" ; # 111