, 139 tweets, 65 min read Read on Twitter
Los circuitos digitales se intercambian información a través de buses de comunicaciones. Hay muchos. Uno de ellos es el bus SPI. Un microcontrolador, como por ejemplo arduino, puede leer datos de un sensor mediante el bus SPI #FPGAwars es.wikipedia.org/wiki/Serial_Pe…
El circuito principal, el que lleva la voz cantante en la comunicación, se nomina el Maestro. Típicamente es un microprocesador (Ej. Arduino). El otro circuito se denomina esclavo, y su misión es responder a los comandos que le envía el maestro #FPGAwars
Los datos se transmiten en serie, bit a bit, uno por cada periodo del reloj SCLK del maestro. Según cómo se haya configurado, las acciones de lectura y escritura de los bits se harán bien en los flancos de subida o de bajada #FPGAwars
Por MOSI se transmiten los datos del maestro al esclavo, y por MISO del esclavo al maestro. La información fluye en ambos sentidos a la vez (full-dúplex). El esclavo sólo funciona cuando se activa la señal SS, en caso contrario no responderá a ninguna petición #FPGAwars
Nos centraremos en cómo hacer circuitos esclavos en la FPGA, que se comunican con un maestro. En los ejemplos utilizaremos un Arduino UNO como Maestro. Con Arduino trabajaremos en software, mientras que con la FPGA en hardware #FPGAwars @arduino @dcuartielles
Utilizamos la unidad de SPI hardware que incorpora Arduino, por lo que los pines que usaremos para las señales son: D13-SCLK, D12-MISO, D11-MOSI, D10-SS. Los conectamos a los pines del mismo nombre en la Alhmbra-II. El conexionado queda así: #FPGAwars
Para implementar fácilmente nuestros circuitos esclavos por el SPI usaremos el bloque SPI-esclavo, dispoinible en la colección Jedi 1.6.0 en el menú Varios/SPI/SPI-slave/SPI-slave-unit. Las patas MISO, MOSI, SCLK y SS se conectan directamente a los pines SPI correspondientes
Los intercambios de información se hacen siempre en grupos de 8 bits, lo denominamos una transacción. En cada transacción llega un dato del maestro y se envía a la vez otro hacia el maestro. Por tanto, en toda transacción hay siempre un dato que llega y otro que sale #FPGAwars
Por rcv se recibe un tic cada vez que se ha completado una transacción, y por tanto se habrá recibido un dato nuevo y se habrá enviado otro. El esclavo emite un tic por load para cargar el dato que quiere enviar al maestro. Pero hasta que el maestro no lo indique no se envía nada
En este primer ejemplo haremos un circuito esclavo en la FPGA que simplemente muestra por los LEDs el dato recibido a través del SPI. En el arduino se ejecutará un programa que envía dos valores, cada medio segundo. El escenario es el siguiente #FPGAwars
El circuito es muy sencillo. Sólo hay que colocar el bloque SPI-esclavo y conectar directamente las señales del SPI a los pines correspondientes. El dato de salida se lleva directamente a los LEDs de la Alhambra II. ¡Ya tenemos nuestro primer periférico SPI hecho! ¡Así de fácil!
En el Arduino cargamos este código. El SPI se configura a su máxima velocidad: 4 Mhz. Los pines SCLK y MOSI los controla el hardware spi de Arduino, mientras que SS lo establecemos nosotros en el programa. La función write_LEDs() activa SS, envía el valor y desactiva SS #FPGAWars
El programa principal envía 0xAA, espera medio segundo, envía 0x55 y espera otro medio segundo. Esta se repite para obtener la secuencia en los LEDs. En este vídeo lo vemos en acción. Si quitamos el cable SCLK se dejan de transmitir los datos y la secuencia se detiene #FPGAwars
También, al apretar el reset de Arduino, la secuencia se para, porque se dejan de enviar los valores. Al apretar el reset de la FPGA, todo se apaga porque el hardware desaparece. Al terminar se vuelve a configurar la FPGA, aparece el circuito del SPI y la secuencia continúa
Si necesitamos guardar el dato recibido en un registro, usamos la señal rcv. En este ejemplo se captura el dato y se muestra en los LEDs, pero pasándolo por el bloque brillo-gradual para generar una transición suave #FPGAwars
Actualizamos el hardware, pero usamos el mismo software anterior para Arduino. En este vídeo se muestra el resultado. El registros que hemos usado no es necesario realmente. Si lo quitamos sigue funcionando igual. Es sólo un ejemplo de cómo capturar lo recibido #FPGAwars
Para enviar datos desde el esclavo al maestro, primero hay que cargarlos en el transmisor, y se enviarán en la siguiente transacción que inicie el maestro. Como ejemplo leeremos los dos pulsadores de la Alhambra II, SW1 y SW2 y los mostraremos en dos LEDs conectados al Arduino
Sabemos que comienza una transacción nueva cuando la señal SS pasa de 0 a 1 (es activa a nivel bajo). Ese es el evento que usaremos para capturar el estado de los pulsadores. El byte a transmitir contiene el estado de SW1 y SW2 en los bits 0 y 1 respectivamente, y el resto a 0
El programa de arduino está constantemente leyendo los pulsadores Si alguno está apretado, se enciende su LED. Se usa ña función leer_pulsadores(). Activa el esclavo y realiza una transacción de envío y recepción (a la vez). Se envía el valor 0, que el esclavo ignora #FPGAwars
Cargamos el programa en el Arduino, y el circuito en la FPGA. En este vídeo se muestra en funcionamiento. Apretando cada pulsador se enciende el LED correspondiente. ¡Nuestro periférico de lectura de pulsadores por SPI funciona! 😀 #FPGAwars
En este ejemplo se muestran transmisiones y recepciones. Todo lo que envía el maestro se saca por los LEDs. Cada dato recibido se incrementa en 1 y se devuelve como respuesta en la siguiente transacción #FPGAwars
El programa de arduino genera una secuencia de dos estados, enviando los valores 0xF0 y 0x0F, que se ven en los LEDs. Los valores recibidos se imprimen en el terminal serie de Arduino para comprobar que se han incrementado #FPGAwars
En este vídeo vemos la secuencia en los LEDs, y los datos recibidos en el terminal de Arduino. Ya sabemos cómo hacer periféricos que envían y reciben. Estamos listos para pasar al siguiente nivel #FPGAwars
El bloque SPI esclavo que estamos usando en los ejemplos de este cuaderno técnico tiene las siguientes especificaciones técnicas: #FPGAwars
Este es su cronograma. Tanto el maestro como el esclavo capturan los datos en el flanco de subida, y los depositan en el de bajada #FPGAwars
Vamos a realizar mediciones para comprobar que nuestro SPI se comporta adecuadamente. Usamos el mismo circuito del ejemplo 4, al que simplemente le hemos añadido la documentación sobre los canales a los hemos conectado cada uno de los pines. Es el ejemplo 5 #FPGAwars
Este es el escenario. El bus SPI va del Arduino a la FPGA usando cables macho-macho, y al analizador mediante cables hembra-hembra. En los canales del 0 al 3 se muestran las 4 señales del SPI #FPGAwars
En el arduino cargamos un programa que envía la secuencia 0xAA y 0x55 por el SPI, sin pausas y sin usar el puerto serie. Los valores 0xAA y 0x55 se usan mucho en hardware porque tiene los bits alternados y permiten ver mejor las señales #FPGAwars
Realizamos las mediciones con el Pulse-View @sigrokproject . Los valores que se envían por MOSI son 0x55 y 0xAA, alternativamente. Y los recibidos por MISO son los mismos pero incrementados en una unidad: 0x56 y 0xAB, y recibidos en la transacción siguiente #FPGAwars
Aquí se muestra una transacción más de cerca. Los marcadores A y B están en los dos primeros flancos de subida, donde se hacen las capturas. Se comprueba que se cumple el cronograma anterior. Las señales MOSI y MISO inferiores muestran los bits ya capturados #FPGAwars
Y en esta otra captura se muestra la temporización de la señal de reloj, que efectivamente es de 2Mhz (500ns) #FPGAwars
Con el SPI ya tenemos solucionado el problema del intercambio de bytes entre dos circuitos, en ambas direcciones. El siguiente paso es definir comandos para controlar nuestros periféricos. Tendremos que definir una sintáxis para ellos #FPGAwars
Un forma típica es usar comandos de 2 bytes, donde el primero contiene el código de comando, y el segundo el valor. Así por ejemplo, para sacar un valor por los LEDs podemos definir el comando WRITE_LEDS así #FPGAwars
Por ejemplo, para sacar el valor 0xAA por los LEDs, tendríamos que enviar los siguientes bytes: 0x40 y 0xAA. El primero le indica al periférico la acción a realizar (activar los leds) y el segundo el valor de los LEDs. El código 0x40 lo hemos definido nosotros (los diseñadores)
En este ejemplo se implementa el comando WRITE_LEDs. Un biestable RS es el encargado de notificar la llegada del comando, comparando el dato recibido con el código 0x40. Este biestable se inicializa a 0 con cada comando terminado, cuando SS se pone a 1 #FPGAwars
Todo lo recibido se ignora, hasta que se detecta el comando. Entonces el biestable habilita la puerta AND, de forma que el siguiente tic llega hasta el registro, capturándose el valor y sacándose por los LEDs. El maestro debe activar SS, envíar los dos bytes y desativar SS
Esto es lo que hace la función write_LEDs(). El programa principal saca una secuencia de 3 estados, para comprobar que el comando funciona correctamente. En este ejemplo no se prueba, pero cualquier otro comando diferente se ignora #FPGAwars
Cargamos el circuito y el programa de Arduino. En este vídeo los vemos en acción. No es nada espectacular, pero tenemos implementado un periférico por el SPI que responde a nuestro primer comando de 2 bytes 😀 #FPGAwars
Los comandos con dos parámetros: código de comando y valor son muy comunes. Para hacer más fácil y rápida su implementación podemos usar el bloque cmd8, disponible en el menú Varios/Syntax/cmd8. Por su entrada se van recibiendo los datos del spi #FPGAwars
Si se recibe el comando especificado, el bloque devuelve el valor que llega tras ese comando, y emite un tic de datos. Para reconocer el siguiente comando se debe inicializar. Se hace con la señal SS del SPI #FPGAwars
Se trata de un bloque sintáctico, para detectar el patrón comando-valor. Aunque lo estamos usando con el SPI, es un bloque genérico y sirve para reconocer comandos que lleguen por cualquier periférico: bus i2c, spi, serie, etc... #FPGAwars
Rehacemos el ejemplo 6-1, pero usando el nuevo bloque cmd8. Ahora queda mucho más compacto y fácil de entender y modifcar. Y lo más importante, es mucho más fácil añadir nuevos comandos. El funcionamiento es exactamente igual que el del ejemplo anterior #FPGAwars
En este ejemplo implementamos un comando más, para controlar el brillo de los LEDs: BRILLO_LEDS, cuyo código de comando es 0x50. Así, nuestro nuevo periférico tiene 2 comandos: escribir un valor en los LEDs (WRITE_LEDs) y controlar su brillo (BRILLO_LEDs) #FPGAwars
Los dos comandos se implementan muy fácilmente con el bloque sintáctico cmd8. Usamos uno para cada comando, y colocamos registros para almacenar los valores recibidos. Un registro para almacenar el nivel de brillo y otro para el dato a mostrar en los LEDs #FPGAwars
Gracias a las etiquetas, el diseño es muy legible y nos permite separarlo en tres zonas: la parte de comunicación SPI, el comando WRITE_LEDs y el comando BRILLO_LEDs. También permite que sea muy fácil llevar comandos de un periférico a otro mediante copiar y pegar 😀 #FPGAwars
En el programa de Arduino creamos la función brillo_LEDs() para establecer el nivel de brillo usando el nuevo comando. La mecánica es la misma: bajar SS, enviar el código de comando, el valor para el brillo y subir SS. La función Write_LEDs() no cambia: es la misma de antes
Como ejemplo de uso, en el programa principal establecemos diferentes valores para los leds, con diferentes intensidades, cada medio segundo, generando así una secuencia simple #FPGAwars
Cargamos el programa en el Arduino y el circuito en la FPGA. En este vídeo vemos el resultado. Nuestro periférico por SPI ya tiene 2 comandos 😀 #FPGAwars
En este ejemplo modificaremos el programa de arduino para implementar LEDs pulsantes, que se encienden y apagan progresivamente. En el setup() se escribe 0xFF en los LEDs y en el bucle principal se modifica el brillo, del mínimo al máximo y vice versa #FPGAwars
En este vídeo lo vemos en acción. Cambiando el tiempo de los diferentes delays se consigue modificar el tiempo de encendido/apagado, así como el tiempo en el que los LEDs están totalmente apagados #FPGAwars
Implementaremos un comando más: READ_BUTTONs, para leer los dos pulsadores de la Alhambra II. Para este comando usaremos el código 0x60. Al recibir este comando, el esclavo nos devuelve el estado de ambos pulsadores en la siguiente transacción. Tabla resumen de los 3 comandos
El comando READ_BUTTONS NO tiene argumentos adicionales. Por ello NO usamos el bloque sintáctico cmd8, sino que en cuanto se recibe el código 0x60 se carga el valor de los pulsadores en el registro de transmisión del SPI, para su envío en la siguiente transacción #FPGAwars
Desde el Arduino, hacemos la lectura de los pulsadores usando la función read_buttons(). Se activa el esclavo, se envía el código 0x60 y luego el código basura 0x00 para que haya una segunda transacción. El esclavo devuelve el estado de los pulsadores en esta segunda transacción
Para probar el funcionamiento de todos los comandos hacemos un programa en Arduino que genera una secuencia en los LEDs. Con los pulsadores SW1 y SW2 subimos y bajamos el brillo de los LEDs. Conectamos dos LEDs en el Arduino para mostrar el estado de los pulsadores #FPGAwars
En este vídeo se ven las pruebas. Comienza con la secuencia en los LEDs. Al pretar SW2, el brillo disminuye. Al apretar SW1, aumenta. Además, se encienden los LEDs en el Arduino, para tener feedback visual de las pulsaciones #FPGAwars
Lo que más me gusta de estos experimentos es que estamos trabajando en ambos mundos: Hardware y Software. Este pantallazo de mi portátil de trabajo me encanta 😀 . En la derecha tenemos el diseño del hardware. En la izquierda su programación #FPGAwars
En la derecha usamos un pensamiento espacial y paralelo, donde hay movimiento físico de bits. En la izquierda un pensamiento algorítmico secuencial: se ejecuta una instrucción tras otra. En la derecha tenemos FPGAs, en la izquierda Arduino (procesador) #FPGAWars
Con un click de ratón aquí, actualizamos el hardware. Con otro click allá, cambiamos su programación. No dejo de asombrarme de lo potente y apasionante que es esto. ¡Estoy enganchadísimo! ¡¡Sigamos pues!! 😀😀 #FPGAwars
Implementaremos un comando más: READ_ID que nos devolverá el identificador del periférico. Un valor constante, por ejemplo 0xE3, que identifique a este esclavo. Así aprenderemos cómo enviar al maestro información proveniente de varias fuentes #FPGAwars
Mediante un codificador de 2 a 1, obtenemos una señal que nos indica cuál de los dos comandos READ se ha recibido, lo que nos permite seleccionar el byte a enviar al maestro, mediante un multiplexor 2 a 1. Por load llevamos el tic de carga al SPI #FPGAwars
El resto del circuito es igual que en el ejemplo anterior. Eso es lo bueno de usar etiquetas, que podemos tener sub-circuitos dentro de los circuitos para organizarlo mejor. Este es el circuito completo #FPGAwars
El programa de arduino lo podemos mejorar. Creamos la función cmd() para enviar un comando genérico. Pasamos como parámetro el código del comando y el valor. Devuelve lo leido por el SPI, si el comando era de lectura. Los comandos los implementamos a partir de esta función
Modificamos el ejemplo anterior (ejemplo 9) para que cada 2 segundos lea el identificador del esclavo y lo imprima por la consola serie. Al final del bucle principal añadimos #FPGAwars
Probamos el nuevo ejemplo. Además de ponder cambiar el brillo de los LEDs con los pulsadores mientras hay una secuencia, veremos en la consola serie el identificador el esclavo que hemos asignado. Aparece la información cada 2 segundos #FPGAwars
Muchos periféricos por SP tienen registros accesibles mediante una dirección. Se denominan registros mapeados. Para acceder a ellos se usa un registro especial que contiene la dirección del registro al que se quiere acceder. Es el registro de dirección (o puntero de registros)
Sólo se usa 3 comandos: uno para establecer el valor del registro de dirección, lo que selecciona el registro a usar. Otro para escribir en el registro activo y otro para leer de él. Los denominamos SAP (Set address Pointer), WR (Write in register) y RD (Read from register)
Cada comando tiene su propio código, que dependen del diseñador. Los códigos que vamos a usar son los mostrados en esta tabla, que coinciden con los usados por el chip CAP1188, un lector de sensores capacitivos de MicroChip #FPGAwars
Empezaremos por un ejemplo de un periférico SPI en el que sólo tenemos un registro mapeado: el registro de LEDs, en la dirección 10h. Al escribir en él se cambian los LEDs. Su lectura nos devuelve los valores actuales que se están mostrando #FPGAwars
Esta es la implementación de los 3 comandos, que ya conocemos. Sólo cambian los código usados, que son otros. Sólo hay un registro, el de dirección, donde se almacena la dirección del registro a leer o escribir. El comando de escritura emite el tic wr y el de lectura el tic rd
Con el tic de wr se guarda el valor en el registro previamente seleccionado con el comando SAP, y con el tic de rd se carga el valor a enviar al maestro, que se transmisitrá en la siguiente transacción. Gracias a las etiquetas el diseño queda muy compacto y modular #FPGAwars
El registro LEDs está en la dirección 10h (lo hemos decidido nosotros) y es de lectura y escritura. El valor que tiene inicialmente es 0, pero se puede establecer cualquier otro. En esta tabla se resume #FPGAwars
Con un comparador generamos leds_cs, para indicar que se accede a la dirección del registro LEDs. Al llegar el tic de wr se guarda el valor en el registro, que se saca por los LEDs. Esta es su implementación #FPGAwars
Para la lectura se usa un multiplexor 2-1 y la señal leds_cs para seleccionar qué llevar al bloque SPI. Si se ha seleccionado el regisro LEDs, se lleva su valor, o de lo contrario un 0. Por tanto, si leemos de cualquier otro registro que no sea LEDs, leeremos un 0 #FPGAwars
El circuito completo es el siguiente, con todas las partes juntas #FPGAwars
En el programa de Arduino creamos las funciones para invocar los tres comandos: SAP_cmd(), WR_cmd() y RD_cmd() #FPGAwars
Y a partir de ellas escribimos las dos funciones que nos dan el interfaz final: write_reg(), para escribir en un registro situado en una dirección, y read_reg() para leer el registro de una dirección. En este ejemplo sólo tenemos el registro LEDs en la dirección 10h #FPGAwars
Cargamos el circuito en la FPGA y el programa en el Arduino. En la consola serie veremos el valor leído de los LEDs, cada medio segundo #FPGAwars
Y en este vídeo vemos la secuencia en acción #FPGAwars
Trabajar con regitros mapeados es lo más habitual, por eso se ha creado el bloque SPI-reg-cmd, accesible desde el menú Varios/SPI/SPI-slave, que implementa los comandos SAP, WR y RD necesarios para seleccionar el registro a usar, escribir o leer #FPGAwars
Recibe por su entrada los datos que llegan del SPI y nos devuelve a la salida la dirección del registro seleccionado, el valor a escribir en caso de escritura y los tics de lectura y escritura necesarios para realizar estas dos operaciones #FPGAwars
Aunque lo estamos usando con el SPI, se trata de un bloque genérico que nos permite implementar el acceso a registros mapeados para cualquier otro Bus: I2C, Serie, etc... Pero de momento nos centramos en el SPI, que es nuestro primer Bus #FPGAwars
Rehacemos el ejemplo 11-1 pero utilizando este nuevo bloque SPI-cmd-reg. El funcionamiento es exactamente igual, no hay nada nuevo, pero ahora el circuito queda mucho más compacto y legible. Los datos que llegan del SPI se procesan en este bloque, que accede al registro de LEDs
Este es el poder del diseño jerárquico: crear bloque más potentes a partir de otros más simples, que nos permitan ocultar la complejidad e ir creciendo en funcionalidad. Poco a poco haremos bloques más avanzados, hasta que lleguemos al procesador. Sigamos de momento con el SPI
Dentro de poco, gracias al trabajo de Carlos Venegas (@cavearr ) podremos trabajar en icestudio con diseños jerárquicos de forma más avanzada: navengado y editando bloques a cualquier nivel. Esto se empieza a poner cada vez más emocionante. ¡Gracias Carlos! #FPGAwars
Los registros mapeados en una dirección son muy comunes, por lo que resulta muy útil tener un bloque específico para implementarlos: el bloque reg-addr, disponible en el menú Varios/Registros/08-bits/reg-addr. Los parámetros son la dirección de mapeado y su valor por defecto
Cuando recibe un tic de escritura, almacena el valor de su entrada de datos (bus de datos) si la dirección en el bus de direcciones coincide con la que tienen configurada.Cuando esto ocurre, además se activa su salida cs (chip select) para indicar que se ha seleccionado #FPGAwars
Modificamos el ejemplo 11-2 para implementar el registro de LEDs usando el bloque reg-addr. El esquema es mucho más claro. El bloque SPI se conecta con el de comandos para procesar lo recibido, y envíar la información por el bus de direcciones, bus de datos y el de control
El registro de LEDs se conecta a estos buses para que se puedan realizar escrituras y lecturas. Su salida se conecta al bus de datos de salida (dataout) mediante un multiplexor. Este bus es el que llega al bloque SPI para enviar las lecturas al maestro #FPGAwars
Aunque este cuaderno técnico es sobre el SPI, vamos a hacer un ejemplo de acceso al registro de LEDs mapeado en memoria pero a través del puerto serie. Los comandos los enviamos desde un terminal serie en el PC. Podemos usar el propio terminal de Arduino #FPGAwars
Esto nos servirá para comprobar que los bloques de comandos y mapeo de registros son genéricos. Aunque cambiemos el nivel físico (del SPI al puerto serie), el resto del circuito se comporta igual. También nos servirá para prototipar más rápido #FPGAwars
Este es el mismo circuito del ejemplo 11-3, pero para el puerto serie. Para hacer más fácil su uso hemos cambiado los códigos de los comandos por caracteres ASCII que se puedan teclear fácilmente desde cualquier termianl serie. La dirección del registro de LEDs es "1" (0x31)
Cualquier carácter enviado se ignora salvo que sea "S" (SAP), "W" (WR) o "R" (RD). La lectura genérica devuelve el carácter "-" salvo que hayamos seleccionado el registro de LEDs previamente con el comando "S1", en cuyo caso nos devuelve su valor #FPGAwars
Abrimos el terminal de arduino, a la velocidad de 115200 baudios para hacer pruebas. Si enviamos el comando de lectura "R" nos devolverá el carácter "-". Podemos enviar varias Rs para hacer varias lecturas #FPGAwars
Si enviamos la cadena S1WU, se selecciona el registro (dirección "1") y se encenderán los LEDs con el valor 0x55 (es el valor ASCII de la 'U'). Ahora al leer nos devuelve lo que habíamos escrito antes: la "U". Si enviamos "W*" saldrá el valor 0x2A por los LEDs, y leeremos *
La Alhambra II está conectada directamente al PC. En esta foto se muestran los LEDs después de enviar el comando de escritura "WU" #FPGAwars
Y en este vídeo de muestra el funcionamiento. Podemos ver cómo cambian los LED al usar el comando de escritura, y los valores que se leen con el comando de lectura #FPGAwars
Añadimos un registro adicional para controlar el brillo de los LEDs, mapeado en la dirección 0x11. En nuestro periférico tenemos ahora dos registros de lectura/escritura accesibles a través de los comandos SAP, WR y RD #FPGAwars
El registro de brillo se añade muy fácilmente con el bloque reg-addr. Especificamos su dirección (0x11) y su valor por defecto (255) en los parámetros. Para la escritura sólo hay que conectarlo al bus de direcciones, de datos y al tic de escritura #FPGAwars
Para la lectura necesitamos un circuito adicional. Con un codificador de 2 a 1 determinamos qué registro está seleccionado: el de brillo o el de leds. Si no está seleccionado ninguno, la salida zero del codificador estará a 1. Con un mux 2:1 obtenemos el dato del registro
Con un segundo multiplexor 2-1 devolvemos bien el valor del registro o bien 0x00 si no hay seleccionado ninguna. Es nuestro valor de lectura por defecto. La salida final va por el bus de datos de salida (dataout) hacia el bloque del spi para enviarlo al maestro #FPGAwars
Usamos el bloque brillo8 para implementar el control de brillo de los LEDs. Conectamos sus entradas a los dos registros con el valor de los leds y con el nivel de brillo #FPGAwars
Esta es la pinta que tiene el circuito final, con todas sus partes. Añadir un registro adicional ha sido fácil, ¿no? 😀 #FPGAwars
Para probarlo hacemos un programa en arduino que muestre en los LEDs la misma secuencia del ejemplo 11, pero alternando también el brillo. No hay que añadir ninguna función más, sólo la definición del registro de brillo y modificar el bucle principal #FPGAwars
Cargamos el circuito en la FPGA y el programa en Arduino. En este vídeo se muestra la secuencia en acción. El brillo es máximo cuando se encienden los leds exteriores, y mínimo cuando lo hacen los interiores. Nuestros dos registros mapeados funcionan correctamente en escritura
Desde el terminal de Arduino comprobamos que los valores leídos son los correctos. Se leen los dos registros cada medio segundo. Lo que se escribe es 0xC3 en LEDs con brillo de 255 y luego 0x3C en LEDs con brillo 20. Comprobamos la lectura #FPGAwars
Como último ejemplo de registros mapeados, añadiremos dos más, pero de sólo lectura. Uno contendrá el identificador del periférico, definido por nosotros, y otro el estado de los pulsadores SW1 y SW2 de la Alhambra II. Estos son los 4 registros disponibles #FPGAwars
Los dos nuevos registros son de sólo lectura, por ello no usamos bloques reg-addr. El registro ID debe devolver una constante, que no se puede modificar. Sólo necesitamos usar un comparador para detectar su dirección y colocar la constante con su valor #FPGAwars
La estructura del registro de pulsadores es similar. Con un comparador detectamos los accesos a este registros. A partir de los bits de los pulsadores construimos un número con todo ceros en los bits más significativos y el estado de los pulsadores en los dos de menor peso
Para realizar la lectura de cualquier registro necesitamos un multiplexor 4:1 y un codificador 4:1. Con el multiplexor seleccionamos el dato del registro activo. El codificador nos indica qué registro es el activo. Con un mux 2:1 devolvermos el valor del registro ó 0x00 #FPGAwars
Este es el circuito completo. ¡Me encanta!😀 Y con un sólo click lo tenemos sintetizado y cargado en nuestra FPGA. Me sigue pareciendo magia... #FPGAwars
Y lo más importante... ¡Sólo con herramientas libres! ¡Herramientas del patrimonio tecnógico de la humanidad! 😀 #FPGAwars
Para probarlo modificamos el programa de arduino anterior para imprimir en la consola el estado de los pulsadores y el identificador del periférico. Usamos estas definiciones para acceder a los 4 registros #FPGAwars
Este es el bucle principal. El estado de los pulsadores se muestra en la consola y en dos leds conectados al propio arduino #FPGAwars
Lo cargamos y lo probamos. El funcionamiento es el mismo que el ejemplo anterior, pero ahora, además, se leen los pulsadores cada medio segundo y se muestra su estado en los LEDs. ¡Nuestros registros mapeados funcionan! #FPGAwars
Y en la consola de arduino comprobamos que todos los valores leídos son correctos. El identificador es 0x50 y el estado de los pulsadores varía según los apretamos #FPGAwars
Este es un pantallazo de la consola de arduino, en un instante concreto, para comprobar de forma estática que los valores son correctos #FPGAwars
Si queremos que este mismo ejemplo funcione sobre el puerto serie sólo hay que cambiar el bloque SPI por el transmisor y receptor serie, como hicimos en el ejemplo 12. Para facilitar las pruebas cambiamos también los códigos de los comandos, para que sean caracteres ASCII
También cambiamos las direcciones de los registros, para facilitar las pruebas desde el terminal serie, y los valores devueltos (El registro de identificación contiene "A", y el de pulsadores "0" inicialmente) #FPGAwars
Este es el circuito completo, con los valores cambiados #FPGAwars
Lo probamos con cualquier terminal de comunicaciones, a 115200 baudios. Por ejemplo con el script communicator. En rojo vemos los comandos enviados, y en negro lo recibido. Con SIR leemos el registro de identifición, que es "A". Con S3R los pulsadores #FPGAwars
En el cuaderno técnico 2 aprendimos cómo poner en marcha la pantalla VGA, con una resolucón de 256x240 y color verde. Hicimos un componente, llamado VGALEDs para controlar la mitad derecha e izquierda de la pantalla como si fuesen "píxeles gordos" github.com/Obijuan/Cuader…
Mapearemos este componente como el registro VGALEDs, y lo haremos accesible a través del SPI para poder manejarlo desde el Arduino. ¡Es nuestro primer mini-controlador VGA por SPI!. El circuito es prácticamente igual al ejemplo 11-3 #FPGAwars
El registro VGALEDs lo hemos mapeado en la dirección 0x10 y accedemos a él usando los comandos que ya conocemos: SAP, WR y RD. Los dos bits de menor peso son lo que se llevan al componente VGALEDs que controla la VGA. Además, se sacan por los LEDs 1 y 0 para ver su estado
Este es el escenario. La Alhambra-II está conectada al monitor VGA a través de la placa AP-VGA. El Arduino Uno está conectado a la Alhambra-II, por los cables del SPI #FPGAwars
Este es el bucle principal del código que se ejecuta en el Arduino. Simplemente escribe los valores 0x01 y su negado para hacer que las dos mitades de la pantalla se enciendan alternativamente, cambiando cada medio segundo. Se accede a la VGA escribiendo en el reg. VGALEDs
Cargamos el circuito en la FPGA y el programa en el Arduino. En esta foto se muestra uno de los estados, cuando la mitad izquierda de la pantalla está encendida #FPGAwars
y en este vídeo vemos la animación en acción. Además de activarse la dos mitades alternativamente, el registro VGALEDs también se muestra en los LEDs 0 y 1, que también se están alternando #FPGAwars
El Bus SPI permite la comunicación entre un maestro y varios esclavos. La señal de reloj (SCLK) y la de datos (MOSI) llega a todos los esclavos. La salidas de los esclavos están unidas y llegan al maestro por MISO #FPGAwars
El maestro tiene un cable propio para activar cada esclavo (ss). Así, si hay 3 esclavos, habrá tres señales ss para activar cada uno de ellos. Sólo puede estar activado un esclavo a la vez. Haremos un ejemplo práctico de conexión de dos esclavos a Arduino #FPGAwars
Este es el esquema de que usaremos en los ejemplos: Un arduino UNO conectado mediante el bus SPI a dos FPGAs esclavas. El maestro debe gestionar dos señales de selección de esclavo: ss1 y ss2 #FPGAwars
En la Alhambra II los pines Dx están duplicados: hay uno hembra y otro macho. Esto simplifica mucho las conexiones. Desde el Arduino a la FPGA 1 usaremos cables macho-macho. Y para llevar los cables a la FPGA 2 usamos hembra-hembra, desde la FPGA1 #FPGAwars
Los cables amarillos son macho-macho, y son los de selección. Van desde el Arduino a la FPGA1 y a la FPGA2. Para alimentar la FPGA2 podemos tirar directamente el cable de GND y el de VCC desde la FPGA1 #FPGAwars
Este es el escenario real para hacer las pruebas: El Arduino UNO conectado por SPI a las dos placas Alhambra-II. Para las señales SS1 y SS2 de selección de los esclavos se usan los pines D10 y D9 de Arduino, respectivamente #FPGAwars
En el software de arduino tenemos que definir los pines de selección: SS1 y SS2. Usaremos los pines 10 y 9. Los configuramos para salida y los dejamos inicialmente a 1 para que no haya ningún esclavo seleccionado #FPGAwars
Todas las funciones de acceso al SPI hay que modificarlas para aceptar un nuevo parámetro: el pin de selección del esclavo. Esto nos permitirá indicar con qué esclavo nos queremos comunicar #FPGAwars
Y por último, el programa principal sacará un secuencia de dos estados por cada esclavo, además de leer sus identificadores y sus pulsadores SW1. Estas operaciones se realizan cada medio segundo, para hacerlo sencillo. En la consola serie se imprimen los resultados #FPGAwars
La secuencia en los LEDs se genera enviando su identificador y su negado. De esta forma cada esclavo mostrará una secuencia de 2 estados diferente. Cargamos el programa en el Arduino. En este vídeo lo vemos en acción #FPGAwars
El refresco de los pulsadores se hace cada medio segundo, por eso hay un poco de retraso desde que se pulsa hasta que el arduino lo muestras. Se ha hecho así por simplicidad. En la consola serie podemos ver los valores leidos de cada esclavo #FPGAwars
Aunque los ejemplos de este cuaderno técnico están hecho para la placa Alhambra-II, también son válidos para la Icezum Alhambra (y para el resto de placas ice40, por supuesto). Este es el escenario en el que se está probando el ejemplo 14 #FPGAwars
Missing some Tweet in this thread?
You can try to force a refresh.

Like this thread? Get email updates or save it to PDF!

Subscribe to Juan Gonzalez
Profile picture

Get real-time email alerts when new unrolls are available from this author!

This content may be removed anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!