Paso 1: Creación del proyecto y chequeo de la sintaxis.
En el caso en que desconozcas como crear un proyecto con el software de XILINX, puedes basarte en las entradas cuyo links dejo a continuación o echar un vistazo en los numerosos tutoriales que hay en Internet partiendo de código VHDL (también se puede hacer partiendo de esquemáticos del diseño digital con puertas OR, AND, XOR… MULTIPLEXORES, CONTADORES… etc, pero eso ya es otra historia).
http://ecalamartronico.blogspot.com.es/2016/08/introduccion-al-kit-open3s250e-6-crear.html
Pero ojo, el código que usaremos en esta ocasión es muy
similar al que describo en esas entradas anteriores, pero ligeramente
modificado por mí, así que lo dejaré a continuación para que puedas copiar y
pegar al crear tu módulo VHDL en el proyecto.
---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity LEDA_blogChSc0 is Port ( clk : in STD_LOGIC; led1_0 : out STD_LOGIC; led1_1 : out STD_LOGIC; led1_2 : out STD_LOGIC; led1_3 : out STD_LOGIC); --LCD_N : out STD_LOGIC; --LCD_P : out STD_LOGIC); end LEDA_blogChSc0; architecture light_blogChSc0 of LEDA_blogChSc0 is SIGNAL clk1:std_logic :='0'; SIGNAL CLK2:std_logic :='0'; SIGNAL clka:std_logic :='0'; begin --LCD_N<='0'; --LCD_P<='0'; P1:PROCESS (clk) VARIABLE count:INTEGER RANGE 0 TO 9999999; BEGIN IF clk'EVENT AND clk='1' THEN IF count<=4999999 THEN clk1<='0'; count:=count+1; ELSIF count>=4999999 AND count<=9999999 THEN clk1<='1'; count:=count+1; ELSE count:=0; END IF; END IF; END PROCESS ; P3:PROCESS(CLK1) Begin clk1 <= clk1; IF clk1'event AND clk1='1'THEN clk2<=not clk2; END IF; END PROCESS P3; P2:PROCESS(clk2) variable count1:INTEGER RANGE 0 TO 16; BEGIN IF clk2'event AND clk2='1'THEN if count1<=4 then if count1=4 then count1:=0; end if; CASE count1 IS WHEN 0=> led1_0<='0'; led1_1<='1'; led1_2<='1'; led1_3<='1'; WHEN 1=> led1_0<='1'; led1_1<='0'; led1_2<='1'; led1_3<='1'; WHEN 2=> led1_0<='1'; led1_1<='1'; led1_2<='0'; led1_3<='1'; WHEN 3=> led1_0<='1'; led1_1<='1'; led1_2<='1'; led1_3<='0'; WHEN OTHERS=> led1_0<='1'; led1_1<='1'; led1_2<='1'; led1_3<='1'; END CASE; count1:=count1+1; end if; end if; end process; end light_blogChSc0;
Disculpa si no entro mucho en detalle en esta sección, pero
es que si lo hago esto se puede hacer demasiado largo, denso y pesado tanto
para ti como para mí.
Paso 2: Creación del
archivo .ucf (user constraints).
De nuevo voy a dejar otro enlace para este paso.
---------------------------------------------------------------------------------------------------------
Nota importante:
El momento en que se va abrir el PlanAhead a mí me tarda más
que bastante, en el pasado me he llegado a impacientar, he hecho clic varias
veces en I/O Planing (PlanAhead…) y transcurrido un tiempo se me han abierto
varios PlanAhead.
Si te ocurre como a mí que sepas que es relativamente
normal, quizás no estemos trabajando en las mejores condiciones: el PC está
saturado, la RAM no es muy potente, nuestro software no es el mejor… que se yo,
la cuestión es que no te impacientes como yo las primeras veces please, al
final se abre.
---------------------------------------------------------------------------------------------------------
Yo lo estoy haciendo con versiones de ISE porque he
trabajado con ellas más y voy justo de tiempo, pero si puedes investigar un
poco y hacerlo con las últimas versiones de XILINX, es decir con Vivado, mucho
mejor aunque el proceso no es exactamente como aquí lo describo, hay que hacer
lo que se llama un “Migrating to Vivado Logic Debug Cores”, pero al menos
muchos conceptos son similares o iguales, y espero que esta entrada te ayude. Dejo un link que te puede ser de ayuda si trabajas con Vivado.
En el link
que ya
dejé anteriormente, ahí trabajo con una versión más antigua de ISE que la que
estoy usando esta vez, es por eso que cambia ligeramente el interfaz del
PlanAhead. No es difícil manejar
este nuevo interfaz conociendo el otro, no obstante dejo un mini-tutorial en
forma de clip para que facilitar las cosas:
Filmar con una mano y trabajar con la otra, y encima con poca luz y una cámara mala no da resultados muy óptimos, pero espero y deseo que el clip sea suficiente para ilustrar el proceso.
Se repite el proceder del clip anterior (si te equivocas
asignando los pines de la FPGA se puede corregir de forma fácil e intuitiva)
hasta obtener la configuración que se muestra en la siguiente figura:
---------------------------------------------------------------------------------------------------------
Notas:
Si las imágenes las ves muy pequeñas, puedes hacer clic en ellas para verlas más grandes y luego en la flecha de retroceder de tu navegador (apuntando a la izquierda) para volver a la entrada. Normalmente está en la parte superior izquierda del navegador dónde estés viendo el blog.
En otras ocasiones se abre la imagen con el fondo del blog oscurecido, en esos casos basta con dar al icono con forma de aspa (típico para cerrar) que aparece en la parte superior derecha y volverás al blog.
Estos pequeños detalles como que los post sean cómodos de leer, es algo que a veces se te escapa y sin embargo es muy importante.
---------------------------------------------------------------------------------------------------------
La asignación de pines no es en absoluto arbitraria, si
trabajas con una Core3S250E la explicación la puedes obtener en el siguiente
link:
Si estás trabajando con otro hardware seguro que encuentras
información similar en Internet. Me extraña que no haya información de este
tipo para placas como la Basys o Nexys, y si eres tan máquina que has hecho tu
propia placa, seguro que has visto el datasheet de la FPGA que estés usando y
la configuración de la PCB la sabrás mejor que nadie.
Al volver al ISE o el Vivado verás que se ha añadido un
archivo con extensión “.ucf”. Si es así y has seguido los pasos correctamente
todo va bien.
Paso 3: Conexión del
hardware.
En realidad esto se puede hacer un poco más tarde, pero no
está de más que lo hagamos ya.
Por aquello de que “una imagen vale más que mil palabras” en
este paso no va a haber mucha "literatura".
No olvidar dar a la clavija de ON (el led de la DLC9G de
XILINX blanca tiene color naranja en off):
En la anterior imagen ya le hemos puesto la clavija de la
Core3S250E en ON, por eso se nos enciende un LED en dicha placa y en la DLC9G
(artefacto blanco) el led ahora está en verde (mis disculpas por la escasa calidad de las fotos).
Si usas otro tipo de hardware no creo que encuentres muchos
problemas para conectarlo al ordenador, suelen estar diseñados para que las
conexiones al PC sean fáciles, además el fabricante suele dejar algún enlace
para que descargues algún manual.
Aquí ya no valen atajos en forma de enlaces, clips o fotos
de dudosa calidad, esto es parte ya esencial de la entrada, así que toca
“remangarse la camisa”.
En estos momentos tendremos algo como esto,
Si usas Vivado la interfaz cambia, y el proceso no es exactamente como aquí lo describo, como ya
dije hay que hacer lo que se llama un “Migrating to Vivado Logic Debug”, no
obstante ver este tutorial te puede facilitar luego trabajar con Vivado (queda pendiente hacer más cosas con Vivado, ojala no me caduque pronto el trial que tengo):
Obsérvese en la anterior imágen, que está seleccionado el “LEDA_blogChSc0.vhd”, y
si no lo tienes seleccionado te sugiero que lo hagas porque lo necesitamos
seleccionado para los siguientes pasos:
También se puede observar que de la raíz de dicho archivo
está el archivo con extensión “.ucf” que tiene que ver con la configuración de
pines que hemos hecho del hardware mediante el PlanAhead.
Hacemos clic botón derecho del ratón en dicho archivo
seleccionado.
Nos aparece el siguiente cuadro de diálogo:
Dentro
de él seleccionamos “ChipScope Definition and Connection File”:
Por supuesto es imprescindible que el casillero “Add to
Project” esté seleccionado, lo más normal es que esté ya seleccionado por
defecto, sino lo está haz clic en él.
Ahora en el campo “File name”, le damos el nombre que
queramos, yo que soy un poco sesudo a veces le voy a llamar TestChSc0.
Clic en “Next”.
Ahora tenemos la siguiente ventana emergente que tiene una
función meramente informativo, en ella clic en “Finish”.
Después de un ratito no muy largo de procesamiento ya
tenemos un nuevo fichero en la ventana superior izquierda llamada Design dónde
está el Hierachy (jerarquía en inglés, haciendo alusión a la jerarquía en el
“árbol” de ficheros del proyecto).
Este archivo o fichero (con extensión “.cdc”), es lo que se
llama el “Inserter”, y lo vamos a usar para definir qué es lo que queremos
visualizar de la simulación del proyecto.
---------------------------------------------------------------------------------------------------------
Yo decido mostrar la simulación que concierne al proceso P2,
que es el que gestiona las salidas a los leds: led1_0, led1_1, led1_2 y led1_3. Dichas salidas se gestionan con el “reloj”
CLK2, y pongo reloj entrecomillado porque el auténtico reloj del sistema es una
entrada de este notada como clk. CLK2 es una señal resultado de procesar la
señal de reloj de entrada clk para que la transición entre led encendido, led
apagado y siguiente led encendido pueda detectarla el ojo humano (clk tiene una
frecuencia demasiado alta para eso).
¿Porque decido mostrar esa parte del algoritmo y no toda u
otra parte?, porqué de entre las diversas simulaciones que he hecho en los últimos días esta es la que
tiene mejor presentación sin tener que complicar mucho el proceso, y quiero que
la persona que lea esto le guste el ChipScope, no que empiece a "tomarle ojeriza" desde el principio.
Si usas algún hardware (Nexys o Basys por ejemplo)
compatible con el software Diligent Adept todo se simplifica mucho y las visualizaciones
son mucho mejores.
---------------------------------------------------------------------------------------------------------
Hacemos doble clic en
el archivo TesChSc0, tras lo cual no tendremos inmediatamente un cuadro de
diálogo sino que el programa empezará a procesar cosas la síntesis, el análisis
HDL… etc (esto nos va apareciendo en la consola que normalmente ocupa todo lo
largo de la parte inferior del interfaz.
En un momento dado (sin que haya acabado el procesamiento),
surge la secuencia de cuadros de diálogo que tenemos que cumplimentar.
En la primera ventana ya está todo cumplimentado por
defecto, así que Next.
En esta otra ventana tampoco hay nada que hacer, puro
trámite en este caso, Next.
En este otro cuadro de diálogo si nos tenemos que fijar
mejor, haremos especial hincapié en lo que circulo en rojo en la siguiente
figura:
Para entender mejor que son los “Input Trigger Ports” vamos
a usar el caso concreto de este tutorial. Dije anteriormente que pretendemos
visualizar la simulación del proceso P2:
Si nos fijamos en el código del proceso P2 vemos que se
activa mediante en el momento en que se ejecuta la lista sensible de dicho
proceso (indicada al principio entre paréntesis tras la palabra reservada de
VHDL PROCESS).
En la implementación de código en el hardware, si en
cualquier otro lugar del código se ejecuta una instrucción en la que aparezca
CLK2, de forma paralela y casi inmediatamente se empezará a ejecutar el proceso
P2.
Esto es una característica propia de los sistemas digitales
y del lenguaje VHDL -que viene a ser una forma más de describir esos sistemas
digitales como pueden ser los FPGA- A esta característica la llamamos ejecución
de instrucciones concurrente o concurrencia.
En la simulación, como la hace el ordenador, en principio se
ejecutan las instrucciones de forma secuencial, así que de alguna manera la
concurrencia se implementaría como una llamada a la “función” P2 en cuanto se
activa CLK2.
Para decirlo de una forma simple y resumida: el proceso P2 se pondrá en marcha en cuanto
se active la señal CLK2.
Por tanto nuestra Input
Trigger Ports aquí será CLK2.
Pero el espacio a rellenar no nos indica quién en el Input
Trigger Port, sino cuantos usaremos, como sólo usamos CLK2 en el desplegable
que activamos a la derecha del casillero (y aquí seguro que se denomina en
inglés drop-down list), debemos buscar el 1 o dejarlo en 1 si te viene por
defecto como es mi caso.
Por tanto:
Number of Input
Trigger Ports = 1
2 – Trigger Width:

Podemos tener un solo puerto para la señal de activación de
entrada (Input trigger port), pero el puerto puede – por ejemplo- ser un bus en
el que se mandan 8 bits en paralelo (la señal de entrada en este caso sería un
vector de tamaño 8).
No es el caso, CLK2 es una señal que funciona como un reloj,
de manera que en un instante de tiempo t0 hay un 0 lógico, en el
siguiente t1 hay un 1 lógico… etc.
Es decir, CLK2 es un
tren de pulsos de una sola línea.
---------------------------------------------------------------------------------------------------------
Nota importante:
Pero ojo, y esto es importante, cuando se ejecuta el proceso
P2, se ejecuta para el valor que tenga en ese momento CLK2, es decir un 1 o un 0 (recordemos que CLK2 es la "lista" sensible del proceso P2).
De manera que todos los parámetros (señales, variables… etc)
que hay dentro del proceso P2 trabajarán o bien con un 1 lógico fijo en CLK2, o
bien con un 0 lógico fijo en CLK2, hasta que se ejecute el proceso completo.
Será cuando vuelva a ejecutarse o “llamarse” al proceso P2,
cuando ese valor 0 o 1 pueda cambiar.
Es por eso que si pretendiéramos en este ejercicio
visualizar CLK2, veríamos una línea recta con valor 1 o 0 en lugar del tren de
pulsos que esperaríamos encontrar (puedes hacer la prueba después de este
tutorial si lo deseas).
Y ahí es donde entra el rol del reloj del sistema o de la
señal que tomemos como reloj de la simulación (que en este caso será también
CLK2).
Si el reloj (que es un tren de pulsos), está en un 0 lógico
-por ejemplo-, P2 se simulará con CLK2 = 0, pero si en el siguiente instante de
tiempo muestreado la señal de reloj (CLK2 en nuestra simulación), cambia a 1, entonces
P2 se ejecutará con CLK2 = 1.
Entender bien esto es importante porque cuando simulamos en
un proceso, lo hacemos para un “Trigger Input Port” determinado, y no para
todos los tránsitos de la señal de reloj.
Es por eso que si hemos hecho nuestro código en VHDL de
forma funcional o algorítmica, que es normalmente mediante procesos, no va a ser
fácil simular para comparar señales, señales como las de trenes de pulsos por
ejemplo (que es la forma que tendrá en nuestro caso tanto clk, como clk1, como
clk2).
---------------------------------------------------------------------------------------------------------
Por tanto:
Trigger Width = 1
3 – Match Type:
En este caso no es importante, podemos dejarlo tal y como
está por defecto. Pero no está mal considerarlo para otros casos, para ello dejo
la siguiente tabla: En este caso no es importante, podemos dejarlo tal y como
está por defecto. Pero no está mal considerarlo para otros casos, para ello dejo
la siguiente tabla:
El resto de casilleros y cuadros se dejan igual que como
vienen por defecto.
Por consiguiente nos queda:
Ahora clic en Next.
Nos fijamos en lo que está señalado en rojo en la siguiente
figura.
Data Same As Trigger: Se usa para que los datos a simular sean a la vez los "trigger". Normalmente viene por defecto su casillero activado (como en la figura
anterior). Si está activado en esta ocasión interesa que lo desactives.
Teniendo ahora:
Fijémonos en los dos parámetros que señalo con rojo en la siguiente figura:
Data Width: vamos
a simular el comportamiento de las cuatro señales de salida que van a los leds,
esto es: led1_0, led1_1, led1_2 y led1_3.
De lo que se deduce:
Data Width = 4
Data Depth: para
entender lo que significa este parámetro, hay que entender que el software que
simula tiene que tomar un número finito de muestras. Cuantas más muestras se
toman, más y mejor definidas estarán las señales que visualicemos en la
simulación, pero por el contrario más memoria consumimos y la ejecución de los
resultados también puede tardar más.
Así que esto depende
de cada diseño y de nuestro criterio. En este caso vamos a visualizar trenes de
pulsos que no son señales complejas que necesiten muchas muestras, no obstante
para “curarnos en salud” tomamos 1024.
Por último veamos el parámetro Sample On (Clock Edge).
Este indica si las modificaciones de las señales vienen
dadas por los cambios de reloj en flanco de subida o flanco de bajada.
Lo dejamos con el flanco de subida, es decir, Rising.
Con lo que tenemos:
Ahora Next.
En el campo central (la ventana Net Conections), nos
encontramos UNIT, CLOCK PORTS Y DATA PORTS en rojo porque aún no les hemos dado
valores, para ello hacemos doble clic en cualquiera de ellos.
Se abre la siguiente ventana emergente:
Vamos a darle valor al Trigger
Signals, para lo cual tenemos que encontrar CLK2 en esa lista enorme de
señales y variables que encontramos.
Un truco para hacerlo es teclear clk2 en el campo a la
derecha de dónde pone Pattern (patrón en inglés).
Ahora seleccionamos esa única señal en que se ha quedado la
lista y clic en Make Conections.
Ahora hacemos clic en la pestaña Clock Signals y seguimos exactamente el mismo procedimiento:
De la misma manera le damos valores led1_0, led1_1, led1_2 y
led1_3 a Data Signals.
Ahora clic en OK y nos queda:
Si nos fijamos ahora tanto CLOCK PORT, como TRIGGER PORT,
como DATA PORT, como UNIT están en negro señal de que han sido cumplimentados.
A continuación hacemos clic en Return Project Navigator tras lo cual emerge una ventana llamada Save Project en la que hacemos clic en
SI.
Con lo
cual volvemos al ISE Project Navigator con el Insert ChiScope ya configurado.
Paso 5: Conectamos
mediante el ChipScope con el hardware.
Seleccionamos en
la ventana superior izquierda denominada Design
el archivo LEDA_blogChSc0-light_blogChSc0.vhd,
y luego en la ventana inferior izquierda de Processes deslizamos el
scroll hacia abajo hasta encontrar el icono Analyze Design Using ChipScope.
Doble clic en dicho icono.
Ahora empecerá a procesarse el Análisis. La primera vez a mí
me lleva un buen rato, empiezan a aparecer comandos en la consola y a veces
parece que el programa se ha quedado “colgado”, pero luego sigue sin problemas.
Si te ocurre lo mismo piensa que es relativamente normal, no ha ido nada
necesariamente mal.
Ten en cuenta que en el proceso se está sintetizando,
implementando, generando el archivo de programa… y eso con todos los pasos
intermedios que conllevan cada uno de estos pasos.
Es un proceso largo, y si no tienes un ordenador “en forma” (al
mío no le vendría mal una limpia) y potente es fácil que ocurra.
Si todo ha ido bien nos surgirá la siguiente ventana:
Hacemos clic en el extremo superior izquierda en el icono Open Cable/Search JTAG Chain.
Ahora debería salir un cuadro de diálogo como en el de la
siguiente figura en el que daremos en OK.
Si sigue yendo bien las cosas te dirá en la ventana de
consola inferior algo como:
MyDevice0 (XC3S250E) is not configured
(sin ningún mensaje
de error en rojo).
Para configurar seguimos los siguientes pasos:
Seleccionamos dónde se señala con fondo azulado en la
siguiente imagen. Es decir, DEV:0 MyDevice0 (XCS3S250E) en mi caso, si estás
usando un hardware diferente al mío dónde aparece (XCS3S250E) saldrá otra cosa
diferente.
En donde hemos seleccionado hacemos clic en el botón derecho
del ratón y tendremos un desplegable como en la figura de a continuación:
En dicho desplegable clic en Configure…
Nuevamente aparece una ventana emergente dónde haremos clic
en el botón que señalo con una flecha roja a continuación:
Tras esto navegamos hasta encontrar el archivo con extensión
“.bit” (en mi caso lo encuentro inmediatamente y se llama leda_blogchsc0.bit).
Lo seleccionamos y le damos a abrir.
Tras esto volvemos a encontrarnos con la ventana anterior
pero esta vez pulsamos en OK.
Finalmente podemos comprobar que el hardware empieza a hacer
exactamente lo que esperábamos de él (los leds se van encendiendo y apagando
secuencialmente).
Dejo un clip para demostrar esto que acabo de decir.
Normalmente esto sería suficiente, pero el objetivo de este
tutorial no es demostrar que nuestro código funciona (cosa que por otra parte
ya he demostrado en otras entradas), sino familiarizarnos con el uso del
ChipScope, así que aún nos queda simular por software.
Paso 6: Simulamos.
El interfaz del ChipScope tendrá ahora el siguiente aspecto:
Vemos que en la ventana pequeña superior izquierda ahora
tenemos las opciones:
- Trigger Setup
- Waveform
- Listing
- Bus Plot
Hacemos doble clic en Trigger Setup, y luego en Waveform.
La cuestión es que yo ya simulé esto y se “de buena tinta”
que no es necesario 1024 muestras para tener una visualización aceptable de los
resultados, de hecho si simulamos con 1024 tardará más en mostrarse los
resultados y prefiero hacerte ganar tiempo. Pongamos mejor 128 muestras aunque
parezca demasiado poco.
Ahora
clic en el icono que señalo con la flecha roja llamado “Apply Settings and Arm
Trigger”.
Hay un impasse de espera en el que el buffer se va cargando
con las muestras obtenidas por el programa ChipScope.
La visibilidad de esto aún se puede mejorar. Para ello
seleccionamos la opción Waveform en la ventana superior izquierda y luego le
damos el zoom in.
Una
forma de verlo, es además de acercarlo suficientemente, usar los cursores
verticales X y O.
Y así sucesivamente, de forma que podemos tener una
secuencia tal y como vemos en la siguiente figura:
Espero que los dos siguientes videos sean suficiente descriptivos de lo que acabo de explicar:
Si no se ven suficientemente claros los clips, puedes hacer clic en dónde señalo en la siguiente imagen y lo podrás ver en modo pantalla completa (Full Screen).
Y ahora si, pondré como en las películas antiguas:
- THE END -











































































0 comentarios: