2017_07_08: Makespace Madrid

Juan Gonzalez-Gomez edited this page Nov 5, 2017 · 278 revisions

Taller de electrónica digital para Makers, con FPGAs Libres

Ficha

  • Título: Taller de electrónica digital para Makers, con FPGAs Libres
  • Repositorio: 2017-07-08-makespace-madrid
  • Lugar: Makespace Madrid
  • Instructores: Jesús Arroyo y Juan González Gómez
  • Duración: 2h
  • Fecha: 08 de Julio de 2017, en primera convocatoria, y 13/Julio/2017 en la segunda :-)
  • Hora: 18:00h
  • Asistentes: 10
  • Destacado: El taller estaba planificado para el 8 de Julio, sin embargo... en vez del taller había preparada una fiesta sorpresa para Obijuan con motivo del O'Reilly Open Source Awards :-) Así que el taller se aplazó al 13 de Julio

Colección

Resumen

Introducción al diseño de circuitos digitales usando Icestudio y la placa Icezum Alhambra, con un enfoque puramente práctico. Se comienza por lo más sencillo: encender un led y se van introduciendo otros elementos gradualmente. Se utilizan servos y sensores de IR para hacer pequeños automatismos

Contenido

Herramientas y material

Icestudio 0.3. Entorno gráfico, libre y multiplataforma, para trabajar con placas con FPGAs libres
Inkscape Programa libre y multiplataforma para dibujo vectorial
Placa Icezum Alhambra. Tarjeta entrenadora con FPGA libre
Servo Futaba 3003 o compatible
Sensor de Infrarrojos de 5v, con 3 pines: vcc, gnd y señal

Parte I: Instalación de las herramientas software

Para realizar el taller, necesitamos tener instalada la herramienta Icestudio y la colección con los bloques y ejemplos que usaremos. Opcionalmente, se instalará el terminal de comunicaciones ScriptCommunicator y el programa de dibujo 2D Inkscape

Instalación 1: Icestudio

Dejaremos instalado y configurado el programa Icestudio. Estos pasos sólo hay que hacerlos la primera vez. Luego, una vez listo, simplemente se arranca icestudio, se conecta la placa y a trabajar

Paso 1: Descargar el fichero de instalación, según el sistema operativo.

Elegir la opción de 64 ó 32 bits, según el ordenador que se tenga:

Paso 2: Ejecutar el instalador

  • GNU/Linux: Paso no necesario en Linux
  • Mac: ??
  • Windows: Arrancar el instalador, y en las opciones que aparecen apretar siempre en la tecla siguiente

Paso 3: Arrancar Icestudio

  • GNU/LInux: Descromprimir el fichero .zip. Entrar en la carpeta creada y ejecutar icestudio
  • Mac: ???
  • Windows: Buscar por la aplicación Icestuddio recién instalada, y ejecutarla

Al arrancar Icestudio aparecerá una ventana como esta:

Paso 4: Instalar la toolchain

Para poder sintetizar circuitos, es necesario instalar la toolchain. Para ello nos vamos a la opción Herramientas/toolchain/Instalar

Se nos abrirá una ventana donde pondrá el progreso de la instalación. Dependiendo del ordenador, esta operación puede tardar varios minutos

Una vez finalizada la instalación, aparecerá esta ventana:

y pulsamos en OK para terminar

Paso 5: Comprobar la toolchain (Opcional)

Este paso se puede realizar más adelante, sin embargo esto le servirá a la gente que quiera hacer pruebas de síntesis pero que NO tenga una placa con FPGA libre

Cargamos un programa hola mundo ejemplo, desde Archivo/Ejemplos/1.Básico/01.UN LED

Nos aparecerá el circuito en la ventana, junto con una notificación verde indicando que se ha cargado correctamente (que desaparecerá a los pocos segundos):

Ahora probamos a sintetizar el circuito, pulsando en la opción Herramientas/Sintetizar:

Empezará la síntesis del circuito. Al cabo de pocos segundos aparecerá un mensaje verde de confirmación de que la síntesis se ha hecho bien, junto a los recursos consumidos:

¡Ya estamos listos para continuar con la instalación!

Paso 6: Habilitar el driver de la tarjeta con FPGA libre

Para que el ordenador reconozca la tarjeta con la FPGA libre y poder cargar en ella los circuitos sintetizados, es necesario habilitar el driver. Primero conectamos la placa a un puerto USB. Luego nos vamos a la opción Herramientas/drivers/habilitar:

(Da igual si tenemos el ejemplo anterior abierto. Funciona igual si tenemos un ejemplo cargado o la ventana está en blanco)

La opción de habilitar el driver es diferente según el sistema operativo

Sistemas GNU/Linux y Mac

La operación de habilitar el driver requiere permisos de administración. Por ello nos aparecerá una ventana solicitando la clave del usuario

La introducimos, y a los pocos segundos nos aparecerá la notificación de que el driver ya está habilitado:

Tendremos que desconectar la placa y volverla a conectar. Ya lo tenemos todo listo

Windows

En las máquinas con Windows la parte de los drivers siempre es problemática. Al habilitar el driver nos aparecerá una ventana con las instrucciones a seguir

(PENDIENTE: Poner captura con las instrucciones)

(TODO: Hacer instrucciones para windows)

Paso 7: Cargando nuestro primer circuito en la FPGA

Ya lo tenemos todo listo para hacer la primera prueba de carga en la placa de la FPGA (¡El momento de la verdad!)

Abrimos el ejemplo "hola mundo" si no lo teníamos abierto ya, desde Archivo/Ejemplos/1.Básico/01.UN LED

Nos aparecerá el circuito en la ventana, junto con una notificación verde indicando que se ha cargado correctamente (que desaparecerá a los pocos segundos):

Nos aseguramos que la placa de la FPGA está conectada en el USB y le damos a la opción de Herramientas/cargar:

y comenzará la descarga. Nos aparecerá una notificación indicando que ha comenzaddo la carga

A los pocos segundos debe aparecer otra notificación verde indicado que ya está todo ok:

¡¡Ya estamos listos para hacer el taller!! :-)

Solucionando problemas

  • Placa Icezum Alhambra NO Detectada

Si no podido realizar la carga del circuito y aparece un mensaje de error con el fondo rojo diciendo que la placa no se ha detectado, nos aseguramos de los siguientes puntos:

  • Que la placa estaba correctamente conectada al USB. Desenchufarla y volverla a enchufar. Repetir la operación de carga

  • (Usuarios de windows): Asegurarse de que la placa está conectada en el mismo USB donde se habilitó el driver. Esto es muy importante. En windows los drivers se asocian a cada conector USB. Si se conecta a uno diferente, donde no se ha instalado el driver previamente, no reconocerá la placa

  • (Usuarios de windows): Si sigue sin detectar la placa, probar a habilitar el driver en un USB diferente, repitiendo las instrucciones del paso 6, pero con otro USB. Puede ocurrir que en el USB elegido, ya haya un driver de otro dispositivo previamente instalado, que haga conflicto

  • (Usuarios de windows): Si los problemas persisten, otra opción es conectar un hub usb (que nos asegura que no hay drivers instalados), conectar la placa a uno de esos USB del hub y volver a habilitar el driver, siguiente las instrucciones del paso 6

  • Si no se consiguen resolver los problemas, escribir un correo en la lista de FPGAwars, aportando toda la información posible: sistema operativo, placa conectada, errores que aparecen, pruebas hechas, etc, para poder solucionarlo entre todos

Instalación 2: Colección makespace-17

Los bloques y ejemplos de icestudio se agrupan en colecciones. Lo siguiente será instalar la colección del taller del Makespace, que trae los bloques y ejemplos que usaremos. Para ello hay que hacer lo siguiente:

  • Descargar este fichero: makespace-17.zip (No descomprimir el archivo)

  • Abrir Icestudio

  • Añadir la colección a Icestudio: Ir a la opción Herramientas/Colecciones/Añadir. Seleccionar el archivo descargado previamente (makespace-17.zip)

  • Seleccionar la colección makespace-17: Ir a la opción Select/Collection/makespace-17

En menú superior veremos las nuevas opciones que aparecen para mostrar los bloques. También tendremos ejemplos nuevos en Archivo/ejemplos

Instalación 3: Programa Inkscape (opcional)

Opcionalmente instalar el programa Inkscape. Lo usaremos para las figuras de nuestros propios bloques personalizados

Instalación 4: Programa Scriptcommunicator (opcional)

Opcionalmente instalar el terminal de comunicaciones ScriptCommunicator. Lo usaremos para conectar nuestros circuitos con el ordenador

Parte II: Frikeando con FPGAs

Comenzamos la creación de circuitos digitales, sintetizándolos en la placa Icezum Alhambra

Ejemplos básicos I

Empezaremos con circuitos sencillos que encienden los leds. El primer de todos, el "hola mundo", lo haremos desde cero muy detalladamente, para mostrar la mecánica de funcionamiento. Para el resto de ejemplos se indicarán las opciones del menú que el usuario debe usar y se mostrará el circuito final que se tiene que crear, pero se dejan los pasos intermedios para que el usuario practique

Ejemplo "Hola mundo": Encender un led

El circuito digital más sencillo que se puede hacer es el que enciende un led. Sólo hay que colocar un pin de salida, un bit a 1 y unirlos mediante un cable. El resultado final debe ser esto:

Este ejemplo está accesible desde el menú Archivo/Ejemplos/01-Basicos/01-ledon. Sin embargo, lo crearemos desde cero para aprender el manejo de icestudio

Abrimos Icestudio. Nos aparecerá una pantalla en blanco como esta:

En Icestudio estamos "dentro" de la FPGA. Para encender un led, tenemos que sacar un bit 1 hacia fuera de la FPGA, donde están conectados los leds de la Icezum Alhambra. Lo primero es colocar el pin para salir al exterior. Lo hacemos desde la opción de menú: Básico/Salida.

Nos aparece una ventana para introducir el nombre del pin de salida

Podemos darle cualquier nombre, por ejemplo LED

Pinchamos en OK. Nos aparece un bloque amarillo en la posición del ratón, con la etiqueta LED en la parte superior. Movemos el ratón para colocar el bloque donde queramos y hacemos click con el botón izquierdo

Hemos colocado un pin de salida genérico. Todavía no está asociado a ninguna pata físicia de la FPGA. En este ejemplo, queremos que se corresponda con la pata que está conectada al LED0 de la Icezum Alhambra. Esto lo establecemos desde el menú desplegable que está dentro del bloque

Al hacer click con el botón izquierdo en él, nos aparecen los nombres de las patas físicas

Seleccionamos LED0 y hacemos click. Ahora ya tenemos seleccionado el pin de salida que se corresponde con el LED 0

A continuación colocamos el bit 1, pinchando en Const/Bits/1

Nos aparece el bloque 1 en la posición de ratón. Lo colocamos como se muestra en la figura y hacemos click con el botón izquierdo del ratón

Vemos que nos aparece un "1" con patitas :-) Yo me imagino siempre a los bits como unos bichitos que tienen patas y que van correteando por los cables. Ahora tiramos un cable para unir el Bit 1 hasta el pin de salida. Nos situamos en la parte derecha del bloque 1 hasta que el cursos se convierta en una cruz

Dejamos el botón izquierdo pulsado y movemos el ratón para que aparezca el cable

Nos situamos en la parte izquierda del pin de salida. El cursor cambia de cruz a mano cerrada

Soltamos el botón izquierdo. ¡Ya tenemos nuestro primer circuito digital creado! :-)

Con este ejemplo hemos aprendido a crear pines de salida y a tirar cables. Ahora lo sintetizaremos y cargaremos en la placa Icezum Alhambra. Nos aseguramos que está conectada al USB del ordenador. En la parte inferior hay un led azul (PWR) encendido que indica que está alimentada

Para sintetizarlo y cargarlo en la placa le damos a la opción Herramientas/cargar

Nos aparecerá una notificación en la parte inferior derecha de la pantalla, indicando que comienza la carga

En la Icezum se encederá un led naranja en la parte superior, etiquetado como CFG para indicar que ha comenzado la configuración de la FPGA

Al cabo de unos segundos aparecen en la pantalla las notificaciones que nos indica que la carga ha finalizado, así como los recursos utilizados

Veremos cómo el LED0 se enciende, y el resto permanecen apagados

En esta animación se muestra el proceso completo de creación del circuito hola mundo desde cero, y su carga en la Icezum Alhambra

El resultado en la placa es este:

