jueves, 15 de septiembre de 2011

Tutorial emulación/simulación de Arduino en FPGA - Parte VI

Acelerar, personalizar y optimizar Arduino

Hasta ahora no hay ninguna razón por la que utilizar una FPGA para ejecutar código Arduino: es mejor y más barato programar una Arduino convencional. En este capítulo se van a discutir y explicar varias razones para emular Arduino -o cualquier microcontrolador- en una FPGA:

1. Aceleración
Una FPGA puede realizar operaciones complejas en uno o pocos ciclos de reloj. Un microcontrolador está especializado en hacer un gran número de operaciones sencillas por segundo. En algunos casos es muy beneficioso resolver un problema con lógica reprogramable. Los ámbitos interesantes son: criptología, tratamiento de imágenes, reconocimiento de voz, radioastronomía...

Es una ventaja interesante especialmente para la investigación. Hay pocos usos en los que una FPGA sea más rápido que un microprocesador moderno o una GPU. En el ámbito Arduino (bajo coste), no importa demasiado.

2. Obsolescencia
Este problema se presenta especialmente en la industria: un microcontrolador utilizado hace años en un proyecto aún en producción, se deja de fabricar. Normalmente el código programado para microcontroladores están especialmente concebidos para un modelo concreto e incluso con una frecuencia de reloj concreta.

Este problema no existe si se emula el microcontrolador en una FPGA. Aunque la FPGA se deje de fabricar, se puede emular el mismo código, con el mismo comportamiento, en cualquier modelo parecido de chip reprogramable.

En el ámbito de Arduino este problema no se suele dar: es más fácil cambiar el código.

3. Paralelismo
Esta es la primera ventaja que sí es interesante en el mundo hazlo-tú-mismo/Arduino.

Ejemplo I: es necesario encender 8 LEDS exactamente a la vez, sin un retraso mayor de un ciclo de reloj entre la primera y la última. Además, hay que encender sólo algunos, dependiendo de una entrada.

Ejemplo II: se está generando una señal con la Arduino que se transmite por radio. Una modulación PWM cuya distorsión debe ser mínima. Además, hay que generar 5 con distintas frecuencias. Además, hay que usar el micro para leer del puerto serie y otros trabajos que utilizan el microcontrolador por períodos indeterminados de tiempo.

Ejemplo III: en un sistema que controla un robot se están utilizando 4 timers, 30 LEDS, 8 entradas analógicas y varios sensores que piden interrupciones para dar su dato.

En estos tres ejemplos una Arduino convencional estaría saturada o no sería capaz de cumplir requisitos. Un número importante de interrupciones puede saturar el microcontrolador y, sobre todo, convertir el desarrollo del proyecto en un auténtico infierno.

Una solución podría ser la siguiente: un microcontrolador para cada sensor, uno para cada salida PWM, uno para cada LED, uno para cada servo y cada motor y una Arduino para gobernarlos a todos.

Con una FPGA es posible llegar a un término medio y es una de sus aplicaciones más comunes: un microcontrolador gobierna un sistema de módulos independientes con un sistema de comunicación entre ellos eficiente y simple.

Entonces, en el ejemplo I se programaría en VHDL un módulo que gestione 8 salidas digitales a la vez, en el mismo ciclo de reloj, en el momento que le llegue la orden del microcontrolador.

En el ejemplo II se programaría un módulo VHDL que genera una señal PWM. Para ello utilizaría un contador, parecido al timer del microcontrolador pero sin interferir con él. Para generar 5 señales sólo hay que instanciar este módulo 5 veces y conectarlos con las salidas correspondientes. Cualquier pin físico sería válido.

En el ejemplo III se generaría un módulo en VHDL para cada timer, módulos de gestión de cada sensor, etc. El microcontrolador sólo tendría que atender las entradas de usuario y enviar los mensajes correspondientes a cada módulo. Todo a máxima velocidad y mínima saturación del micro.

La comunicación entre módulos se hace utilizando las direcciones de ram externa que no están siendo utilizadas en el proyecto AVR8. Se definen tantos registros como sea necesario para cada módulo.

4. Personalización

Tener el código del microcontrolador a utilizar tiene sus ventajas. Es posible, por ejemplo, aumentar el número de salidas digitales o analógicas (y hacerlo de forma más eficiente gracias al punto anterior).

En el siguiente ejemplo se crea una Arduino emulada y se modifica para tener 48 salidas pseudo-analógicas PWM.

  1. 48 módulos independientes con un temporizador de una resolución de 8 bits.
  2. Cada módulo se conecta a un pin de la Papilio.
  3. 48 direcciones de memoria externa reservadas para la comunicación entre Arduino y los módulos.
  4. Si el valor en cada registro es mayor que el contador, a la salida del módulo se pone un uno. Si no, un cero.
Con la herramienta Oruga (pendiente de publicación) es posible crear puntos base para desarrollar este tipo de proyectos

Herramienta Oruga

Además, se baja el módulo PWMout.vhd que está preparado para ser utilizado con un proyecto Oruga. Es un módulo que recoge un valor de 8 bits de un registro de memoria (cuya dirección es definida en el momento de instanciarlo) y lo utiliza para generar una señal PWM con un ciclo de trabajo proporcional al valor que le llegue.

En el siguiente código (auto-generado por Oruga) se instancia el módulo que se configura con la dirección de memoria E/S 0x0FE0 y se conecta con el pin físico 0 del puerto A. Además, se configura ese pin para ser de salida en la última línea.

OrugaA_0:component Oruga_PWMout
GENERIC MAP(
io_base_address_generic => x"0fe0")
PORT MAP(
    nReset => nrst,
    clk => clk16M,
    adr => core_adr,
    dbus_in => core_dbusout,
    iore => core_iore,
    iowe => core_iowe,
    output_sig => porta(0)
); 

DDRAReg(0)<='0';

Se genera un proyecto con 48 pines conectados a instancias de módulos PWMout. Por defecto se reservan dos direcciones de memoria para cada módulo. El primer módulo tendrá las direcciones 0xFE0 y 0xFE1, el segundo 0xFE2 y 0xFE3 y así hasta el último módulo: 0x103e y 0x103f. Esto es así para poder utilizar un byte de escritura y otro de lectura, pero en este caso sólo es necesario enviar datos al módulo PWM (sólo se usan las direcciones pares).

El esquema con los 48 módulos es peculiar:

El código Arduino inicial va a ser:

void setup()
{
  for (int i = 0; i<48; i++){
    writePWM(i, 256*i/48);
  }
}

void loop()
{
}

 Junto con el fichero Oruga.pde, que contiene lo siguiente:

#define io_start_address 0x0FE0

byte writePWM(int pin, byte value){
    _SFR_IO8(io_start_address+pin*2) = value;
}


Este sketch va a configurar el estado inicial de cada módulo PWM con código Arduino, por lo que la configuración va a hacerla el microcontrolador, módulo a módulo.



Se puede observar que en 800 microsegundos (menos de un milisegundo) se han configurado los 48 canales, cada uno con un valor distinto de ciclo de trabajo, con 3 líneas de Arduino y ni una sola de VHDL, gracias a la herramienta Oruga. Además, la función loop() de Arduino está vacía, por lo que el microcontrolador está totalmente libre para otros trabajos.









No hay comentarios: