El Propeller, un microcontrolador nada habitual

por Eduardo J. Carletti

¿Qué es el Propeller?

El Propeller es un microcontrolador producido por Parallax Inc. Como muchos chips de este tipo, posee una sección de proceso, generación de reloj, contador de sistema, puertos de entrada/salida, memoria RAM y ROM… pero aquí termina toda similitud con los microcontroladores conocidos.



El Propeller posee una novísima arquitectura, que contiene ocho procesadores que trabajan cooperativamente y comparten los pines de salida y otros recursos.
Cada uno de estos 8 procesadores —a los que Parallax ha bautizado «cog»— es de 32 bits, con una velocidad de proceso de 20 MIPS (millones de instrucciones por segundo) usando un pulso de reloj de 80 MHz. Es decir, en un momento en que están trabajando todos los cogs, tenemos una capacidad de proceso de 160 MIPS.
Cada procesador tiene su propia RAM local de 2 Kb (512 registros de 32 bits). También existe una memoria común, compartida, que se divide en dos secciones: una RAM de 32 Kb y una ROM de 32 Kb.
La ROM contiene rutinas preprogramadas, como la de arranque o «bootstrap», un interpretador y recursos tales como generadores de caracteres, tablas matemáticas, etc.

Pero no es regrabable y no está pensada para contener el programa de usuario.


¿Entonces… cómo funciona esto?

Uno se pregunta enseguida… ¿cómo se programa este chip? Sin memoria de programa reprogramable, como las flash que son habituales en los microcontroladores de hoy, ¿dónde se alojan las instrucciones del microcontrolador, es decir, lo que hemos programado?

Veamos el concepto de Parallax para la programación de este microcontrolador.

Bootstrap o rutina de arranque

Por cierto, no es una novedad para los diseñadores con microcontroladores: una pequeña rutina preprogramada se ocupa de cargar el programa principal en el chip.
¿Pero dónde se guarda este programa principal?
Muchos microcontroladores que conocemos cargan su programa en la memoria flash, pero en el Propeller, como en las computadoras convencionales del tipo de nuestra PC, el programa se instala en la RAM. El programa de arranque que reside en la ROM se comunica a través de una interfaz serie (puede ser una interfaz serie convencional o transformada a USB por un chip convertidor) y descarga el programa en la RAM.
«Ah, pero entonces este chip sólo funciona conectado a una computadora, para que ésta le envíe el programa…»
No necesariamente: una vez probado y en funcionamiento, el programa se aloja en una memoria externa EEPROM de tipo serie desde donde el Propeller, en el arranque, copia el programa a la RAM. Por esta razón, casi siempre veremos asociado al Propeller con una memoria EEPROM serie de capacidad suficiente, como la 24LC256 (32K x 8).
Interesante.

Secuencia de arranque



Placa de prueba del Propeller

Después del inicio (reset), el Propeller arranca funcionando con un reloj en modo lento (de unos 20 KHz), espera 50 milisegundos, pasa el reloj a modo rápido (de unos 12 MHz), y entonces comienza a ejecutar su rutina interna de arranque, o Boot Loader, en el procesador número 0 (cero).
A través de los pines P30 y P31, esta rutina observa si existe comunicación con un procesador principal o «host», tal como una PC. Si esta comunicación se establece, se genera un intercambio con el programa en la PC, que resulta en la descarga de un programa hacia la RAM principal o, alternativamente, hacia la EEPROM externa auxiliar, de 32 Kb.
Si no se detecta la presencia de una computadora principal que aporte el programa, la rutina de arranque busca una EEPROM serie exterior en los pines P28 y P29. Si esta memoria existe, copia su contenido completo en la memoria RAM del Propeller.
Si no se pudo comunicar con una computadora principal, y tampoco detecta esta memoria EEPROM, el Propeller pasa a un modo de apagado con todos los pines definidos como entradas.
Si en cambio se logró descargar el programa a la RAM, ahora el procesador 0 (o cog 0) carga el interpretador y comienza a correr el código del usuario.

¿Interpretador? Oh, oh…