Cuando hacemos un circuito en icestudio y lo cargamos, se transfiere a la FPGA. Si pudiésemos ver qué hay en el interior de la FPGA, veríamos nuestro circuito:

Nuestro circuito de icestudio se ha mapeado en los recursos de la FPGA, y se ha materializado físicamente. Es decir, que nuestro circuito existe y ocupa un espacio. No es una simulación ni una emulación

Ejercicio:

  • Cambiar el led del puerto de salida para que sea otro diferente, por ejemplo el LED7. Cambiarlo y volver a cargar el circuito. Probar con otros leds: LED1, LED2, etc

Experimento: El circuito es no volátil

Cuando cargamos el circuito en la placa, en realidad se queda grabado en una memoria flash, de manera que al alimentar la placa, se carga automáticamente el circuito. Esto permite que nuestros circuitos sean no volátiles: Si desconectamos la placa de ordenador, y la volvermos a conectar, se configurará la FPGA y se encenderá el led (que es el último circuito que hemos cargado)

Tambien podemos alimentar la placa través del jack de alimentación, y así nuestro circuito será autónomo (no necesitamos estar conectados al PC). En esta foto vemos la placa cargada con el circuito "hola mundo", conectado a una pila de 9v

Para conectar la alimentación el interruptor rojo de la parte inferior tiene que estar desplazado hacia la izquierda. Si lo llevamos a la derecha se desconecta la alimentación y el led se apaga

Ejemplo 2: Apagando el led

Para hacer un circuito que apague el led que acabamos de encender, simplemente ponemos una constante de bit 0 en vez de 1. Partiendo del circuito anterior, nos situamos sobre el bloque Bit 1 y hacemos click con el botón izquierdo del ratón para que se seleccione. Aparecerá un borde azulado alrededor

Pulsamos la tecla delete para eliminarlo. También se podría hacer desde el menú: Editar/Cortar

Ahora colocamos la nueva constante Bit 0, que la encontramos en el menú superior en Const/Bits/0

Y tiramos un cable para unirlo con el pin de salida

Lo cargamos en la placa. Vermos como ahora el LED0 ya NO está encendido

Ejemplo 3: Encendiendo 2 leds

Ahora usaremos una de las características más importantes del hardware: el paralelismo. Partimos del ejemplo original de encender un LED. Bien lo creamos desde cero o bien cargamos directamente el ejemplo desde el menú Archivos/Ejemplos/01-Basicos/01-led-on

Para encender 2 leds, hacemos un "copy & paste" del circuito original. Primero seleccionamos el circuito manteniendo pulsado el botón izquierdo y moviendo el ratón hasta que la ventana de selección cubre todo el circuito

Soltamos el botón. Los dos bloques del circuitos estarán seleccionados

Ahora hacemos el copy & paste. Se puede hacer através de la opción del menú: Editar/Copiar y luego Editar/Pegar

o también utilizando los atajos de teclado (lo más habitual y más rápido): primero pulsamos ctrl-C y luego ctrl-V

Nos aparece una copia del circuito en la posición del ratón, que está seleccionado. Pulsando con el botón izquierdo del ratón sobre alguno de sus bloques movemos el circuito entero. Lo ponemos debajo del original

Hacemos click en cualquier punto del fondo blanco para quitar la selección y cambiamos el LED0 por LED7

Ya tenemos el circuito que enciende dos leds, que en realidad son dos circuitos en paralelo. Lo cargamos en la placa, y veremos los dos leds encendidos al cabo de unos segundos:

En esta animación se puede ver el proceso completo de creación del circuito

Circuito equivalente

Otro circuito equivalente es conectar dos cables desde un único bit a 1

Para hacerlo, partimos del circuito anterior y borramos el bit 1 inferior

Nos situamos en la parte derecha del bloque del bit 1, igual que hicimos para tirar un cable, hasta que el cursos se transforma en una cruz

Apretamos el botón izquierdo y vemos cómo aparece un cable nuevo, que está unido al original. Esta unión se va desplazando según movemos el cable

Finalmente nos situamos en la parte izquierda del bloque de salida del LED7 y soltamos el botón para completar el cable

Vamos a mover el nuevo cable. Al situarnos encima se selecciona y aparece una X roja. Si pinchamos en esta X el cable se elimina (no es lo que queremos ahora)

Para desplazarlo pulsamos el botón izquierdo (aparece un círculo verde) y movemos el cable hacia la izquierda

Soltamos el botón y ya hemos finalizado el circuito

Ejercicio: Encender todos los leds impares

Se propone como ejercicio hacer un circuito en el que se enciendan los 4 leds impares: LED1, LED3, LED5 Y LED7, usando ún unico bloque bit 1

Solución:

Personalizando y documentando bloques

Los bloques los podemos personalizar, creando nuestros propios bloques con las imágenes o dibujos que queramos. También se puede añadir documentación

Ejemplo 1: Bloques de información

Añadir información de texto a nuestros circuitos es muy importante, para tenerlos bien documentados. Esto lo hacemos añadiendo bloques de información. Vamos a abrir el ejemplo que hay en Archivo/Ejemplos/02-Bloques-Personalizados/01-Comentarios

Nos aparece el circuito "hola mundo" que ya conocemos, pero con comentarios

Hay tres bloques de información que podemos mover como si fueran elementos de nuestro circuito. Vamos a mover el primer bloque, que tiene un marco, y lo pondremos encima del circuito. Colocamos el ratón en el marco hasta que el cursor tenga la forma de una mano cerrada

Ahora mantenemos pulsado el botón izquierdo y movemos el ratón para arrastrar el bloque. Lo colocamos en la parte superior del circuito

El bloque de texto de la parte inferior no tiene marco, pero se puede mover igual. Colocamos el cursor encima y lo arrastramos hasta la parte inferior del circuito

El bloque superior es de lectura/escritura. Esto significa que lo podemos editar y cambiar el tamaño de la ventana de texto. Nos situamos encima del bloque y hacemos click para entrar en modo edición. Ahora podemos editar el texto. Añadimos una cadena al final

También podemos cambiar el tamaño de la ventana, arrastrando la esquina inferior derecha

Vamos a converir el bloque superior en un texto de sólo lectura. Hacemos doble click sobre el marco para acceder a sus propiedades. Se nos abre una ventana nueva

Marcamos la propiedad de Sólo lectura

Y pinchamos en OK. Ahora el bloque ya no tendrá marco y no lo podremos editar, pero sí mover

También se puede realizar a la inversa. Vamos a convertir el bloque inferior en un bloque de lectura/escritura. Al hacer doble click nos aparece su ventana de propiedades, donde la casica "Sólo lectura" está marcada. La desmarcamos y damos al ok. Ahora el texto aparecerá en un bloque editable

Los bloques con comentarios se crean en la opción del menú: Básico/Información

Nos aparecerá un bloque nuevo, situado sobre el cursor del ratón. Lo colocamos en la posición deseada y hacemos click con el botón izquierdo

Ahora ya podemos introducir nuestro comentario

Ejercicio

Hacer el circuito para encender los 4 leds impares, colocando un bloque con la información del circuito: Qué hace, autor, fecha, etc.

  • Solución:

Ejemplo 2: Bloques de bits constantes diferentes

Para encender los leds, hemos usado los bloques constantes de bit. Lo normal es usar el 1 para encender y el 0 para apagar, pero en icestudio se pueden crear bloques con diferentes dibujos. Por ejemplo, se puede usar una antorcha encendido como 1, y una apagada como 0. O cualquier otra metáfora que se nos ocurra

En la colección del taller de Makespace se han creado bloques de bits constantes con diferentes imágenes. Para verlos todos abrimos el ejemplo que está en Archivo/Ejemplos/02-Bloques-personlizados/03-Constantes-Bit-Personalizadas

Y nos aparece este circuito tan extraño:

En realidad se trata del clásico: "Encener los 4 leds impares" que ya conocemos, pero se están utilizando otras constantes para representar los bits a 1 y 0. Si nos fijamos en los LEDs impares, vemos que el LED7 está conectado a la constante 1. El LED5 a la constante 1 "con patitas". El LED3 a la antorcha encendida y el LED1 a un conmutador en on

Todos estos bloques hacen lo mismo: encender el led. Son en realidad bloques que representa un bit a 1 constante, pero usando diferentes imágenes. Si ponemos el ratón encima de alguno de estos bloques, y lo dejamos sin mover unos segundos, aparecerá una descripción del bloque. Vemos cómo en todos ellos pone el comentario: "Un bit constante a 1"

Al ponernos sobre el 1 con patas obtenemos el mismo mensaje:

Los leds pares se han conectado a las constantes 0. En realidad no hace falta, porque por defecto estarán apagados. Pero se han añadido en el ejemplo para mostrar ambos estados. Así, tenemos los bits clásicos: 0,1. La misma versión con "patitas", que es la que hemos usado en los ejemplos anteriores. Y la versión con antorchar e interruptores. En nuestros diseños podremos usar cualquiera de esos bloques indistintamente o crear los nuestros propios

Ejercicio: Encender 2 leds con la antorcha :-)

Para practicar, se propone hacer un circuito que encienda los LEDs 6 y 1, utilizando la antorcha. Esta se encuentra en el menú Const/Bits/1-torch

  • Solución:

Ejemplo 3: Bloque de bit constante personalizado

Con Icestudio podemos crear nuestros propios bloques personalizados. Haremos nuestra propia versión del bloque de bit 1 constante, con nuestra foto

Abrimos un proyecto nuevo, pinchando en Archivo/Nuevo para que nos aparezca una ventana nueva y vacía. Nuestro bloque constante es un circuito que sólo tiene una salida, que estará siempre a 1, y ninguna entrada. Lo crearemos basándono en los bloques que ya conocemos

Partimos del circuito "hola mundo" que enciende un led, que ya sabemos hacer. Podemos usar cualquiera de los bloques constantes que ya conocemos (antorcha, switch, 1, ó 1 con patitas). Yo usaré la antorcha:

El bloque amarillo etiquetado como LED se corresponde con un pin físico de la FPGA. Par definir nuestro bloque, queremos que ese pin sea una salida de mi bloque, pero que **NO ESTÉ ASOCIADO FÍSICAMENTE a ningún pin++. Para ello hacemos doble click en el bloque para acceder a sus propiedades

El pin tiene 2 propiedades: el nombre y si se trata de un pin físico de la FPGA. Borramos el nombre actual (LED) y no ponemos ninguno. También desactivamos la casilla que pone FPGA pin

Le damos al OK

El pin de salida se ha transformado en un bloque verde. Nos indica que es una salida, pero del bloque, no de la FPGA. Y por tanto no está asociada a ningún pin físico del exterior. Vamos, que no sale al exterior del chip

Con esto ya tenemos definida la funcionalidad de nuestro nuevo bloque: Sacar un 1 hacia fuera. El siguiente paso es cambiar sus propiedades. Pinchamos en Editar/Preferencias/Información del proyecto

Se nos abre una ventana con las propiedades de nuestro proyecto/bloque en blanco

Las rellenamos con nuestra información

El último campo es el que nos permite meter una imagen en SVG. Lo haremos después. Le damos al OK para terminar

Con esto ya tenemos creado nuestro propio bloque, llamado mi-bit1, y que podemos usar como veremos más adelante. Para que quede más chulo, vamos a añadirle nuestra image. Nos hacemos un selfie haciendo algún gesto que indique aprobación, que significará que es un 1 :-)

Voy a eliminar el fondo, para que se vea mejor

Es la típica foto en formato .jpg. Necesitamos que la imagen esté en formato SVG, para importarla en Icestudio. Abrimos el programa Inkscape. Importamos la imagen desde File/import

Abrimos las propiedades del documento en File/Document Properties:

Desplegamos la opción que pone Resize page to content...

y pulsamos el botón que dice Resize page to drawing or Selection

El tamaño de página se ajustará exactamente a la imagen que tenemos:

Podemos añadir dibujos u otras imágenes si queremos (dentro de la hoja). Una vez terminado, hay que guardar el fichero dándole a la opción File/Save y seleccionando el formato Inkscape SVG (que es el que está seleccionado por defecto)

Volvemos al icestudio, abrimos la ventana de información del proyecto en Editar/Preferencias/Información del proyecto. Pinchamos en el botón Abrir SVG y seleccionamos el fichero SVG que acabamos de guardar con el Inkscape. Nos aparecerá una miniatura en la información del proyecto:

