Rust en el ESP32 dejó de ser un experimento hace tiempo. Hoy el ecosistema
esp-rs es estable y sorprendentemente agradable, con una ventaja enorme: el
compilador te evita errores de memoria y de concurrencia que en C te cuestan una
tarde de depuración.
La contrapartida: hay que aprender Rust y montar una toolchain aparte.
Dos rutas, no una
| Ruta | Qué es | Ideal para |
|---|---|---|
esp-idf-hal | Rust sobre ESP-IDF, con std | Reutilizar ESP-IDF, Wi-Fi, proyectos grandes |
esp-hal | no_std, sin ESP-IDF | Control total, binarios pequeños, async |
embassy | Framework async sobre esp-hal | Tareas concurrentes elegantes |
La regla: si quieres Wi-Fi fácil y las APIs de Espressif, esp-idf-hal. Si
quieres exprimir y no te importa lo no_std, esp-hal + embassy.
Toolchain
El instalador oficial es espup:
cargo install espup
espup install # instala targets Xtensa y RISC-V
. $HOME/export-esp.sh # o el script que genera
Y para flashear, cargo-espflash:
cargo install cargo-espflash
cargo espflash flash --monitor
Versión actual del HAL: esp-hal 1.2.0.
Ejemplo: blink con esp-idf-hal (con std)
use esp_idf_svc::hal::delay::FreeRtos;
use esp_idf_svc::hal::gpio::PinDriver;
use esp_idf_svc::hal::peripherals::Peripherals;
fn main() -> anyhow::Result<()> {
esp_idf_svc::sys::link_patches();
let peripherals = Peripherals::take()?;
let mut led = PinDriver::output(peripherals.pins.gpio2)?;
loop {
led.set_high()?;
FreeRtos::delay_ms(1000);
led.set_low()?;
FreeRtos::delay_ms(1000);
}
}
Fíjate en el detalle: el compilador te obliga a declarar el pin como salida
antes de escribir. En C, un pinMode olvidado es un bug silencioso; aquí no
compila.
Async con embassy
Lo mejor del camino no_std es embassy: tareas asíncronas de verdad, sin
loop() ni máquinas de estado a mano.
#[embassy_executor::task]
async fn parpadeo(mut led: Output<'static, Gpio2>) {
loop {
led.toggle();
Timer::after_millis(500).await;
}
}
Dos tareas que «duermen» a la vez sin bloquearse: es la forma moderna de escribir firmware concurrente.
Ventajas reales
- Seguridad: sin use-after-free, sin carreras de datos, sin null.
- Concurrencia honesta: si compila, normalmente no se pisa la memoria.
- Binarios pequeños en
no_std. cargo: dependencias, tests y documentación en un solo sitio.
Inconvenientes
- Curva de aprendizaje de Rust (préstamos,
async,no_std). - Ecosistema más joven que Arduino: menos librerías listas.
- Toolchain aparte:
espup, targets, versión de Rust concreta. - Menos ejemplos y tutoriales que en C/C++.
¿Cuándo elegirlo?
Sí:
- Te importa la fiabilidad y quieres menos bugs raros.
- Ya sabes Rust (o quieres aprenderlo en serio).
- Necesitas async real o binarios muy pequeños.
- Es un proyecto a largo plazo donde el mantenimiento importa.
No:
- Es tu primer contacto con microcontroladores: empieza en Arduino o MicroPython.
- Necesitas una librería concreta que solo existe en C++.
- Vas con prisa.
Resumen
- Dos rutas:
esp-idf-hal(constd, sobre ESP-IDF) yesp-hal(no_std), másembassypara async. - Toolchain con
espupy flasheo concargo-espflash. - El compilador evita errores que en C son silenciosos.
esp-halva por la 1.2.0 y el ecosistema ya es maduro.- Merece la pena si te importa el mantenimiento y la seguridad.
Siguiente paso: cambiamos de tercio con los IDE: cuál usar y por qué. O vuelve al hub de la serie.