Post

Rust on ESP32: From Blinky to Async Wi-Fi

A step-by-step guide to writing Rust firmware for the ESP32 using the Embassy async runtime — covering toolchain setup, GPIO, serial output, and a working async Wi-Fi client that connects to a network and fetches a URL.

Rust on ESP32: From Blinky to Async Wi-Fi

🚧 Work in Progress — This post is a placeholder. Full content coming soon.

The ESP32 is arguably the most popular microcontroller for hobbyist and prototyping work — dual-core Xtensa LX6, Wi-Fi, Bluetooth, cheap, and abundant. Rust support has matured rapidly in 2024–2025. The esp-hal crate and Embassy async runtime now make it possible to write safe, async Wi-Fi firmware without touching the Espressif SDK (ESP-IDF) at all. This post walks through the journey from a blinking LED to an async HTTP request.

Planned Content

1. The ESP32 Rust Ecosystem

  • Two approaches: std (ESP-IDF bindings) vs no_std (bare metal with esp-hal)
  • Why no_std + Embassy is the more interesting path
  • Supported chips: ESP32, ESP32-S3, ESP32-C3 (RISC-V), ESP32-C6

2. Toolchain Setup

1
2
3
cargo install espup
espup install                    # installs Xtensa Rust fork + LLVM
cargo install cargo-espflash
  • espflash for flashing over USB-UART
  • probe-rs for JTAG debugging (ESP32-S3 only)

3. Blinky: Hello World in esp-hal

  • esp-hal HAL structure
  • Output GPIO with type-state API
  • Using esp-println for UART debug output
  • Understanding the boot process: ROM bootloader → app

4. Introducing Embassy

  • Cooperative async executor for embedded
  • #[embassy_executor::task] macro
  • Timer::after_millis() — async delay without blocking
  • Porting the Blinky to async

5. Async Wi-Fi with esp-wifi

1
2
3
4
let wifi = Wifi::new(peripherals.WIFI, &mut rng, &clocks);
let (mut controller, interfaces) = create_network_interface(wifi);
controller.start().await.unwrap();
controller.connect(&config).await.unwrap();
  • Scanning for networks
  • Connecting with WPA2
  • Getting an IP address via DHCP
  • Making an HTTP GET request with reqwless

6. Real-World Patterns

  • Sharing the Wi-Fi stack between tasks with embassy-sync channels
  • Deep sleep and wake-on-timer for battery-powered sensors
  • OTA firmware updates via Wi-Fi

Hardware Used

  • ESP32-S3-DevKitC-1 (preferred: native USB, JTAG support)
  • Or any generic ESP32 DevKit with CP2102 USB-UART

Previous in series: Getting Started with Embedded Rust on ARM Cortex-M (coming soon)

This post is licensed under CC BY 4.0 by the author.