Le damos al OK y guardamos el proyecto dando en Archivo/Guardar Como. Le damos el nombre que queramos, por ejemplo mi-bit1.ice. Ya tenemos nuestro bloque listo para ser usado desde otros proyectos de icestudio

Ejemplo 4: Usando nuestro bloque personalizado

Haremos el circuito "hola mundo" usando nuestro bloque personalizado, en vez de la antorcha o el bit 1. Creamos un proyecto nuevo (Archivo/Nuevo o Ctrl-N). Incluimos el nuevo bloque desde la opción Archivo/Añadir como bloque...

Y seleccionamos el proyecto que hemos guardado antes: en mi caso: mi-bit1.ice. ¡Aparece nuestro bloque personalizado! :-)

Ahora ya podemos crear el "Hola mundo" y encender un led con nuestro bloque "Yo-soy-un-bit-1" :-D

Si colocamos el ratón encima del bloque, nos aparecerá el mensaje que hayamos puesto en el campo Descripción de la información del proyecto

Ejemplo 5: Metiendo nuestro bloque en la colección makespace-17

Los bloques personalizados los podemos incluir en nuestros diseños con la opción que hemos visto antes: Archivo/Añadir como bloque. Pero también los podemos incluir en nuestra colección, para que nos aparezcan en el menú

Incluiremos el bloque en la colección del taller de makespace: makespace-17, que es la que hemos instalado. Para ello seguimos los siguientes pasos:

  • Paso 1: Descargar la colección

Nos bajamos el archivo .zip con la colección actual. Esto ya lo hicimos para instalar la colección. Podemos descargar el fichero desde este enlace: makespace-17.zip

  • Paso 2: Descomprimir el zip

En el directorio que queramos, descomprimimos el fichero .zip. Se nos crea la carpeta makespace-17

En su interior tenemos otras dos carpetas: blocks y examples, junto con algunos archivos con información

  • Paso 3: Copiar el fichero mi-bit1.ice en makespace-17/blocks/Const/Bits

El proyecto con nuestro bloque personalizo (fichero mi-bit1.ice) lo copiamos en la carpeta makespace-17/blocks/Const/Bits. Opcionalmente también podemos copiar ahí el fichero SVG que hemos usado como imagen del bloque, por si en el futuro lo queremos editar, pero no es necesario que esté almacenado ahí

Todas las carpetas que se encuentra en makespace-17/Blocks se corresponden con las opciones que aparecen en la parte superior derecha del menú: Const, PUertas, Varios. Cualquier directorio o sub-directorio que creemos, aparecerá como un menú o sub-menú

  • Paso 4: Comprimir la carperta makespace-17 en ZIP

Ahora nos situamos en la carpeta original y comprimimos la carpeta makespace-17 a fichero ZIP. En Ubuntu GNU/Linux lo hacemos dando al botón de derecho y seleccionando la opción compress...

  • Paso 5: Instalar la nueva colección

Ahora instalamos la nueva colección, como ya sabemos: Herramientas/Colecciones/Añadir y seleccionamos el archivo .zip que acabamos de crear. Nos aparecerá una ventana con la opción de cambiar el nombre a la colección

Simplemente le damos al OK. Nos aparece otra ventana preguntando si queremos reemplazarla

Le damos al OK. ¡Listo!

  • Paso 6: Usar el nuevo bloque

Ahora ya tenemos nuestro nuevo componente listo en la opción de menú Const/Bits/mi-bit1

y nuestro bloque aparece :-)

Viaje al interior de los bloques

Se puede acceder al interior de cualquier bloque circuito de icestudio (bloques azules) haciendo doble click. Para comprobarlo, vamos a meternos en nuestro bloque mi-bit1, que acabamos de crear y colocar

Aparece el circuito que habíamos creado. Sin embargo, lo estamos viendo en modo sólo lectura: no podremos modificar nada del circuito. Para la creación del bloque nos basamos en el bloque "Antorcha". Hacemos doble click en él para ver cómo está hecho :-)

Ya hemos llegado a lo más profundo del diseño. El bloque antorcha está creado a partir de código Verilog:

//-- Bit constante a 1
assign q = 1'b1;

Afortunadamente no hace falta llegar a esta nivel para crear circuitos: podemos crearlos a partir de otros bloques básicos. Pero en última instancia, los bloques básicos están hechos en Verilog. Es este código el que se envía a las herramientas libres del proyecto icestorm para la generación del bitstream que se carga en la FPGA

También podemos reutilizar proyectos hechos en Verilog y encapsularlos en nuestros propios bloques de Icestudio, aunque eso es una opción para usuarios avanzados y está fuera de este taller

Para volver al nivel superior, pinchamos en la opción Volver que aparece en la esquina superior derecha. En la parte inferior podemos ver dónde nos encontramos: sin título/mi-bit1/1. La primera cadena es el nombre del documento, que como no lo hemos grabado todavía, no tiene nombre, y por defecto se le asigna sin título. El segundo nivel lo forma el bloque mi-bit1, y el tercer nivel el bloque 1

Probando los Stickers

Los *Stickers son bloques que no tienen ni entradas ni salidas. No forman parte de nuestros circuitos (no ocupan espacio), pero nos sirven para decorar, documentar o frikear :-)

Podemos ver algunos de los stickers ya creados cargando el ejemplo Archivo/Ejemplos/02-Bloques-personalizados/06-stickers

Se nos abre un ejemplo que tiene 15 stickers

Podemos colocar los stickers desde la opción de menú Varios/Stickers

Ponemos como ejemplo otro otro stickers de GNU/Linux

Ejercicio: Sticker personalizado

  • Se propone como ejercicio crear tu propio Sticker personalizado, con la imagen que quieras. Inclúyelo en la colección Makespace-17

Ejercicio: Stickers anidados (Inception!)

  • Se propone como ejercicio hacer un Sticker con Stikers anidados dentro. Abrir el ejemplo de Archivo/Ejemplos/02-Bloques-personalizados/07-Sticker-Trollface-inception para ver un ejemplo de anidación de varios niveles

Ejemplos básicos II

Seguiremos haciendo ejemplos sencillos, que encienden y apagan leds, para familiarizarnos con la electrónica digital y la forma de pensar en hardware

Ejemplo 1: Led parpadeante

Hacer parpadear un led es uno de los ejemplos típicos que se usan para aprender programación con Arduino. Aquí lo haremos, pero en harware. Para lograrlo, necesitamos bombear bits hacia el led, en vez de conectar un bit a 1 fijo, como hemos hecho hasta ahora

El componente para bombear bits es el corazón, que se encuentra en el menú: Varios/Bombeo/Corazon_x1. Colocamos un corazón x1, un pin de salida asociado al LED7 y tiramos un cable. El circuito nos queda así

Al cargarlo, el led empezará a parpadear a una velocidad de un parpadeo por segundo

TODO

  • Ejercicio: dos leds parpadeando a la vez (LED7, LED0)

  • Dos leds que parpadean a diferentes velocidades

  • Puerta NOT: Dos leds palpitando alternativamente

  • Botón "Hola mundo": conectar el sw1 a un led

  • Dos botones sin memoria, conectados a leds

  • Modificar un botón para que sea "con memoria": Pulsador de cambio

  • Meterse dentro del pulsador de cambio ¿Qué hay? Es un ejemplo de bloque definido mediante verilo (avanzado)

  • TEMPORIZADOR: ejemplo de un led encendido durante 5 segundos, y que luego se apaga

  • Entrar dentro del temporizador: Ejemplo de bloque hecho a partir de otros bloques

  • Ejemplo de Servo: Servobit90: conectar el servo Futaba 3003 al botón (OJO! Está calibrado para un Futaba 3003!!).

  • Ejemplo del MONÓCULO!!!

  • Ajustando los valores de las posiciones del servo: ServoBit: Concepto de Parámetro. Conectar otros servos que no sean futaba 3003... o usar un Futaba 3003 pero cambiando las posiciones

  • CREAR un componente nuevo (MiServobit) con los nuevos valores

  • Ejercicio: Barrera de entrada manual. Al dar a un pulsador se abre la puerta. Al volver a dar se cierra

  • Ejercicio: Puerta temporizada: Al darle al pulsador se abre la barrera/puerta. Al cabo de 3 segundos se cierra sola

  • Mismo ejercicio: pero la detección se hace automáticamente, mediante un sensor de IR

  • Ejercicio: Barrera de enrada con detección de entrada / salida con IR (Necesarios 2 IRs)

  • Ejemplo: Perrito Contento: Conectar un corazón al servo, para que oscile de un lado a otro

  • Ejemplo: Posicionamiento de un servo en cualquier posición: Con ServoTime

  • Ejemplo: Secuencia de movimiento desde una rom (8 posiciones)

  • Puerto Serie: Uso de la señal DTR para mover el ServoBit

  • Posicionamiento del ServoTime en la posición especificada desde el ordenador (ScriptCommunicator)

Parte III: Avanzado

Esta parte no se vió en el taller, sin embargo se incluye aquí para que los que quieran puedan profundizar más en los fundamentos de la electrónica digital y entender cómo están hechos algunos de los bloques

Todos los circuitos digitales, por muy complejos que sean, están formados sólo por 3 elementos básicos: puertas lógicas (and, or, not), Biestables y cables (En realidad, los biestables también se obtienen directamente de las puertas lógicas, pero aquí los usaremos como bloques básicos)

Buses

Por cada cable se transmite un bit. Así por ejemplo, para encender 4 leds, colocamos 4 cables en paralelo

En los circuitos digitales se trabaja con números de varios bits, por lo que hay que tirar muchos cables. Para simplificar los esquemas, y que quede más compactos, se agrupan los cables en Buses

Así, el ejemplo anterior se puede simplificar usando un bus de 4 bits, en vez de 4 cables en paralelo. Y también usar la constante 15 de 4 bits, que en binario es el número 1111

Primero colocamos la constante 15 con la opción Const/Bus/04_bits/Valor_15_4bits

Aparece un bloque con el número 15, y un bus de salida en su derecha, con el texto K[3:0], que indica que la salida se llama K y es un bus de 4 bits (desde el bit 0 hasta el 3)

Ahora colocamos una salida de bus, pinchando en Básico/Salida y usando el nombre LED[3:0]

Colocamos el bloque con las 4 salidas. En su parte izquierda tenemos su bus de entrada

Unimos la constante con el bloque de salidas, de la misma forma que tiramos un cable normal

Aparece un cable más gordo, con el número 4 en su parte central. Es un bus de 4 bits

Finalmente asignamos los pines al bloque de salida: LED3, LED2, LED1 y LED0

Este circuito hace exactamente lo mismo que el inicial, de hecho es el mismo circuito, pero al representarlo mediante buses y números todo se simplifica bastante

Este bus podemos separarlo en cables, usando el bloque Split que se encuentra en Varios/Buses/04_bits/Split-4. Es un bloque pasivo, que NO consume ningún recurso. Simplemente se usa para separar el bus y tener acceso a los cables individuales

El bloque Join hace justo lo contrario. Agrupa cables en un bus, y tampoco consume recursos. En este circuito de ejemplo se usan ambos bloques, Split y Join para separar un bus de 4 bits en 4 cables, y unirlos de nuevo en un bus, sin realizar manipulaciones. Es equivalente al primer circuito de ejemplo mostrado

Puertas lógicas

Todas las puertas lógicas: and, or, not y xor se pueden implementar a su vez a partir de un único tipo de puertas lógicas. Una forma es usando SÓLO puertas NAND. Sólo con puertas NAND se puede realizar cualquier función logica. Esto es muy interesante, ya que al final, todo lo digital se reduce a 0, 1, puertas nand y cables. A partir de estos elementos se puede construir cualquier circuito digital. ¡Fascinante!

Puerta NAND

La puerta NAND es un AND negado. Su salida siempre es 1 salvo que sus dos entradas sean 0, en cuyo caso es 0. Su tabla de verdad es la siguiente:

a b NAND
0 0 1
0 1 1
1 0 1
1 1 0

Su funcionamiento se puede comprobar con este circuito de pruebas:

Al cargarlo en la placa se enciende el LED0. Sólo cuando se aprietan los dos pulsadores a la vez, se apaga

La ecuación que describe la puerta NAND es esta:

Y su descripción verbal sería: "algo por algo, negado"

Usaremos esta puerta para ir construyendo las demás, y a partir de las nuevas, otras más. Pero en última instancia todo se reducirá a puertas NAND