¿Cómo que corre un interpretador, se pregunta uno de inmediato? ¿No hay un código de programa en idioma binario? ¿Qué clase de microcontrolador es éste?
Tranquilos. El programa se puede componer de instrucciones en Spin, que es un lenguaje de alto nivel específico del Propeller que corre por medio de un interpretador, y también de componentes de bajo nivel, escritos en el lenguaje ASM del Propeller.
Todo lo que está en lenguaje Spin es interpretado por un cog en el que corre el interpretador, mientras que lo que aparezca en idioma binario (compilado a partir del ASM de Propeller) se ejecuta en otro cog.


Veamos el hardware

Ya vimos cómo se maneja el concepto de programa de este chip, veamos entonces cómo es a nivel físico.

El diagrama en bloques del Propeller tiene tantos elementos que deja ver muy poco de sus detalles. De todos modos, lo muestro aquí:



Será mejor que lo veamos por partes.

Paso a paso, la arquitectura del Propeller

Dijimos ya que el Propeller contiene ocho procesadores, o cogs, que se identifican con los números 0 a 7. Todos contienen los mismos componentes: un procesador, una RAM local de 2 K bytes —que se estructura en 512 registros de 32 bits—, dos asistentes de E/S (Entrada/Salida) y PLLs (lazos de enganche de fase), un generador de video, un registro de salida de E/S, un registro de dirección de E/S, y otros registros que no se representan en el diagrama que sigue. El procesador se conecta con las barras de direcciones, de datos, del contador de sistema y de entradas (en inglés, lo que llamamos «barra» es «bus»). Los asistentes de E/S están conectados a las entradas y las salidas.



Diagrama de un cog

Los ocho cogs pueden realizar tareas independientes y también pueden trabajar en tareas cooperativas.



Detalle de cuatro de los cogs y su interconexión

Estas explicaciones suenan muy bien en términos generales, pero la verdad es que no dicen mucho, así que uno se pregunta: ¿cómo funciona esto?
¿Cómo acceden sin conflicto los procesadores que trabajan simultáneamente a los recursos compartidos, como la RAM principal y la ROM? ¿Cómo escriben en los puertos de salida? ¿Para qué son los generadores de video que tiene cada procesador? ¿Cómo atienden
los procesadores a los sucesos que ocurren en el mundo exterior?
Aportemos algunas respuestas.

Sucesos del mundo real: interrupciones… no hay

Debido a que posee varios procesadores, el sistema no tiene necesidad de usar un mecanismo de interrupciones: asigna tareas importantes a algunos cogs, mientras que mantiene libres a otros cogs para atender los sucesos que se presentan. Sólo es necesario asignar algunas patas de E/S a esas tareas de alta velocidad. Los cogs tienen instrucciones especiales para esperar por un suceso externo, como WAITPEQ, que espera hasta que un pin esté en un determinado estado, o WAITPNE, que espera lo contrario, que el pin no esté en ese estado. También, obviamente, se puede recurrir a una técnica de sondeo continuo de las líneas, lo que en inglés se llama «polling».

Compartir las entradas y salidas

El propeller tiene 32 patas dedicadas a entrada/salida. De éstas, sólo cuatro tienen una función predefinida, y esto sólo durante el inicio o Boot Up, y luego quedan libres para su uso a gusto del programador. Las 28 restantes son de propósito general.
Los pines utilizados durante el boot son:

  • P28 – conexión SCL del bus I2C a una EEPROM externa opcional.
  • P29 – conexión SDA del bus I2C a una EEPROM externa opcional.
  • P30 – Señal Tx (Transmisión) de la interfaz serie con el computador principal.
  • P31 – Señal Rx (Recepción) de la interfaz serie con el computador principal.

Cada cog tiene su registro propio de dirección de las E/S, de 32 bits (que define si es entrada o salida), y un registro de salida, también de 32 bits. No hay una protección de hardware que impida que distintos cogs usen el mismo pin para usos diferentes; esto lo debe controlar el programador.



Las salidas de los cogs se unen entre sí en forma de «o» inclusiva (compuerta o), y lo mismo pasa con las definiciones de dirección de las E/S.
Debido a esto, la definición de la dirección de cada pin y de sus niveles de salida (si son salidas) cumple las siguientes reglas:

  • A. Un pin del Propeller es una entrada si todos los cogs activos lo tienen definido como entrada. Si un único cog activo lo define como salida, el pin será salida.
  • B. Una línea de un pin de salida irá a bajo sólo si todos los cogs que lo tienen definido como salida la ponen en bajo.
  • C. Una línea de un pin será alta si cualquier cog activo que la tiene definido como salida la pone en alto.

