Recientemente obtuve una placa de desarrollo FPGA para empezar a aprender y desarrollar algunos proyectos. La placa es una Nanoboard 3000 con un Xilinx Spartan-3AN, tiene muchos complementos pero para este primer ejemplo solo voy a usar un pulsador y los LEDs RGB de usuario.

FPGqué?

Si no sabes nada acerca de FPGAs te recomiendo que investigues un poco antes de leer este artí­culo. En una oración, un FPGA es hardware programable, no software corriendo sobre un hardware, sino diferentes bloques de hardware que se recombinan de acuerdo a tu programa. Por supuesto hay muchas webs con explicaciones mejores y más precisas, si te interesan los FPGA deberí­as leerlas.

El Proyecto

El proyecto propuesto es muy simple, usar un pulsador para prender y apagar un LED. La idea es que cada vez que se presiona el botón el LED cambie de estado, si estaba apagado se prenda, si estaba prendido se apague. Nada deberí­a pasar si el botón se mantiene apretado o cuando se lo suelta, el único evento que importa es cuando se presiona. En realidad, simple es de describir, pero la implementación tiene sus vueltas. Los lenguajes más comunes para la programación de FPGAs son Verilog y VHDL, pero como todavía estoy aprendiendo y no podía esperar para probar mi placa utilicé lo que se: Esquemas (Schematics)

Una Primera Aproximación: Un Biestable T

Primero, en caso de que no lo sepas, un Biestable (o Flip-Flop) es un circuito bi-estable, es decir puede estar en dos estados (generalmente considerados como 0 y 1 o Bajo y Alto). Esta propiedad los hace útiles como memorias de un bit, donde se puede guardar un valor lógico para su uso futuro. Perfecto!, utilicemos un Biestable para mantener el estado del LED: cuando el Biestable tiene un 1 en su salida, el LED estará prendido, cuando tiene un 0, el LED estará apagado. Pero hay varios tipos de Biestable, cuál utilizamos? En este caso podemos utilizar un Biestable T, donde T viene de toggle (conmutar, alternar). Su nombre descibre su funcionamiento, siempre que haya un uno en la entrada del Biestable T cambiará de estado, pasando de un 0 a un 1 o de un 1 a un 0 dependiendo su estado previo.

Entonces la operación básica sería que siempre que se pulse el botón el Biestable recibirá un 1 en su entrada y alternará de estado, cambiando el estado del LED. Es un poco más fácil entenderlo viendo el esquema:

FPGA First Project: First Approach

Explicaré brevemente el esquema de izquierda a derecha. Primero están las dos entradas, el pulsador (SW_USER0) y el reloj de la placa (CLK_BRD), necesario para el Biestable. Luego está el Biestable T, con su entrada T conectada el pulsador, su entrada de reloj conectada al reloj de la placa, una entrada Clear (CLR, borrar) conectada a tierra ya que no la necesitamos por ahora, y su salida Q. Lo que sigue es un Bus Joiner (Unión de Bus). Es necesaria ya que la placa tiene 8 LEDs controlados por un bus de 8-bits (un bit por cada LED), de manera que la salida del Biestable de un bit se conecta a cada bit de dicho bus utilizando el bus joiner (en este ejemplo controlaremos los 8 LEDs juntos). Finalmente están los LEDs. Las entradas LED_G y LED_B estan conectadas a tierra ya que son LEDs RGB y en este momento solo interesa el color rojo.

Listo, a probarlo.

Funciona... MAL, muy mal, totalmente aleatorio. Qué pasó? Tomate tu tiempo para analizar el circuito y tratar de descubrir el problema vos mismo. La solución en el próximo párrafo, no hagas trampa!

Bueno, el problema es realmente simple (simple de darse cuenta una vez que cometiste el error). El Biestable T cambia su estado siempre que tenga un 1 en su entrada, con CADA pulso de reloj. El reloj de la placa por defecto funciona a 50MHz, es decir hay un pulso cada 20ns. No hay forma de presionar y soltar el botón en 20ns, por lo que cada vez que lo aprientes habrá más de un pulso, o peor, un número desconocido de pulsos, dejando el Biestable en cualquier estado menos el deseado.

La Solución Final: El Biestable D

Ya encontramos el problema pero... cómo lo resolvemos? El truco es que no deberíamos cambiar el estado del Biestable cada vez que el botón da como salida un 1. En cambio, solo deberí­amos alternarlo cuando el botón recién fue presionado, o más precisamente, cuando la salida del botón cambia de 0 a 1. Para detectar esta transición no solo necesitamos el estado actual del botón sino que debemos recordar el estado previo, necesitamos entonces memoria. Memoria... memoria? qué utilizábamos como memoria?

Si, necesitamos otro Biestable. En este caso utilizamos un Biestable D, con d de delay (retardo). Su comportamiento es muy simple, simplemente da como salida la entrada. ¿Cómo es útil ésto? Porque solo cambia con un pulso de reloj, manteniendo como salida la entrada previa, no la actual, hasta el próximo pulso. Entonces si en el pulso de reloj previo habí­a un 0 y ahora hay un 1 en la entrada, la salida del Biestable permanecerá 0 hasta el próximo pulso, justo lo que necesitabamos.

Como dije antes, sólo necesitamos cambiar el estado del Biestable T si hubo un cambio de 0 a 1 en el pulsador. El estado actual se obtiene directamente del botón, mientras que el estado anterior se obtiene del Biestable D. Todo lo que neceistamos es una compuerta AND con una entrada negada, de manera que solo de como salida 1 cuando el botón está en 1 y el Biestable D en 0. El resto del circuito se mantiene, dando como resultado el siguiente esquema:

FPGA First Project: Final Solution

El Resultado

Un breve video para mostrar su funcionamiento

Espero te haya gustado el tutorial, si te quedó alguna duda o tenés alguna sugerencia hacémelo saber. Voy a tratar de seguir escribiendo artí­culos a medida que aprenda más sobre los FPGAs.

El proyecto fue desarrollado utilizando Altium Designer. Podés bajar los archivos y jugar con ellos desde Github