La CPU del Apolo, la nave que llevó al primer hombre a la luna, estaba implementada SÓLO con puertas NAND

Bajando de nivel

Si pinchamos en la puerta NAND y nos metemos dentro, veremos su implementación en Verilog

assign c = ~(a & b);

La toolchain libre para síntesis (yosys + icestorm) genera la puerta NAND a partir de este código, y se mapea en los recursos de la FPGA (como un bloque lógico)

Sin embargo, a nivel físico, una puerta NAND se implementa a partir de la unión de varios transistores. La tecnología actual es CMOS

Icestudio nos permite crear nuestros propios bloques, con información en su interior, para poder documentar. Estos bloques de transistores no consumen recursos de la FPGA: sólo están ahí para aportar información. Si nos metemos dentro de ellos bajamos al siguiente nivel: los semiconductores

Los semiconductores, a su vez, están creados a partir de cristal de silicio, que se dopa para darle las propiedades de semiconductor

Y en el nivel más bajo tenemos los átomos de Sílicio, que se combinan para formar los cristales de silicio

Podemos meternos dentro del bloque del átomo, pero ya entramos en el terreno de la física de partículas :-) Nos encontramos con este bloque de texto

Recorriendo resumidamente estos niveles en orden inverso, partimos del átomo de Silicio (Nivel 1). Cada uno de ellos está unido a otros 4 átomos de Silicio, formando un tetraedro, y todos los tetraedros forman el cristal de Silicio (nivel 2). Sustituyendo algunos de estos átomos por otros, mediante un proceso que se llama dopar el silicio, aparecen dos tipos de semiconductores (Nivel 3) P y N, que al unirnos nos permiten implementar diodos y transistores (Nivel 4). Finalmente, uniendo transistores implementamos puertas lógicas (por ejemplo la NAND) y a partir de la NAND todas las demás (Nivel 5). Estamos en el nivel de la electrónica digital

Puerta NOT

La puerta más simple es la NOT: saca por su salida el negado de la entrada. Sólo tiene una entrada. Su tabla de verdad es:

a NOT
0 1
1 0

Y el circuito hola mundo de prueba es:

La ecuación de la puesta NOT es:

Si partimos de la ecuación de la puerta NAND y colocamos por sus dos entradas el mismo valor a, tenemos que:

obtenemos la ecuación de la NOT. Es decir, para tener una puerta NOT, hay que partir de una NAND e introducir el operando por sus dos entradas

Es lo que vemos si hacemos doble click en la puerta Not, y nos metemos dentro

Ya disponemos de la puerta NOT, que podemos usar para implementar el resto de puertas. ¡Logro desbloqueado!

Puerta AND

La puerta AND se activa cuando sus dos entradas están a 1. Su tabla de verdad es:

a b AND
0 0 0
0 1 0
1 0 0
1 1 1

y el circuito de pruebas:

La ecuación de la puerta AND es:

Se implementa a partir de una NAND y una puerta NOT:

Y ya hemos visto que la NOT también se implementa con puertas NAND, por lo que la AND también

Ya disponemos de la puerta AND, que podemos usar para la implementación de otras puertas y circuitos digitales. ¡Logro desbloqueado!

Puerta OR

La puerta OR activa su salida cuando alguna de sus puertas tiene un 1. Su tabla de verdad es:

a b OR
0 0 0
0 1 1
1 0 1
1 1 1

y el circuito de pruebas:

La ecuación de la OR es:

Partiendo de la ecuación de la OR y aplicacando algunas leyes del Algebra de Boole, tenemos:

que es igual a una NAND cuyos operandos de entrada están negados. Es lo que veremos si nos metemos dentro del bloque OR:

Y como la NOT también se puede expresar con puertas NAND, tenemos que la OR también se puede obtener sólo con puertas NAND

Ya disponemos de la puerta OR, que podemos usar para la implementación de otras puertas y circuitos digitales. ¡Logro desbloqueado!

Puerta XOR

La puerta XOR es también conocida como la operación de O-exclusivo. Su salida se pone a 1 cuando alguna de sus entradas está a 1, pero NO cuando están las dos a la vez. Su tabla de verdad es:

a b XOR
0 0 0
0 1 1
1 0 1
1 1 0

La puerta XOR se utiliza muchísimo para implementar operaciones aritméticas como la suma

El circuito de pruebas es:

La ecuación de la puerta OR es:

Y si la desarrollamos aplicando algunas leyes del Algebra de Boole llegamos a la expresión:

que nos indica que podemos implementar la puerta XOR con 3 puertas NAND y 2 NOT. Si hacemos doble click en la puerta XOR veremos su implementación

Y como las puertas NOT también se pueden implementar con puertas NAND, tenemos que la XOR se puede implementar con 5 NANDS

Ya disponemos de la puerta XOR, que podemos usar para la implementación de nuestros circuitos digitales. ¡Logro desbloqueado!

Puerta NOR

La puerta NOR es una OR negada. Tiene la característica de que sólo a partir de ella se pueden implementar el resto de puertas lógicas, igual que lo que ocurre con la NAND. Su tabla de verdad es:

a b NOR
0 0 1
0 1 1
1 0 1
1 1 0

La ecuación de la puerta NOR es:

Se puede implementar directamente con una OR y una NOT, ya que ambas ya han sido implementadas previamente con la NAND. Si nos metemos dentro de la NOR:

Ya disponemos de la puerta NOR, que podemos usar para la implementación de circuitos digitales. ¡Logro desbloqueado!

Multiplexores 2:1 (Mux 2:1)

Los multiplexores nos permiten seleccionar cuál de las entradas se saca por la salida. Los más básicos son los multiplexores 2 a 1, que tienen 2 entradas de datos, una de selección y una salida. Según el valor dado a su entrada de selección (Sel), por la salida saldrá una u otra de sus entradas

En este circuito se muestra un ejemplo. Se usa un multiplexor 2 a 1 para seleccionar cuál de los dos corazones emplear para hacer parpadear un led: el corazón de 1Hz o el de 4Hz. La selección se realiza mediante el pulsador SW1 de la Icezum Alhambra

La tabla de verdad simplificada de este multiplexor 2:1 es la siguiente:

Sel o
0 i0
1 i1

En los siguientes apartados veremos cómo se hace el multiplexor 2 a 1 a partir de puertas lógicas

Creando multiplexores 2:1 a partir de puertas lógicas

Aunque no es el objetivo hacer un curso de electrónica digital y Álgebra de boole, se mostrarán los pasos para la implementación del multiplexor con puertas lógicas. Son:

  1. Crear la tabla de verdad
  2. Obtener la ecuación booleana simplificada
  3. Crear el circuito a partir de la ecuación
  4. Implementar el circuito en Icestudio

Paso 1: Tabla de verdad del Mux 2:1

El Mux 2:1 tiene 3 entradas: Sel, i1, i0, y unn salida o. Primero creamos su tabla de verdad, dando valores a las 3 entradas para cubrir todos los casos:

Sel i1 i0 o
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1

Sabiendo cómo funciona el multiplexor, rellenamos las salidas. Siempre que Sel = 0, la salida será igual a la de i0. Cuando Sel = 1, la salida será igual a i1. Con esta información ya sabemos lo que se obtendrá en la salida en todos los casos

Sel i1 i0 o
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 0
1 1 0 1
1 1 1 1

Paso 2: Ecuación booleana simplificada

A partir de la tabla obtenemos la ecuación booleana simplificada. Esto se puede hacer por varios métodos. Uno es obteniendo la ecuación directamente y luego usando las reglas del álgebra de boole para simplificarla. La otra es usando el métido de Karnaugh. Usaremos el Primero

Nos fijamos en las filas cuya salida es 1. Vemos que hay en total 4. Esto significa que la función de salida tiene 4 términos, es decir, que la salida será: o = algo + algo + algo + algo

Ahora desarrollamos cada una de las filas, multiplicando las entradas. Cuando una entrada es 1 se pone la variable de entrada tal cual. Y si es 0, se pone su negada. Así, al desarrollar la fila 2, tenemos que Sel = 0, i1 = 0, i0 = 1, por lo que su desarrollo será

Repetimos para el resto de las 3 filas y obtenemos la ecuación:

Aplicamos las reglas del álgebra de Boole, que son muy parecidas a las que usamos en las matemáticas clásicas. Nos fijamos en los dos primero términos. Podemos sacar factor común a Sel negada, y en los dos últimos a Sel, quedando:

En el primer término sacamos factor común a i0, y en el segundo a i1, quedando:

Ahora aplicamos la regla del Algebra de Boole que dice que algo más su negado es siempre verdad, por lo que i0 + i0 negado es igual a 1. Y lo mismo con i1 + i1 negado. Nos queda:

Y por último, sabemos que cualquier cosa por 1, es cualquier cosa. Lo mismo en el Álgebra de Boole. La ecuación final nos queda:

Paso 3: Crear circuito a partir de la ecuación

Convertir la ecuación en circuito es muy fácil: el operador + es una puerta OR de dos entradas, mientras que el producto es una AND. Para la negación de Sel usamos una puerta NOT. El circuito final que define un multiplexor de 2 a 1 queda así:

Paso 4: Implementar el circuito en Icestudio

Por último implementamos este circuito en Icestudio. Si colocamos el multiplexor 2 a 1 y hacemos doble click en él, podremos ver sus tripas y aparecerá este circuito:

Multiplexores 2:1 de 2 bits (Buses)

El multiplexor 2:1 del apartado anterior funciona con entradas de 1 bit. También es posible usar multiplexores con entradas de varios bits (buses). Son muy útiles para seleccionar números. El más básico es el multiplexor 2:1 de 2 bits, que nos permite sacar por su salida cualquiera de los dos números de 2 bits de su entrada.

En este ejemplo se usa un mux 2:1 de buses de 2 bits para mostrar por los leds el número 1 ó 2, según si el botón SW1 está apretado o no

Creacion de un mux 2:1 de 2 bits

Construimos un mux de 2:1 de 2 bits usando un multiplexor 2:1 para cada uno de los bits individuales. En este caso necesitamos dos, uno para seleccionar el bit 0 (Mux 0) y el otro para el 1 (Mux 1)

Lo implementamos en Icestudio usando buses de 2 bits. Necesitamos los bloques split para separar el bus en sus dos cables, y el bloque join para volver a crear el bus de salida

Multiplexores 2:1 de N bits

Los multiplexores 2:1 de N bits se crean igual que los que hemos visto en el apartado anterior: hay que colocar un mux 2:1 por cada bit. Si las entradas tiene N bits, habrá que colocar N multiplexores 2:1

En este ejemplo se muestra un mux 2:1 de 4 bits, que saca por los leds los números 6 y 9 según el estado del pulsador sw1

Ejemplo: multiplexor 2:1 de 4 bits

Para hacer un multiplexor 2:1 de 4 bits utilizamos 4 multiplexores 2:1: mux0, mux1, mux2 y mux3. Cada uno selecciona uno de los dos bits de cada entrada: el mux0 selecciona entre los bits de menor peso, el mux1 entre los bits 1, el mux2 entre los bits 2 y finalmente el mux3 entre los dos bits de mayor peso

La entrada de selección entra en todos los multiplexores a la vez

La implementación en Icestudio es igual, pero hay que añadir los bloques de Split y Join para separar y agrupar los buses de 4 bits en cables

Multiplexores 4:1

Los siguientes multiplexores en complejidad son los de 4 a 1. Tienen 4 entradas de 1 bit, y mediante su entrada de selección de 2 bits se saca una por la salida

En este ejemplo se puede ver su funcionamiento. El led puede estar en 4 estados: apagado, encendido, parpadeo lento y parpadeo rápido. Con cada pulsación del pulsador SW1 se pasa al siguiente estado

Está implementado mediante un multiplexor de 4 a 1. Su entradas son las señales para el led: un 0 (apagado), un 1 (encendido), un corazón de un 1hz y otro de 4hz. La entrada de selección está conectada a un contador de 2 bits, que se incrementa con cada pulsación.

Cuando el contador es 0, está seleccionada la entrada i0, por la que llega un 0, y por tanto el LED0 está apagado. Cuando vale 1, se selecciona i1, que está conectad al bit constante 1, por lo que el led se enciende. Con 2 se selecciona i2, conectada al corazón de 1Hz, por lo que el led parpadea a 1Hz. Finalmente, cuando vale 3, se selecciona i3, que está conectada a un corazón de 4Hz, y el led parpadea más rápido

Creación de un multiplexor de 4:1