En base a esta lógica, un cog puede dejar libres para el uso de los otros cogs los pines de E/S —quedando sin ninguna influencia sobre ellos— sólo con poner a cero su registro de dirección de E/S y a cero su registro de salida.

Generadores de video

No he encontrado precisiones sobre por qué cada procesador tiene un generador de video y tampoco cómo es que puede generar video sin una RAM para mantener la imagen. Es de suponer que si se genera video en cada procesador, se pueden crear distintas imágenes que se sumen o que se alternen.

Simultaneidad y reloj del sistema

Los ocho cog están en funcionamiento con el mismo reloj del sistema, de modo que mantienen la misma referencia en el tiempo.
El reloj del sistema alimenta casi todos los componentes del chip Propeller. La señal del reloj del sistema se produce en tres fuentes posibles: el oscilador RC interno, el lazo de enganche de fase del reloj (PLL), o el oscilador a cristal, que puede ser interno o un dispositivo externo que genere los pulsos de reloj. La fuente del reloj se determina por los valores definidos en el registro CLK, que se pueden seleccionar al compilar y también durante la ejecución del programa.


Los únicos componentes que no usan directamente el reloj del sistema son el Hub y las barras (o Buses), donde la frecuencia del reloj del sistema está dividida por dos.
La funcionalidad de los cog para trabajar en forma simultánea está bajo control del usuario. El programa escrito por el usuario tiene control total sobre cómo y cuándo se utiliza cada cog. Pueden ser programados, entonces, para realizar tareas simultáneamente, independientes o con la coordinación de otros cogs, así como también hacer que cualquiera de los cogs arranque y se detenga durante el funcionamiento del programa.

Compartir los recursos

Existen dos tipos de recursos a compartir en el Propeller: recursos de uso común, y recursos de uso momentáneamente exclusivo. Los recursos comunes, como los pines de E/S y el contador del sistema, permiten el acceso conjunto de varios cogs en todo momento, mientras que los recursos de uso momentáneamente exclusivo, como la RAM y ROM principales, los registros de configuración, etc., pueden accederse desde todos los cogs, pero solamente puede ser utilizado por uno de ellos a la vez.
¿Cómo gobierna el Propeller este acceso a los recursos de uso exclusivo, de a uno por vez? Existe un dispositivo llamado Hub, que es el que controla qué cog puede acceder, por turno, a los recursos exclusivos.
La palabra «hub», en inglés, se refiere al cubo en el extremo del eje de un automóvil, donde se fija la rueda (entre otros ejemplos), y en electrónica a un distribuidor o múltiple: en este caso sería como el distribuidor de bujías de un automóvil.
El dispositivo se representa en el esquema en bloques, justamente, como un objeto circular rodeado por los cogs.



El Hub va dando acceso exclusivo a cada «cog» de manera secuencial, comenzando por el cog 0, y así en sucesión hasta el cog 7, sin importar cuántos cogs estén activos. Cuando se desea un acceso exclusivo a los recursos para alguno de los cogs, se utilizan semáforos, controlados por programa.



Hub, Registros de configuración, generación de reloj, RAM, ROM, semáforos

La memoria principal

El mapa de memoria principal cubre 64 Kbytes sin ninguna división en bloques, y se la puede direccionar de manera continua. Esto evita los esquemas de paginado en secciones de código, datos o variables que se observan en otros microcontroladores.
La memoria principal tiene dos partes funcionales: la primera mitad de las direcciones está ocupada por 32 Kbytes de RAM y la segunda mitad por 32 Kbytes de ROM.
La RAM es de propósito general, y en ella se juntan programa, datos y variables. Cuando se descarga el programa desde una PC a través de la interfaz serie, o se lo copia desde los 32 Kbytes de la EEPROM auxiliar externa, se puede utilizar por completo esta memoria.
Las primeras ubicaciones se ocupan con los datos de inicialización que utiliza el intérprete, el espacio que sigue es utilizado por el código ejecutable y datos del programa, y el resto del espacio se puede utilizar para localizar variables.
En los 32 Kbytes de ROM están pregrabados recursos de programa y datos vitales para el funcionamiento del Propeller, entre ellos el programa de arranque y el intérprete, tablas de definición de caracteres y funciones matemáticas.
La primera mitad de la ROM contiene las plantillas píxel a píxel de un juego de 256 caracteres de 16 píxeles de ancho por 32 píxeles de alto. Estos caracteres se pueden utilizar para exhibir en pantallas de video, LCD gráficos, para imprimir, etc. Además de letras comunes, se han definido cantidad de caracteres auxiliares para uso en diagramas esquemáticos, símbolos griegos y varias flechas y formas predefinidas.

