Rust on ESP32

I recently got my hands on an ESP32 microcontroller for hacking purpose and successfully ran Rust code on it 🦀

Installing the tools

First, you need to download and install the prebuilt binaries of the Rust and LLVM compiler forks by Espressif or follow yesterday's guide about how to compile Rust and LLVM for ESP32 (warning: Even if Rust and LLVM compile successfully, it's today not possible to build a Rust program for ESP32 on Raspberry Pi due to, but flashing works).

First, you need to install the auxiliary tools:

$ cargo install -f ldproxy espflash espmonitor


$ rustup default esp

Our Rust program

Here is the simplest "Hello world" you can have. As you may have noticed, the std lib is available :)

use embedded_svc::anyerror::*;
use esp_idf_hal::prelude::*;
use esp_idf_svc::sysloop::*;
use std::{thread, time::Duration};

fn main() -> anyhow::Result<()> {
    loop {
        println!("Hello world");
} (from

use std::path::PathBuf;

use embuild::{
    self, bingen,
    build::{CfgArgs, LinkArgs},
    cargo, symgen,

// Necessary because of this issue:
fn main() -> anyhow::Result<()> {

    let cfg = CfgArgs::try_from_env("ESP_IDF")?;

    if cfg.get("esp32s2").is_some() {
        let ulp_elf = PathBuf::from("ulp").join("rust-esp32-ulp-hello");
        symgen::run(&ulp_elf, 0x5000_0000)?; // This is where the RTC Slow Mem is mapped within the ESP32-S2 memory space





name = "rust_on_esp32"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at

# No xtensa in regular compiler yet
default-target = "x86_64-unknown-linux-gnu"

# symbols are nice and they don't increase the size on Flash
debug = true
opt-level = "z"

opt-level = "s"

bind = []

anyhow = {version = "1", features = ["backtrace"]}
esp-idf-sys = { version = "0.20" }
embedded-svc = "0.8.3"
esp-idf-svc = { version = "0.20", features = ["binstart"] }
esp-idf-hal = "0.20"

embuild = "0.24"
anyhow = "1"

.cargo/config.toml (from

target = "xtensa-esp32-espidf"

linker = "ldproxy"

build-std = ["std", "panic_abort"]
build-std-features = ["panic_immediate_abort"]
configurable-env = true # No longer necessary since 1.56, as it was stabilized:
extra-link-arg = true   # No longer necessary since 1.56, as it was stabilized:

ESP_IDF_SYS_GLOB_BASE = { value = ".", relative = true }

ESP_IDF_SYS_GLOB_0 = { value = "/sdkconfig.release" }
ESP_IDF_SYS_GLOB_1 = { value = "/sdkconfig.debug" }
ESP_IDF_SYS_GLOB_2 = { value = "/sdkconfig.defaults" }

sdkconfig.defaults (from


Compiling the Rust program for ESP32

Compiling it is as simple as running:

$ cargo build # or cargo build --release

Flashing the ESP32

Thanks to espflash (which just reached v1.0 🎉) flashing our binary to an ESP32 board is easy:

Press the BOOT button on the ESP32, then:

$ espflash /dev/ttyUSB0 target/xtensa-esp32-espidf/debug/rust_on_esp32 # or target/xtensa-esp32-espidf/release/rust_on_esp32


Finally, getting logs can be achieved with espmonitor that we previously installed:

$ espmonitor --speed 115200 /dev/ttyUSB0

Getting Wi-Fi to work

You can find a more advanced and complex example (from which this Hello-World is derived) with Wi-Fi and a web server on GitHub:

Want to learn more?

Explore the esp-rs GitHub organization and Join the matrix channel.

The code is on GitHub

As usual, you can find the code on GitHub:

1 email / week to learn how to (ab)use technology for fun & profit: Programming, Hacking & Entrepreneurship.
I hate spam even more than you do. I'll never share your email, and you can unsubscribe at any time.

Tags: programming, rust, tutorial, esp32

Want to learn Rust, Cryptography and Security? Get my book Black Hat Rust!