El multiplexor de 4 a 1 se podría implementar igual que el 2:1, a partir de las puertas lógicas. Pero es mucho más fácil hacerlo a partir de multiplexores 2:1 que ya hemos implementando antes con puertas lógicas. El circuito es el siguiente:

Las cuatro entradas se dividen en dos grupos, las dos de menor peso, i0 e i1, y las dos de mayor: i2 e i3. Cada grupo de lleva a un Mux 2:1 y ambos multiplexores se controlan con la misma señale de selección Sel0. La salida de estos multiplexores se introduce por un tercero, controlado por la señal Sel1, que selecciona el grupo. Cuando sel1 = 0 se selecciona el grupo con los bits de menor peso, y con Sel1 = 1 el grupo con las de mayor

Es fácil comprobar la tabla de verdad (reducida):

Sel1 Sel0 o
0 0 i0
0 1 i1
1 0 i2
1 1 i3

Mostraremos aquí sólo la comprobación para el caso Sel = 2 (Sel1 = 1, Sel0 = 0), pero es similar para los otros 3 casos

Se han marcado en rojo el estado de los multiplexores. Como Sel0 = 0, por las salidas de los dos primeros multiplexores sale lo que entra por su entrada 0. En el multiplexor final, como Sel1 = 1, por su salida se saca lo que viene por la entrada 1. De esta forma, hay un camino que va desde i2 hasta o (marcado en verde). Es la entrada i2 la que sale por la salida

Cuando implementamos este circuito en Icestudio queda así:

La única variación es la entrada Sel, que se usa una de bus de 2 bits (en vez de los dos bits sueltos). Mediante el bloque split se divide en sus dos cables

Creación de un multiplexor de 4:1 de 2 bits

Podemos tener multiplexores de 4:1 de datos de N bits. Se construyen usando N multiplexore 4:1 de 1 bit. En este apartado haremos uno sencillo: para datos de 2 bits

En este ejemplo usamos un multiplexor 4:1 de 2 bits para mostrar por los leds los números 0, 1, 2, 3. Cada vez que se pulse el botón se selecciona el siguiente número y se muestra en los leds

Para construir un mux 4:1 de 2 bits necesitaremos 2 multiplexores de 4:1 de 1 bit. El conexionado es el mostrado en la siguiente figura:

Y esta es su implementación en Icestudio:

Multiplexores N:1 de M bits

Con todo lo que hemos visto en estos apartados, ya podemos construir cualquier mutiplexor de N:1 (Siendo N una potencia de 2: 2, 4, 8, 16...) y de M bits de datos (Siendo M=1,2,3,4...)

Biestables

Partiremos del biestable D, que usaremos como bloque básico, y construiremos a partir de él otros biestables más avanzados (D con enable, T y T síncrono). Los biestables son elementos de memoria, que permiten almacenar 1 bit de información

Biestable D

Uno de los biestables más usados es el tipo D que simplemente almacena el bit que recibe por su entrada cuando llega un flanco de subida reloj. Se puede construir a partir de puertas lógicas, sin embargo aquí lo usaremos como bloque básico, a partir del cual constuiremos oros biestables y elementos de memoria

Para más información sobre cómo crear el biestable D desde puertas lógicas se puede consultar el ejemplo Archivo/Ejemplos/03.Puertas/07.Bietable D que viene en la colección default.

Este ejemplo está tomado del Apéndice A.8 del libro Computer organization and design. The hardware/software interface. Risc-V edition". Hennessy & Patterson. Ed. Morgan Kaufmann. 2018

En este ejemplo se muestra el biestable D genérico en acción. Es un biestable paramétrico, que está inicializado con el valor DINI que se pasa como parámetro. En este ejemplo es 1. Por la entrada se coloca un 0 constante. Su salida está conectada a un led, por lo que inicialmente este led estará encendido. Al apretar el botón se captura el 0 y el led se apaga

Este Biestable está implementando en Verilog. Si nos metemos dentro del bloque lo veremos

A la hora de usar los biestables es más cómodo tenerlos ya inicializadoa, bien a 1 o bien a 0, en vez de estar colocando un parámetro cada vez. Por ello, creamos los biestables D-0 y D-1, ya inicializados, a 0 y 1 respectivamente. Se muestra cómo ejemplo cómo se ha creado el D-0:

El parámetro ini está asignado al valor 0, y se ha activado la opción de Parámetro Local

En este ejemplo tenemos los dos biestables nuevos creados, D-0 y D-1 en acción. Uno conectado al pulsador SW1 y el otro a SW2. Al apretar SW1 se captura el 1 y se enciende el LED0. Al apretar SW2 se captura el 0 y se apaga el LED1

Biestables T

Los biestables T tiene una entrada de reloj. Cada vez que llega un flanco de subida cambian a su valor negado, pasando de 0 a 1 ó de 1 a 0

En este ejemplo vemos dos biestables T, con valores iniciales de 0 y 1. Están conectados a los pulsadores SW1 y SW2. Cada vez que apretamos el botón correspondiente, el led cambia de estado

Estos dos biestables, T-0 y T-1, están hechos a partir de un Biestable T genérico, al que se le pasa como parámetro el valor de la inicialización. La implementación del biestable T-1 es:

El biestable T genérico se construye a partir de un biestable D genérico, al que se le conecta un inversor (puerta NOT) a la salida que se vuelve a introducir por su entrada. De esta forma, cada vez que llega un flanco de reloj en el biestable D se captura su valor negado

Bietables D con enable

Las reglas de diseño síncrono nos dicen que hay que utilizar una única señal de reloj para todo el circuito. Cuando colocamos un pulsador en la entrada de reloj del biestable, estamos violando esta regla. En circuitos sencillo, no hay mayor problema. Pero cuando se hacen diseños más complejos, conviene no romper esta regla

Esto se consigue usando biestables D con entrada de enable. En este ejemplo se muestra el funcionamiento de esta biestable. Por su entrada de datos (d) se introduce un 1 constante. Por su entrada de reloj se conecta el reloj del sistema (para cumplir la primera regla del diseño síncrono). El pulsador se lleva a la entrada de enable (en). El dato se captura cuando la entrada de enable está a 1 (botón apretdo) y llega un pulso del reloj del sistema

El funcionamiento es el mismo que en el ejemplo original del biestable D, pero ahora se están cumpliendo las normas del diseño síncrono

Este biestable está creado a partir de un biestable D genérico con enable, que a su vez se implementa como se muestra en este circuito

Cuando el enable NO está activado (en = 0), el multiplexor selecciona el propio valor del biestable D, que se introduce de nuevo al llegar un flanco de reloj del sistema. Es decir, que con en = 0, el biestable NO cambia su valor. Permanece siempre en el mismo estado

Sin embargo, cuando en = 1, se selecciona la entrada d, que se captura por el biestable en el flanco de reloj

Biestable D con reset

Los biestables D también pueden tener una entrada de reset (rst). Hay dos tipos de reset, el síncrono y el asíncrono. El que más se usa es el síncrono: el biestble se inicializa cuando su entrada de rst esté activada y llegue un flanco de reloj

En este ejemplo se usa un biestable D con entrada de reset síncrona. El reloj está conectado al pulsador SW1. Su salida se saca a un led. Inicialmente el biestable está a 0, y el led apagado. Al apretar el pulsador, se captura el 1 de la entrada y se enciede el led. El botón SW2 está conectado a la entrada de reset. Al apretarlo, el led NO se apaga, porque es una entrada síncrona. Para apagarlo se tiene que apretar SW2 y luego SW1 para que llegue un flanco

Este biestable está implementado a partir de un biestable D genérico que tiene un multiplexor en su entrada. En su estado normal, cuando rst = 0, por la entrada llega la señal d. Pero cuando rst = 1, le llega el valor genérico de la inicialización (determinado por el parámetro INI)

Biestable D con reset y enable

Los dos biestables anteriores se pueden combinar, para tener uno con reset y entrada de enable. Cuando hay más de una entrada, se asigna prioridad a alguna de ellas para evitar las ambigüedades. ¿Qué pasa si se activan a la vez rst y enable? ¿Se hacer reset o se captura?. En nuestro biestable le daremos prioridad al reset, de forma que cuando rst = 1, se inicializa el biestable, con independencia del estado de la entrada de enable

El funcionamiento se muestra en este ejemplo. El pulsador SW1 está conectado a la entrada enable. Al apretarlo se captura el 1 de la entrada (en el flanco de reloj de la señal del sistema). El pulsador SW2 está conectado a la entrada de reset. Al apretarlo se inicializa el biestable y se apaga el led

Para su implementación se han utilizando dos multiplexores de 2:1. Uno selecciona entre el valor del biestable y el que viene por d, y el otro entre esta señal y la de reset. Como este segundo multiplexor está más cerca del biestable, es el que manda, y define la alta prioridad del reset. Cuando rst=1, se introduce el valor de inicialización en el biestable, con independencia de lo que haya pasado en el otro multiplexor.

Biestable D con set y reset

Otro biestable D similar al anterior es el que tiene las entradas set y reset. No tiene entrada de datos d. Almacena un 1 al activarse la señale set, y un 0 al activarse reset. El reset tiene prioridad sobre el set

Este es un circuito de ejemplo de su uso: se han conectado dos pulsadores, sw1 y sw2 conectados a sus entradas set y reset respectivamente. Inicialmente está a 0. Apretando los pulsadores se enciende o se apaga el led

Este biestable resulta muy útil para conectarlo a sensores de presensencia. Con set se conecta el sensor que indica que un objeto ha entrado en un recinto, y con reset el que detecta que ha salido

Se implementa utilizando dos multiplexores 2:1. El primero selecciona entre el valor del biestable y el 1, según el valor de set. El segundo entre la salida del primer mux y un 0, según el valor de reset

Biestable T síncrono

El biestable T síncrono es igual que el que vimos en los apartados anteriores, pero está pensado para que los circuitos cumplan con las normas del diseño síncrono. Por ello, además de la entrada para el reloj del sistema, tiene otra que es la que habilita el cambio

Su modo de funcionamiento es el mismo que ya conocemos. En este cirucito de ejemplo se muestra cómo hacer cambiar un led de estado al apretar el pulsador SW1

Se implementa a partir de un biestable D con enable y una puerta NOT. La salida del biestable d negada se vuelve a introducir por su entrada, y se captura cuando llega un pulso por enable y un flanco de subida en el reloj del sistema

Resumen de biestables

Aquí están recopilados todos los biestables de los apartados anteriores (solo se muestran los inicializados a 0). Están implementados a partir del biestable D básico

Registros

Los registros son elementos de memoria de N bits. Así, un registro de N bits, es un elemento que almacena números de N bits. Desde este punto de vista, un biestable en realidad se puede considerar como un registro de 1 bit, ya que sólo almacena 1 bit de información

Los registros se construyen a partir de la unión en paralelo de biestables de D.

Registros de 2 bits

El registro más sencillo es el de 2 bits, que nos permite almacenar un número de 2 bits. En este ejemplo se ha colocado un registro de 2 bits, a cuya entrada se ha puesto la constante 3 (11 en binario). Al apretar el pulsador SW1, el número se captura en el registro y se muestra en los leds

Registro básico de 2 bits

Este registro se construye con dos Biestables tipo D en paralelo, conectados a la misma señal de reloj. La entrada de datos d llega por un bus de 2 bits, que se desdobla con un bloque Split y se lleva a las entradas de ambos biestables. Sus salidas se vuelven a agrupar en otro bus de 2 bits con el bloque Join

Regístro de 2 bits con entrada load

El ejemplo anterior se ha mostrado para enseñar el funcionamiento del registro de 2 bits, sin embargo, no cumple las reglas del diseño síncrono: se ha conectado un pulsador a su entrada de reloj. Aunque en circuitos sencillos como este no hay mayor problema, conviene que en diseños más complejos se cumplan estas normas.

El circuito equivalente que cumple con estas normas es el siguiente:

El funcionamiento es el mismo: cuando se aprieta el pulsador, se captura el número 3 y se almacena en el registro, encendiéndose los dos leds. Ahora la entrada de reloj del registro está conectado al reloj del sistema, y el pulsador a la entrada load. Cuando se recibe un pulso por load y llega un flanco de subida en el reloj del sistema, se captura el dato

Este registro se construye de la misma forma que el básico, pero usando biestables D con entrada de enable. La señal de load se conecta a ambas entradas

Registro de 2 bits con entrada rst

