viernes, 16 de septiembre de 2011

Tutorial emulación/simulación de Arduino en FPGA - Índice y Conclusiones


Este tutorial se ha creado como complemento a la charla titulada Codiseño y cosimulación basado en FPGAs para plataforma Arduino del Open Source Hardware Convention 2011.

Tiene seis partes:



Conclusiones*:
  1. Emular el microcontrolador de Arduino o cualquier otro en una FPGA permite personalizar ancho de buses, número y tipo de salidas y entradas, frecuencias de reloj, tamaño de memoria o puertos de comunicación e inhabilitar los recursos que no sean utilizados para optimizar y adaptar el hardware al proyecto (y no viceversa).
  2. Simular el proyecto completo, hardware y software, a nivel de señal desde un PC sin necesidad de programación en una FPGA es una ventaja tremenda hasta para proyectos básicos de Arduino.
  3. Existen otras ventajas de utilizar hardware reconfigurable como son la capacidad de procesado o la protección de obsolescencia pero no son tan importantes en el ámbito DIY/Hardware Libre.
 
Trabajos futuros:
  1. Crear una herramienta open-source que permita configurar un sistema completo, añadir módulos con funcionalidades, comunicaciones, co-procesamiento, etc. El prototipo se llama Oruga y está escrito en Javascript: http://oruga.tk
  2. Crear módulos en HDL (VHDL, Verilog...) administrados desde Arduino, independientes de ellas o conectados a otros módulos como, por ejemplo:
    1. Salida PWM con frecuencia configurable.
    2. Entrada RC-PPM de varios canales desde una misma señal.
    3. Salida VGA.
    4. Memoria externa.
    5. Generadores de ondas.
    6. Entrada analógica.
    7. Comunicación genérica de protocolos serie como I2C o SPI.
    8. Generación y mezcla de sonido y otras funciones DSP.
    9. Módulos de coprocesamiento.
*Las conclusiones se ponen junto al índice porque son un buen resumen.

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.









miércoles, 14 de septiembre de 2011

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

Compilar programas Arduino para simulación

En capítulos anteriores se ha simulado un programa Arduino previamente cargado. Para programar la FPGA con un sketch personalizado conviene diferenciar dos métodos:
  1. Modificar los bits directamente de la memoria en la FPGA y reemplazar el sketch cargado.
  2. Modificar el código inicial con el que se sintetiza el diseño del microcontrolador.
El primer método sólo sirve para la ejecución del sketch pero no habría forma de probarlo previamente. Es la forma de programar con el Arduino IDE modificado por Gadget Factory. Sólo hay que seleccionar la "board" aplicable en el menú Tools de Arduino. Por ejemplo Gadget Factory Papilio One 500K Board.

Para proyectos complejos es necesario simular y para ello el código del sketch debe ir previamente escrito en el proyecto (en VHDL).

El código inicial se guarda en bloques de memoria que lleva la FPGA, (de tipo BRAM). En el core se instancian bloques de tipo RAMB16_S18, que es un componente que proporciona Xilinx. En la hoja de características de la FPGA hay más explicaciones sobre los diferentes tipos de memoria que se pueden instanciar.

En el código suministrado se instancia el componente de memoria 8 veces: RAM_Word0 a RAM_Word7. En el código de inicialización de la instancia (ver fichero sources/Memory/XPM8Kx16.vhd) es posible dar los datos iniciales de cada bit, son los registros INIT_00 a INIT_3F.


RAM_Word0:component RAMB16_S18
generic map (
INIT => X"00000", -- Value of output RAM registers at startup
SRVAL => X"00000", -- Ouput value upon SSR assertion
WRITE_MODE => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE
-- The following INIT_xx declarations specify the intial contents of the RAM
-- Address 0 to 255
INIT_00 => PM_Inst_RAM_Word0_INIT_00,
INIT_01 => PM_Inst_RAM_Word0_INIT_01,
INIT_02 => PM_Inst_RAM_Word0_INIT_02,
...


En cada registro se pueden almacenar 64 dígitos hexadecimales, es decir 4x64 = 256 bits. En cada bloque hay 64 (3F) registros, por lo que hay 16.384 bits en cada bloque. Juntando los 8 bloques inicialmente instanciados, se pueden utilizar 16KBytes de memoria para programas Arduino.

PM_Inst_RAM_Word0_INIT_XX son constantes, que están definidas en el fichero sources/Memory/prog_mem_init.vhd:

constant PM_Inst_RAM_Word0_INIT_00 : bit_vector(0 to 255) := x"0053940C0053940C0053940C0053940C0053940C0053940C0053940C0030940C"; constant PM_Inst_RAM_Word0_INIT_01 : bit_vector(0 to 255) := x"0053940C0053940C0053940C0053940C0053940C0053940C0053940C0053940C";
...

Los caracteres hexadecimales son el sketch compilado para ser utilizado en ATmega.

En el fichero hardware\tools\butterfly_platform\Makefile del Arduino IDE modificado, se modifica la siguiente línea y se cambia por la ruta correcta:

PAPILIO_SIM_PATH = "C:/Arduino-Soft-Core/sources/Memory/prog_mem_init.vhd"

Si alguna de las carpetas tiene un espacio, es importante añadirle el carácter \ antes.

Ahora se selecciona la Gadget Factory Papilio Custom Board del menú Tools y al pulsar "Upload" se generará el nuevo fichero prog_mem_init.vhd.



Sólo queda repetir los pasos de los capítulos anteriores del tutorial para simular el sketch.

En el siguiente capítulo se modificará el diseño del proyecto para crear módulos de aceleración.


Parte I - Introducción
Parte II - Emulación del modelo RTL de Arduino
Parte III - Simulación con ModelSIM (si se usa una versión de pago)
Parte IV - Simulación con ISim (integrado en Xilinx ISE)
Parte V - Compilar programas Arduino para simulación
Parte VI - Acelerar, personalizar y optimizar Arduino