Entradas y Salidas

El chip Propeller tiene 32 pins de E/S para utilizar en señales de entrada, salida y control. Como ya indicamos, de los 32 pines, 28 —de P0 a P27— son para propósito general y 4 —P28 a P31— tienen un uso especial durante el arranque, utilizándose para la comunicación con la PC y el acceso a la EEPROM externa. Pero luego se los puede utilizar para propósito general.

Contador del sistema

El contador del sistema es un contador de 32 bits de acceso global, lectura solamente, cuyo conteo se incrementa cada ciclo del reloj de sistema. Los cogs pueden leer este contador del sistema para hacer cálculos referidos al tiempo y también disponen del comando WAITCNT para producir retardos en sus programas. El contador del sistema es un recurso común: todos los cog lo pueden leer al mismo tiempo. El contador del sistema no se inicializa durante el arranque debido a que la forma de usarlo es calculando el tiempo de manera diferencial. Si un cog necesita medir el tiempo de un suceso específico lo único que debe hacer es leer el valor inicial del contador en ese momento y comparar los valores posteriores leídos del contador contra el tiempo inicial.

Disposición habitual básica

La disposición típica de circuito nos muestra al microcontrolador conectado a una memoria EEPROM de 32 Kbytes y a una interfaz serie.

La conexión de la memoria EEPROM con el microcontrolador es de tipo serie de dos líneas, como en todas estas memorias, mediante un bus I2C.



El esquema muestra un ejemplo del conexionado de los elementos, y en este caso la comunicación serie se realiza a través de un convertidor de niveles MAX232, que se ocupa de adaptar los niveles lógicos que utiliza la PC en su interfaz serie RS232 a los niveles TTL del microcontrolador.

Bajo consumo de energía

El consumo de potencia de un dispositivo se debe tener en cuenta, sobre todo en sistemas alimentados por baterías, porque cuanto más rápido trabaja el microcontrolador más consumo se produce. Dado que la mayor parte del consumo de los circuitos actuales integrados en los chips se produce en los cambios de estado de las señales (o flancos), al aumentar la frecuencia de reloj para reducir el tiempo en que se ejecutan las instrucciones se produce un ingente incremento del consumo. El chip del Propeller se ha diseñado para ofrecer una muy alta velocidad de proceso en sistemas embebidos pero con bajo consumo de energía.
El Propeller trabaja con una velocidad de reloj de 80 MHz pero se alimenta con sólo 3,3 voltios, lo que facilita su uso en dispositivos portátiles a baterías. Su consumo se calcula así: 500 uA por MIPS, donde MIPS = (frecuencia en MHz / 4) * cantidad de cogs activos. Digamos que si tenemos los 8 cogs corriendo a 80 MHZ, tendremos 20 * 8 * 500 = 80.000 uA (80 mA). A 3,3 V esto significa 264 mW.

¿Ideal para un robot?

Es evidente que un microcontrolador de estas características podría ser el controlador central ideal para un robot móvil. En lugar de repartir tareas entre varios microcontroladores, como se hace necesario muchas veces, con el consiguiente gasto de espacio de plaqueta, consumo y trabajo de armado, se pueden concentrar las tareas críticas en un único chip, especialmente aquellas relacionadas con el manejo de tiempos muy estrictos. Un caso concreto sería la medición de eco en un emisor/receptor de ultrasonido, atención de una cantidad de servos afectados en los movimientos, procesamiento de imagen, y lectura de múltiples sensores.
Estamos ansiosos por instalar este microcontrolador en un robot y empezar a exigirlo con pruebas más y más comprometidas.

Nota:
La placa de desarrollo con el micro Propeller que nos permitió realizar esta nota nos la donó Micros Parallax Argentina, por gentileza de Aristides Álvarez