Los registros también pueden tener una entrada de reset para inicializarse a 0. En este ejemplo se muestra su funcionamiento, aunque no se cumplen las reglas de diseño síncrono. Se muestra sólo como ejemplo de funcionamiento. Con el botón SW1 se captura el dato, y al apretar el sw2 y generar un flanco con sw1, el registro se inicializa a 0 y se apagan los leds

Se construye igual que el anterior, pero sustituyendo los biestables D por otros con entrada de rst

Registro de 2 bits con load y rst

Combinando las dos entradas tenemos el registro de dos bits con la entrada de load y reset síncrono. En este circuito de ejemplo se usa para capturar el valor 3 al apretar el pulsador SW1 y hacer reset al pulsar SW2. Cumple con las reglas de diseño síncrono

Se obtiene uniendo en paralelo dos biestables D con enable y reset:

Registro de 4 bits

Como segundo ejemplo veremos un registro de 4 bits, que almacena números de 4 bits. En este circuito se usa un registro de 4 bits con entrada de load y reset síncrono. Por la entrada se introduce la constante 15 (1111 en binario). Al apretar el pulsador sw1 se captura y se se encienden todos los leds. Al apretar SW2 se inicializa el registro a 0 y se apagan todos los leds

Este registro está formado por 4 biestables tipo D con entradas de enable y reset, colocados en paralelo

Cuando se crear registros de mayor numero de bits, el cableado se puede complicar, por ello, otra opción, es crearlos a partir de otros registros. El resultado es el mismo, y se consumen los mismos recursos, pero el diseño queda más claro

Así, el registro de 4 bits se puede crear colocando 2 registros de 2 bits en paralelo:

Las señales de reloj, load y rst se llevan a los dos registros. El bus de 4 bits se divide en 2 buses de 2 bits, cada uno se lleva a uno de los registros. Y sus buses de salida se agrupan nuevamente en otro de 4 bits.

Registro de N bits

Los registros de N bits almacenan números de N bits. Se puede construir bien colocando biestables D en paralelo, registros en paraleo o combionaciones de ambos. Por ejemplo, un registro de 21 bits se puede construir colocando en paralelo un registro de 16 bits, otro de 4 y un biestable. Esta opción es mejor que colocar 21 biestables D.

Realmente, la mejor forma de hacerlo es usando una descripción en Verilog, que nos permite hacer componentes paramétricos con muy poco código. Pero no es el objetivo de este taller

Operaciones aritméticas

A partir de puertas lógicas podemos crear circuitos digitales que hagan operaciones aritméticas. Veremos las más sencillas: sumas y restas

Sumador de 1 bit

Empezamos por lo más sencillo: un sumador de números de 1 bit. Es un circuito que tiene 2 entradas de 1 bit. Por cada entrada puede llegar 0 ó 1. En la siguiente tabla ponemos todas las sumas posibles, en decimal:

Tabla de sumas
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 2

La suma máxima es de 2, por lo que necesitamos 2 bits para representar la salida. Cuando se hace la suma de 1 + 1 en binario, el resultado es 10 (2 en binario). El 0 de la derecha es el resultado de la suma, y el 1 de la izquierda es el acarreo. Es lo que "nos tenemos que llevar"

El sumador de 1 bit tiene 2 entradas de datos de 1 bit (a y b), la salida de la suma (S) de 1 bit, y el acarreo (Co). Estle último se denota por Co (Carry out) que significa acarreo de salida

Este es el circuito de pruebas, donde las dos entradas de datos están conectadas a los pulsadores SW1 y SW2. La suma y el acarreo se sacan por los leds, por LED0 y LED1 respectivamente. En ellos podemos ver el resultado de la suma en binario

Inicialmente los leds están apagados, ya que se está haciendo la suma (0 + 0 = 0). Si apretamos sólo SW1, se encenderá LED0. Si apretamos sólo SW1. Estos casos se corresponden con las sumas 0 + 1 = 1 y 1 + 0 = 1. Finalmente, si apretamos los dos pulsadores a la vez, se encenderá LED1 y LED0 estará apagado. Se corresponde con la suma en binario ( 1 + 1 = 10)

Diseñaremos este circuito haciendo los pasos clásicos:

  1. Tabla de verdad
  2. Obtención de las ecuaciones de las salidas
  3. Implemententación con puertas lógicas
  4. Bloque en Icestudio

La tabla de verdad la obtenemos poniendo en binario la tabla de sumar:

a b Co S
0 0 0 0
0 1 0 1
1 0 0 1
1 1 1 0

Las ecuaciones de Co y S las obtenemos a simple vista, ya que viendo la tabla de verdad podemos reconocer las operaciones AND para Co y XOR para S. Por tanto, las ecuaciones son:

Y la implementación en bloques de icestudio es:

Sumador de 1 bit con acarreo de entrada

El sumador anterior en realidad no nos sirve de mucho. Necesitamos crear uno que podamos **** para construir sumadores de números de más de 1 bit. Esto lo logramos haciendo un sumador de 1 bit con acarreo de entrada

Este sumador es igual que el anterior, pero con una entrada más: Ci, el acarreo de entrada que llega de la etapa anterior. La suma que se realiza es de 3 operandos de 1 bit: a + b + Ci

El circuito de pruebas es el siguiente:

Por la entrada Ci se deja un 1 fijo, para probar. Las dos entradas de datos se conectan a los pulsadores, y las salidas Co y S a los leds LED1 y LED0 respectivamente, igual que en el ejemplo del apartado anterior

Inicialmente el LED0 está encendido, ya que se está sumando (0 + 0 + 1). Al apretar sólo el pulsador SW1, LED0 se apaga y LED1 se enciende, ya que la suma es 2 (0 + 1 + 1). Lo mismo si se pulsa sólo SW2. Al apretar los dos pulsadores se encienden los dos leds, correspondiente al número 3 (1 + 1 + 1)

La tabla de verdad de este sumador es:

Ci a b Co S
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 1 0
1 1 1 1 1

Vamos a obtener las ecuaciones de S y Co. Nos será de utilizar conocer la ecuación de la XOR negada.

que se obtiene bien desarrollando su tabla de verdad, o bien aplicando el Álgebra de Boole a la expresión de la XOR negada:

Para obtener la ecuación de S nos fijamos en su tabla de verdad. Como se pone cuatro veces a 1, será la suma de 4 términos. Los desarrollamos:

S se obtiene mediante la operación XOR de Ci, a y b. Para la obtención de Co hacemos lo mismo: desarrollamos la tabla de verdad. Tiene también 4 valores a 1, por lo que será la suma de 4 términos:

A partir de las ecuaciones de S y Co obtenemos el circuito con puertas lógicas:

Si nos fijamos en el circuito, está formado for dos sumadores de 1 bit sin accareo de entrada (apartado anterior) y una puerta OR. En Icestudio lo implementamos con los sumadores creados anteriormente:

Sumador de 2 bits

A partir del sumador de 1 bit con acarreo de entrada, podemos construir sumadores de números de mayor número de bits. Vamos a construir uno de 2 bits, con dos entradas de 2 bits (Buses), y una salida de 2 bits (bus) más el acarreo

El circuito de ejemplo es el siguiente:

Por una entrada introducimos la constante 3 y por la otra 2, para calcular la suma 3 + 2 = 5. Como este número no cabe en 2 bits (que es la salida), se activa el acarreo de salida, que se saca por LED2. La suma se saca por LED1 y LED0

Al cargar este circuito en la placa, vemos el número 101 en los leds, que es 5 (LEDS 2 y 0 encendidos, 1 apagado)

La forma de crearlo es a partir de dos suamdores de 1 bits, con acarreos de entrada. El acarreo de salida del primer sumador se introduce por el acarreo de entrada del segundo. Por el acarreo de entrada del primer sumador ponemos un 0. Los dos buses de entrada se separan en dos cables cada uno. Los de menor peso se llevan al sumador inicial, en la parte inferior, y los dos de mayor peso al sumador superior. El acarreo de salida del sumador 2 es el acarreo final del sumador de 2 bits. Los bits de salida de los dos sumadores se agrupan en un bus de 2 bits

Sumador de 2 bits con acarreo de entrada

También se puede hacer la versión de sumador de 2 bits con un accareo de entrada, para poder encadenarlos con otros sumadores. El circuito de pruebas es:

Se suman las constantes 3 y 2 mas el acarreo de entrada que se introduce por el pulsador SW1. Inicialmente por los leds de salida sale el resultados 5 (3 + 2 + 0). Al apretar el pulsador se obtiene 6 (3 + 2 + 1)

Está implementando de la misma forma que el anterior, pero en vez de introducir 0 por el acarreo de entrada (Ci), se saca al exterior, como una entrada adicional

Sumador de 4 bits

El sumador de 4 bits es igual al de 2 bits. Se pone como ejemplo de generalización. Cualquier sumador de N bits tendrá esta pinta. Tiene dos entradas de datos de 4 bits, y una de acarreo de entrada (Ci). El resultado de la suma se saca por una salida de 4 bits (S) junto al acarreo de salida (Co)

Un circuito de ejemplo es este:

Se realiza la suma de 15 + 15 = 30, cuando el acarreo de entrada es 0 (Pulsador SW1 no apretado). 30 en binario es 11110, por lo que se encenderán los LEDS 1,2,3 Y 4, y el 0 estará apagado:

Si se aprieta el pulsador SW1, se obtiene 15 + 15 + 1 = 31, que en binario es 11111. Todos los LEDs del 0 al 4 estarán encendidos

El sumador de 4 bits se construye a partir de la unión en cadena de dos sumadores de 2 bits:

El sumador inferior realiza la suma de los bits menos significativos de los datos de entrada, junto al acarreo de entrada. Su acarreo de salida está conectado al sumador superior, que suma los 2 bits más significativos

Los datos entran por dos buses de 4 bits, que se dividen en dos sub-buses de 2 bits a través de los bloques split. Los dos buses de 2 bits de salida se unen a través del bloque join para formar el bus final de 4 bits de salida, con el resultado de la suma. El acarreo de salida del sumador superior es el que contiene el acarreo total de la suma y se saca directamente hacia fuera del sumador

Esta es la versión del sumador de 4 bits sin acarreo de entrada. Está hecho a partir de la versión anterior poniendo 0 en Cin.

Se realiza la suma 14 + 15 = 27 (11011 en binario), y se saca por los leds

Sumador de 8 bits

Los números de 8 bits son un estándar en el mundo de los microprocesadores. Este circuito de prueba con un sumador de 8 bits realiza la suma 113 + 131 = 244 (11110100 en binario) y se muestra el resultado por los leds. Se le suma el acarreo de entrada que se introduce por el pulsador SW1

Al cargarlo en la Icezum Alhambra, se podrá ver el número 244 en binario (11110100) en los leds:

El sumador está construido a partir de 2 sumadores de 4 bits:

Sumador de 8 bits y el puerto serie

Para probar el sumador se puede utilizar el puerto serie para enviar los datos de 8 bits y visualizar en el terminal los resultados de la suma

Este es un circuito de prueba que suma 1 al dato recibido desde el ordendor y envía de vuelta el resultado, de forma que lo podemos ver en el terminal de comunicaciones

El dato se recibe en serie por el pin RX, y la unidad de recepción serie lo convierte a paralelo y lo saca por el bus de 8 bits. Este dato lleva al sumador para sumarle la constante 1, además de visualizarse por los 8 leds. El resultado se lleva al transmisor serie que lo envía de vuelta al PC

Desde el ScriptCommunicator enviamos datos de prueba, por ejemplo los números 1, 2 y 3. En la pestana Dec vemos en decimal tanto los datos enviados (1,2,3) como los recibidos: 2, 3 y 4. Comprobamos que ha sumado 1 a cada uno de ellos

Circuito generador de la secuencia de Fibonacci

Como ejemplo de aplicación del sumador, vamos a hacer un circuito que calcule los números de la sucesión de Fibonacci. Los primeros números de esta serie son: 0, 1, 1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ... El siguiente sería 377 pero ya no se puede representar en 8 bits

El circuito que los calcula es este:

Hay dos registros de 8 bits. El de la izquierda está inicializado a 1, y el de la derecha a 0. La salida del primero está conectada a la entrada del segundo, de forma que todo lo que se almacena en él, en el pulso siguiente estará almacenado en el de la derecha

