Portabilidad de Embedded Rust

Arduino como plataforma de programación es genial, porque los programas son iguales en todos los micro-controladores que soporta. No tenemos que aprender un dialecto diferente para cada uno de ellos. Embedded Rust es la solución de Rust para micro-controladores: ¿Nos permite aprender una sola cosa para todos los micro-controladores, tal y como nos permite Arduino?

Expresado más subjetivamente: ¿Merece la pena aprender Embedded Rust?

Vamos a comprobarlo con un experimento:

La prueba

Como no soy ningún experto con Embedded Rust (Recordemos que estoy decidiendo si merece la pena aprenderlo) vamos a hacer algo sencillo: Crearemos el archi-famoso programa blink para 3 plataformas intentando, hasta donde se pueda, usar el mismo programa.

Esp32c6 (risc), Attiny85, y RaspberryPi Pico W, con sus respectivos leds, listos para la prueba.

He escogido los 3 micro-controladores que más uso. No tengo un arduino-uno, pero el Attiny85 utiliza el mismo HAL que todos los Arduino, así que será el representante de esta familia.

Resultado

Esta imagen muestra el código resultante para cada micro-controlador y sin necesidad de leer el código; habla por si sola.

Dos son muy parecidos tanto en tamaño como en formato. Pero RaspberryPi Pico tiene mucho más código, mientras que el Esp32c6 y el Attiny tienen menos código, más sencillo y más similar.

Intentaremos encontrar una justificación, pero el resultado de la prueba es este: El código no es tan portable como lo sería con la plataforma Arduino.

HAL (Hardware Abstraction Layer)

En la arquitectura de Embedded Rust existe una capa (un Crate) cuya finalidad es hacer que todos los micro-controladores se usen igual: el crate embedded_hal.

En teoría en la medida en que usemos sólo embedded_hal todos los controladores se programan igual.

Entonces; ¿Qué falla?

1º Inicializaciones

Como la propia documentación asegura aquí: las inicializaciones y la configuración no forman parte del HAL

Todo ese código adicional en la RaspberryPi Pico son inicializaciones. Y como no son estándar en cada placa son diferentes.

  • Attiny85 parece que no tiene, pero está en un fichero que procesa el compilador (que es la única diferencia entre los diferentes arduinos.
  • Esp32c6 tiene una línea mágica esp_idf_svc::sys::link_patches(); que configura cosas.
  • RaspberryPi Pico: tiene un montón de código, que es esa diferencia tan grande que hemos visto con los otros dos micro-controladores.

Por tranquilizar a los lectores: todos los Micro-controladores tienen generadores de dicha configuración.

2º Faltan Traits

Embedded_hal está compuesto de traits que puede o no implementar cada micro-controlador particular. Por ejemplo los pines de RaspberryPi Pico no tienen el método Toggle. Esto es porque sus pines no tienen estado, Así que tenemos otra diferencia: tenemos que usar set_high y set_low alternativamente como se hace en Arduino. Los 3 hubieran podido usar estas instrucciones.

Esto a su vez es una ventaja. Si una placa no tiene pines ADC pues no tiene implementados esos traits y en tiempo de compilación ya se detecta.

De hecho si hay unos pines que tienen PWD y otros no, el trait PWD estará disponible solo para esos pines y el auto-completado del editor ya nos lo dejará claro.

Esta es una tremenda ventaja en realidad, puesto que el código de Arduino compila obviando estas limitaciones, pero solo para fallar en tiempo de ejecución.

3º Madurez

Otra cosa que hemos visto diferente es que el método toggle tiene una firma diferente, en una devuelve Error y en otra no.

Tras un poco de investigación vemos que las dos están bien, pero en Espressif se está usando la versión2 de ese trait, mientras que Arduino está usando la versión deprecada.

¿Estos cambios van a ser frecuentes? Pues: Si.

NOTE This HAL is still is active development. Expect the traits presented here to be tweaked, split or be replaced wholesale before being stabilized, i.e. before hitting the 1.0.0 release.

crate Embedded_hal

Vamos por la versión 0.2.7 y no hay promesa de estabilidad hasta llegar a la 1.0.0

Rust Standard Library

El último atentado contra la portabilidad es la librería estándar: STD

Esta librería tiene cosas que son demasiado complicadas para un procesador como un attiny85, como la gestión de concurrencia de alto nivel. Esto es util en un ESP32, que tiene capacidad de sobra para estas complicaciones. Pero ahora vemos que un ESP32 tiene dos dialectos, con o sin STD.

  • Con STD se comporta como un Rust normal y corriente «de PC» pero con acceso al HAL.
  • Sin STD se comporta como un Arduino normal

STD hace que el código sea sencillo, solo hay que mirar el delay de Esp32. Usa std::Duration y sin lugar a dudas si hubiese escogido hacer el programa sin STD ese codigo ya no funcionaría.

Conclusión

Merece la pena aprenderlo: SI

Lo usaría si profesionalmente: No. Si acaso con el ESP32 porque Espressif está poniendo toda la carne en el asador de Rust, además IDF (lo que hay ahora) realmente no me gusta.

Referencias

Actualización

Ya no son 3 si no 5 los blinks que tenemos en el repositorio. Los nuevos llegados son:

  • El ESP32 (con procesador Xtensa (sin modificaciones necesarias partiendo del ESP32C6 RiskV)
  • El Attiny84, que es una versión con mas pines y menos popularidad que el Attiny45. Hemos descubierto que el ejemplo del Attiny45 se ha hecho usando el Board Crate en vez del HAL Crate. Como consecuencia vemos los pines numerados como aparecen en la tarjeta D1, D2… en vez de PA1, PB1… El Board Crate es realmente más cómodo.

Deja un comentario