El registro de la derecha contiene el número de fibonacci actual, y el otro registro el siguiente. Es decir, almacenan los dos últimos números de fibonacci, que inicialmente son 1 y 0. A partir de ellos se van calculando los siguientes, que no son más que la suma de estos dos. Ambos registros se llevan al sumador y su salida se conecta a la entrada del registro izquierdo. De esta manera, cada vez que llega un pulso por load, en este registro se almacena la suma de los dos anteriores, que es el siguiente término de fibonacci

El número actual se muestra en binario por los leds de la icezum Alhambra, como se muestra en esta animación:

y también se envía por el puerto serie para ver el resultado en el terminal de comunicaciones, en decimal, y comprobar que la sucesión es correcta:

Operación de incremento

La operación de incrementar en una unidad se utiliza mucho, por ello es interesante tenerla en su propio circuito. La usaremos para obtener el complemento a 2 de un número (pasarlo a negativo) y para implementar los contadores ascendentes

Se implementa muy fácilmente a partir de un sumador y la constante de bus 1

Incremento para números de 2 bits

Empezamos creando el incrementador para números de 2 bits. Este es el circuito de prueba, que realiza la operación 1 + 1 = 2 :-)

Y en este gif animado se puede ver cómo se ha creado:

Su implementación se realiza mediante un sumador de 2 bits y la constante 1 de 2 bits, en los que se ignoran tanto el acarreo de entrada como el de salida

Incremento para números de N bits

En general, hacer un incrementador para números de N bits sólo tenemos que tener creado el sumador de N bits al que le introducimos la constante 1 de N bits por una de sus entradas

Particularizando para N=4, un circuito de ejemplo sería así:

En el que se está haciendo la suma 7 + 1 = 8. La implementación de este incrementador de 4 bits es:

Restador de 4 bits

Los circuitos para restar son los mismos que para sumar. Así, la operación con números de 4 bits 4 - 1 es en realidad 4 + (-1). La magia no está en el circuito que hace la operación, sino en cómo se representan los números negativos para que se pueda utilizar la misma operación de suma

Este es un circuito de ejemplo que usa un sumador de 4bits, el mismo que hemos usado hasta ahora, para realizar la operación 4 + (-1) = 3

Al cargarlo en la placa veremos los LEDs 1 y 0 encendedidos, ya que el resultado es 0011

El convenio usado para la representación de los números negativos se llama complemento a 2. Para el caso de números de 4 bits, la tabla de números positivos y negativos es:

Observamos que todos los números negativos tiene su bit de mayor peso a 1 (es la forma de saber si un número es negativo o no). Todos los positivos este bit a 0. Se denomina bit de signo

Para obtener un número negativo (en complemento a dos), hay que hacer la siguinte operación: negar todos sus bits y sumarle 1. Así, para obtener -1 en binario, partimos del 1 en binario (de 4 bits): 0001, negamos todos su bits: 1110, y sumamos uno: 1110 + 1 = 1111.

El complemento a 2 nos permite hacer restas usando la misma circuitería que para las sumas. Simplemente hay que representar los números negativos en complemento a dos. Así, para calcular 4 - 1 hacemos: 0100 + 1111 = 0011 (el acarreo de salida final lo ignoramos)

Es muy importante darnos cuenta de que la interpretación la ponemos nosotros. Si nos preguntan, ¿qué números estamos sumando aquí: 0100 + 1111? La respuesta es "depende". Si lo interpretamos como números enteros sin signo, se refiere a la suma 4 + 15. Si la interpretamos como números con signo, se refiere a la operación 4 - 1. En ambos casos, el circuito hardware para hacer la operación es el mismo :-)

Cuando trabajamos con número de 4 bits, los rangos son:

Interpretación Rango
Enteros positivos [ 0, 15 ]
Enteros con signo [ -8, 7 ]

Restador de 8 bits

Como otro ejemplo más se muestra aquí un restador de 8 bits, que igual que ocurria con el de 4 bits, se implementa con un sumador de 8 bits, pero introduciendo el dato a restar en complemento a 2. Se realiza la operación 64 - 1 = 63, que en binario es (00111111). Se endencerán todos los leds salvo el LED7 y el LED6

Cuando trabajamos con números de 8 bits, los rangos son:

Interpretación Rango
Enteros positivos [ 0, 255 ]
Enteros con signo [ -128, 127 ]

Lo bueno de trabajar con números de 8 bits es que los podemos enviar por el puerto serie para comprobar los resultados de las operaciones con números negativos. En el ScriptCommunicator tenemos que configurar la pestaña DEC para que muestre los números enteros con signo. Esto se hace marcando int8 en el desplegable de la pestaña Console Option en la ventana de Settings

Ahora probamos este circuito de pruebas que realiza la suma de dos números negativos: -2 + (-1) = -3. El resultado se envía al PC cuando se aprieta el pulsador SW1

Desde la pesaña DEC del ScriptCommunicator podemos ver que el resultado es correcto: -3

En este otro circuito hacemos la prueba con un número positivo al que le restamos otro mayor, y el resultado debe salir negativo: 50 - 100 = -50

y lo comprobamos con el Scriptcommunicator

Paso a negativo: Complemento a 2

Para representar un número en complemento a dos hay que invertir sus bits y sumarle uno. Crearemos un bloque para realizar esta operción, a partir de los bloques anteriores

Complemento a 2 de números de 4 bits

Es es un circuito de ejemplo para calcular el complemento a 2 del número 1, y obtener -1, que se saca por los leds

Al cargarlo en la Icezum Alhambra los 4 leds se encenderán. El bloque que calcula el complemento a 2 (COM) está formado por dos elementos: una puerta not de bus y un incrementador para sumar 1:

La puerta NOT de bus está formada por 4 inversores, cada uno aplicado a uno de los cables del bus de 4 bits:

Para restar un número podemos usar directamente la constante en complemento a 2, como hemos hecho en los apartados anteriores, o utilizar el bloque de complemento a dos, como se hace en este ejemplo que calcula 4 - 1

Por la salida se obtiene 3, y se encienden los LEDS 1 y 0

Complemento a 2 de números de 8 bits

El bloque para complementar a 2 se puede hacer para números de cualquier tamaño de bits, por ejemplo 8. En este circuito de prueba se realiza la operación 64 - 1 que se saca por los leds (Se encienden todos salvo el 6 y 7) y además se envía por el puerto serie para ver el resultado, al apretar el pulsador SW1:

En el ScriptCommunicator veremos el resultado: 63

El bloque de complemento a 2 de 8 bits se hace exactamente igual que el de 4, pero usando componentes de buses de 8 bits

y la puerta NOT de bus de 8 se hace a partir de 2 puertas nots de bus de 4 bits

Operación de decremento

Al igual que hicimos con la operación de incrementar, crearemos un bloque para decrementar números de 8 bits en una unidad. Este es el circuito de ejemplo que calcula 64 - 1 = 63, y muestra el resultado por los leds (todos encendidos salvo el 6 y 7)

El decrementador está formado por un sumador de 8 bits y la constante -1

Para hacer decrementadores de números de N bits, sólo hay que sustituir en el diseño el bloque suma y la constante de 8 bits por otros de N bits

Comparadores

Los comparadores son circuitos que nos indican la relación entre dos números. Nos permiten saber si son igules, o si uno es mayor que otro. A partir de los operandos de igualdad (=) y mayor que (<) se pueden construir los demas: mayor o igual (>=), distinto (!=), menor que (<) y menor o igual que (<=)

La operación de igualdad es conmutativa, por lo que el resultado es el mismo si introducimos los números por diferentes entradas. Sin embargo la operación mayor que (>) NO es conmutativa. Hay que introducir los números por las entradas en el orden correcto

Los bloques de comparación que crearemos son estos:

Comparadores de 1 bit

Empezamos por lo más sencillo: comparadores de números de 1 bit

Igualdad

En el siguiente circuito de ejemplo vemos el comparador de igualdad en acción. Como entrada se introducen los dos pulsadores de la icezum alhambra: SW1 y SW2. El resultado de la comparación se muestra por el LED0

Inicialmente el led está encendido porque los dos pulsadores están a 0. Si apretamos uno de ellos, dejarán de ser iguales, y el led se apagará. Si apretamos los dos a la vez, ambos estará a 1 y el led se encenderá

Para el diseño del circuito partimos de la tabla de verdad

a b =
0 0 1
0 1 0
1 0 0
1 1 1

Podemos desarrollar las ecuaciones booleanas directamente a partir de esta tabla, sin embargo nuestros ojos ya están entrenados y nos damos cuenta de que se corresponde con la tabla de verdad de la puerta XOR negada, así que la ecuación es:

y la implementación del comparador de igualdad es

Mayor que

Circuito de prueba en acción:

Las entradas del bloque mayor que están etiquetadas con "a" y "b", a diferencia del bloque de igualdad. Esto es debido a que la operación mayor que NO es conmutativa y el orden por el que se introduzcan los operandos de entrada es MUY IMPORTANTE

Inicialmente el LED0 está apagado, ya que los dos pulsadores valen 0. Al apretar SW1, tenemos que SW1=1, SW2=0, por lo que SW1 > SW2 y se enciende el led. En el resto de caso permanecerá apagado

La tabla de verdad es la siguiente:

a b >
0 0 0
0 1 0
1 0 1
1 1 0

Sólo hay un caso en el que la salida es 1, cuando a está a 1 y b está a 0. En el resto de casos no se cumple la relación >

Obtenemos la ecuación booleana:

Por tanto, la implementación del bloque de mayor que se puede hacer con una puerta NOT y una AND:

Mayor o igual que

Circuito de prueba:

Es una operación NO CONMUTATIVA, por eso las entradas al circuito están etiquetadas con "a" y "b"

Inicialmente el LED0 está encendido, ya que SW1=SW2. Si se aprieta el pulsador SW1, permanecerá encendido, dado que SW1 = 1, SW2 = 0 y se cumple que SW1 > SW2. También si se aprietan ambos a la vez, SW1 = 1, SW2 = 1 (SW1 = SW2). En el caso de que sólo se apriete SW2, el led se apaga, ya que SW1 = 0, SW2 = 1 y no se cumple que SW1 >= SW2

la tabla de verdad es:

a b >=
0 0 1
0 1 0
1 0 1
1 1 1

Sin embargo, el circuito lo crearemos a partir de los bloques = y >, dado que la condición >= se cumple cuando se cumpla > o =

Distintos

Circuito de pruebas:

El LED0 se encenderá cuando los pulsadores están en diferentes estados (uno pulsado y el otro no). Inicialmente el LED0 está apagado porque SW1=SW2=0. Si apretamos cualquiera de los dos, se cumplirá que son diferentes y el led se encenderá. Si se aprietan ambos a la vez se apagará

Es una operación CONMUTATIVA. Da igual el orden de las entradas

La tabla de verdad es:

a b Distintos
0 0 0
0 1 1
1 0 1
1 1 0

Esta operacion se corresponde con una puerta XOR. Sin embargo, la implementaremos a partir de la negación de la operación de igualdad

Menor que

Circuito de pruebas

El LED0 se encenderá sólo cuando SW2 esté apretado, ya es el único caso en que SW1=0, SW2=1 y por tanto SW1 < SW2

Es una operación NO CONMUTATIVA

La tabla de verdad es:

a b <
0 0 0
0 1 1
1 0 0
1 1 0

La implementaremos a partir del bloque mayor que, dado que a < b es equivalente a b > a. Es decir, que la operación menor que la implementamos a partir de la operación mayor que pero cambiando el orden de las entradas

Menor o igual que

Cicuito de pruebas

Es una operación NO CONMUTATIVA

El LED0 sólo se apagará cuando se apriete SW1, ya que es el único caso en el que SW1 es estrictamente mayor que SW2 y por tanto no se cumple la condición de SW1<=SW2

a b <=
0 0 1
0 1 1
1 0 0
1 1 1

Este bloque se implementa a partir del bloque mayor o igual que, ya que a<=b es equivalente a b>=a. Sólo hay que cambiar el orden de las entradas

Comparadores de 2 bits

Los bloques de igualdad y mayor que para números de 2 bits los obtendremos a partir de los mismos bloques que ya tenemos para números de 1 bit. Y el resto de bloques: mayor o igual que, distintos, menor que, menor o igual que para números de 2 bits los crearemos igual que en el apartado anterior, a partir de los bloques de igualdad y mayor que de 2 bits

Vamos a usar la tabla de verdad como guía, y para comprobar en los siguientes apartados que nuestra intuición es correcta

a1 a0 b1 b0 = >
0 0 0 0 1 0
0 0 0 1 0 0
0 0 1 0 0 0
0 0 1 1 0 0
0 1 0 0 0 1
0 1 0 1 1 0
0 1 1 0 0 0
0 1 1 1 0 0
1 0 0 0 0 1
1 0 0 1 0 1
1 0 1 0 1 0
1 0 1 1 0 0
1 1 0 0 0 1
1 1 0 1 0 1
1 1 1 0 0 1
1 1 1 1 1 0

Igualdad de números de 2 bits

Comenzamos con un circuito de pruebas del comparador de números de 2 bits

Se usa un multiplexor de 2 bits para seleccionar entre los números 1 y 2 para realizar las comparaciones 2 = 1, y 2 = 2. Inicialmente el LED0 estará apagado porque al no estar apretado SW1, el número seleccionado es 1, y la comparación que se hace es 2 = 1, que no se cumple. Al apretar SW1, se selecciona el 2 y se hace la comparación 2 = 2 que sí se cumple, encendiéndose el LED

Para implementar el circuito utilizaremos la definición de igualdad entre números de 2 bits: "Los números de 2 bits a (a1,a0) y b (b1, b0) son iguales si sus bits más significativos son iguales (a1=b1) y sus bits de menor peso también (a0=b0)". Esto es justo lo que está representado en la tabla de verdad. Sin embargo, en vez de deducir las ecuaciones booleanas de la tabla, aplicamos la definición y obtenemos su implementación

Usamos dos comparadores de igualdad de 1 bit. El de arriba realiza la comparación entre los bits de mayor peso de los números (a1 y b1) y el inferior de los de menor peso (a0 y a1). El resultado de estas comparaciones se lleva a una puerta AND, ya que sólo se cumple la igualdad si ambas condiciones son correctas

Aunque no es necesario, vamos a hacer una comprobación analítica, a partir de las ecuaciones booleanas. Al implementar este circuito en lógica tradicional, es necesario emplear las ecuaciones boobleanas para asegurarse de que se obtiene la expresión más reducida posible, y usar así el menor número posible de puertas. Sin embargo, al trabajar con FPGAs, el sintetizador ya realiza esta labor por nosotros: simplifica la lógica para que ocupe los mínimos recursos. Por ello, lo importante es centrarse en crear circuitos correctos, pero no hay que prestar demasiada atención a la optimización. No obstante, obtendremos las ecuaciones a de la tabla de verdad

Al final obtenemos lo mismo que nos decía el sentido común: la función de igualdad es la AND entre las funciones de igualdad de a1 y b1, y a0 y b0

Mayor que, para números de 2 bits

Este es un circuito de pruebas, similar al del apartado anterior

Se hace la comparación 2 > 1, por lo que el LED0 se enciende. Al apretar SW1, se hace 2 > 3, que no se cumple, por lo que el led se apaga

La implementación del circuito la haremos también usando la intuición. Para saber si un número de 2 bits es mayor que otro, primero nos fijamos en su bit más significativo. Comparamos ambos bits (comparación de 1 bit). Si son diferentes sabremos si se cumple que uno es mayor que otro. Pero si estos bits son iguales, entonces hay que mirar el bit de menor peso. Si son diferentes, sabemos que uno es mayor que otro, y si no, sabemos que no se cumple esta condición

Por ello, escrito verbalmente, el circuito mayor que entre los números a (a1,a0) y b (b1,b0) queda definido por: "a será mayor que b si bien a1 es mayor que b1 o bien, siendo a1=b1, que a0 sea mayor que b0". Esto lo podemos resumir en esta ecuación:

que se implementa con los comparadores de 1 bit de esta manera

Usando los bloques split, obtenemos los dos cables de cada bus (a1,a0,b1 y b0). El bloque superior hace la comparación entre los bits más significativos (a1 y b1). Esta es una de las condiciones. Como sale al exterior por una puerta OR, si esta condición se cumple, se cumple que a > b. Por el otro lado de la OR se comprueba la otra condición: que a1=b1 y a0 mayor que b0, usándose una puerta AND entre el bloque de igualdad y mayor que de 1 bit.

También se puede obtener la ecuación directamente a través de la tabla de verdad, tal y como hacemos en el siguiente desarrollo:

que es la misma ecuación que habíamos obtenido por "intuición"

Comparadores de N bits

En general, para números de N bits podemos crear los comparadores basándonos en comparadores de numeros de menor número de bits

Como ejemplo, crearemos los comparadores para N=4 bits

Comparador de igualdad para N bits

Dados los números a y b de N bits, sabemos que serán iguales si todos los bits con mismo peso son iguales, es decir, si ai = bi con i entre 0 y N-1

Como ejemplo construiremos uno de 4 bits, cuyo circuito de pruebas es este

Inicialmente se realiza la comparación 7 = 7, por lo que el LED0 se enciende. Al apretar el pulsador se hace 8 = 7, y el led se apaga

La implementación está hecha a partir de dos comparadores de igualdad de 2 bits, puestos en paralelo

Comparador de mayor que para N bits

Dados los números a y b de N bits, sabemos que a será mayor que b si se cumple alguna de estas condiciones:

  • que el bit de mayor peso de a sea mayor que el de mayor peso de b
  • o que los bits de mayor peso de a y b sean iguales, pero en el siguiente en peso, el de a sea mayor que el de b
  • o que los dos bits de mayor peso sean iguales en a y b, pero en el tercero el de a sea mayor que el de b
  • o que los tres bits de mayor peso sean iguales, pero en el cuarto sea mayor el de 4...
    ...
  • o que los N-1 bits de mayor peso de a y b sean iguales, pero el de menor peso de a sea mayor que el de b

Podemos escribir esto en forma de ecuación para que yo haya ambigüedades

Haremos un ejemplo para N=4. Este es el circuito de prueba

Inicialmente se realiza la comparación 7 > 6, y el LED0 se enciende. Al apretar SW1, se hace 7 > 8, y el led se apaga

El comparador de 4 bits está formado a partir de 3 comparadores de 2 bits. Uno de igualdad y otro mayor que

Contadores

Los contadores son componentes muy importantes en los circuitos digitales. Los usamos para medir el tiempo, generar señales de diferentes frecuencias, recorrer memorias, generar secuencias, contar pulsos... se usan en prácticamente todos los periféricos: controladores de servos, generadores de pwm, unidades de comunicaciones, temporizadores, etc, y todos los microprocesadores llevan uno para leer las instrucciones de memoria: el contador de programa

Al igual que los registros, los contadores son de N bits, y funcionan con el flanco de subida (o bajada) del reloj. Al llegar el flanco, actualizan su valor

Según cómo realizan la cuenta, hay tres tipos de contadores: ascendentes, descendentes y ascendentes/descendentes. Según el tipo de cuenta, pueden ser naturales o módulo M. Los primeros cuentan hasta llegar al número máximo según los bits (2 elevano a N, menos 1). Los segundo realizan la cuenta de 0 hasta M-1

Todas estas variadades, además, según el tipo de entradas que tengan pueden ser básicos, con reset síncrono, con entrada de cuenta o ambas

Contadores ascendentes de 4 bits

Describiremos cuatro tipos de contadores ascendentes: contador básico, básico con entrada de reset síncrona, con entrada de cuenta, y con entrada de cuenta y reset síncrono:

Contador básico

Empezaremos con un contador básico: uno de 4 bits, que inicialmente tiene almacenado el valor 0 y se incrementa en cada flanco de subida de la entrada de reloj

Este es un circuito de prueba que muestra una cuenta en binario en 4 leds de la Icezum Alhambra. El contador se incrementa en cada segundo

La entrada de reloj está conectada a un corazón de 1Hz (1 pulso/segundo) de manera que se incrementa cada segundo

El contador de 4 bits se construye a partir de un registro de 4 bits, que almacena la cuenta actual. Inicialmente tiene el valor 0. Su salida se pasa por un bloque de incremento, de forma que por su entrada se tiene siempre el siguiente valor incrementando. Al llegar el pulso de reloj, se captura el nuevo valor en el registro. La salida de este registro es la que se saca hacia el exterior: contiene el valor actual de la cuenta

Contador con entrada de reset síncrono

Igual que en los registros, los contadores pueden tener una entrada de reset síncrono. Cuando esta entrada se pone a 1 y llega un flanco de reloj, se inicializan a 0. Mientras que rst esté activado, el contador no cuenta. Este es un circuito de prueba:

Se implementa igual que el contador básico, pero usando un registro de 4 bits con entrada de reset

Contador con entrada de cuenta

Los ejemplos mostrados anteriormente NO cumplen las reglas del diseño síncrono, donde sólo puede haber una única señal de reloj. La señal que sale del corazón se introduce por la entrada de reloj del contador, y esto viola la norma. Para circuitos simples no hay mayor problema, sin embargo para diseños más complejos hay que respetar esta norma. Para ello se utilizan contadores con entrada de cuenta (cnt). El contador se incrementa cuando la señal de cuenta está a 1 y llega un pulso de reloj. Este es el circuito de ejemplo:

Ahora la señal de 1Hz del corazón se introduce por la entrada cnt del contador, y se cumplen las reglas del diseño síncrono. El funcionamiento del circuito es similar al del contador básico. La única diferencia es que la señal que entre por cnt debe ser un pulso de anchura igual a la del reloj del sistema, ya que sino el contador se incrementará en más de 1 unidad (si el pulso tiene una anchura de 4 ciclos de reloj, el contador se incrementará 4 veces)

Es contador se implementa con un registro con entrada de load, al que se le conecta la entrada de cuenta. Cada vez que se recibe un pulso por cnt, y llega un flanco de reloj, el registro se carga con el nuevo valor incrementado

Contador con entrada de cuenta y de reset

Y podemos combinar la entrada de cuenta y la de reset. Este es el circuito de ejemplo

Es un contador manual, que cuenta las veces que se aprieta el pulsador SW1. Al apretar SW2 se hace un reset y se vuelve a 0

El contador se implementa igaul que los anteriores, pero usando un registro de 4 bits con entrada de load y reset

Contador descendente de 4 bits

Los contadores descendentes son iguales que los ascendentes, pero realizan la cuenta hacia atrás, comenzando también por 0. Tenemos las mismos 4 tipos, pero sólo mostraremos el contador descendente con entrada de cuenta

Se implementa igual que el ascendente, pero ahora usando un decrementador en vez de un incrementador

Contador ascendente/descendete de 4 bits

Ambos tipos de contadores: ascendentes y descendentes, se pueden combinar en uno que haga las dos operaciones según el valor de su entrada down. Cuando down=1, es descendete, y cuando down=0 es ascendente. Este es el circuito de ejemplo:

El contador empieza desde 0, contando hacia arriba. Al apretar el pulsador SW1, se cambia a modo descendente. El modo actual se muestra por el LED7: 0 es ascendente y 1 descendente

Se implementa con un sumador de 4 bits, en el que por un lado se introduce la salida del registro y por el otro un dato de 4 bits que viene de un multiplexor, y que puede ser -1 ó 1 según lo que esté seleccionado. Cuando se selecciona su entrada 0, se envía el 1 por lo que se incrementa el valor actual. Cuando se selecciona la entrada 1, se envía -1 y se decrementa. Esta pata de selección es la entrada down contador

Contador módulo M de 4 bits

Los contadores de N bits cuentan entre 0 y 2^N -1. Los contadores módulo M lo hacen entre 0 y M-1. Son muy útiles para generar señales de cualquier frecuencia, entre otras cosas. Por ejemplo, un contador de 4bits realiza la cuenta entre 0 y 15. Un contador módulo 10 cuenta entre 0 y 9

Además de la salida con la cuenta, tiene una salida de 1 bit que indica que han llegado hasta el tope (M-1), y que vuelve a comenzar desde 0

Este es un circuito de pruebas, de un contador módulo 10, con entrada de cuenta

Se usa un corazón de 1Hz, por lo que la cuenta se actualiza cada segundo. Cuenta de 0 a 9. En el décimo segundo vuelve a 0

El contador módulo M de 4 bits está implementado a partir de un contador de 4, con reset síncrono cuya salida se compara con el número M. Si son iguales, se activa la señal de reset del contador para que vuelva a 0.

Corazón de 1Hz

TODO

Descargas

Fichero Descripción
makespace-17.zip Colección usada en el taller

Fotos

Album de fotos completo en Google

Autores

  • Jesús Arroyo
  • Juan González (Obijuan)

Licencia

Más información

Créditos

Agradecimientos

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.