Back to Blog

July 7, 2025

Getting Started with Rust on the ESP32: A Developer's Guide

So, you've got an ESP32-WROOM-32 and you're ready to dive into the world of embedded systems with Rust. You've made an excellent choice! Combining the power and safety of Rust with the versatility of the ESP32 opens up a universe of possibilities for IoT, home automation, and beyond.

This guide will walk you through the entire setup process, from connecting the hardware to flashing your first "Hello, World!" program. We'll explain the purpose of each tool and configuration step, ensuring you understand not just what you're doing, but why you're doing it.


First, What is the ESP32?

Before we get our hands dirty, let's quickly recap what makes the ESP32 so special. The ESP32 is a low-cost, low-power microcontroller that has become a favorite among hobbyists and professionals alike.

Here's why it's a great platform for your projects:

  • Dual-Core Processor: Plenty of power for complex tasks.
  • Integrated Wi-Fi & Bluetooth: Perfect for connected IoT devices right out of the box.
  • Lots of GPIO Pins: General-Purpose Input/Output pins allow you to connect a vast array of sensors, motors, displays, and other peripherals.

In short, it's a powerful and affordable chip that's ideal for building embedded systems with Rust. The specific model we're using, the ESP32-WROOM-32, is one of the most common and well-supported variants.


Step 1: Install the USB-to-UART Bridge Driver

The very first step is to enable communication between your computer and the ESP32. Your ESP32 board uses a special chip to handle USB communication, and your operating system needs a driver to understand it.

The Purpose of This Step

The CP2102 chip on your board acts as a translator, converting USB signals from your computer into UART signals that the ESP32's processor can understand. Without the correct driver, your computer won't recognize the device, and you won't be able to send code to it.

Installation

  1. Download the Driver: Head to the official Silicon Labs website to get the necessary VCP (Virtual COM Port) drivers.

  2. Install the Driver:

    • Unzip the downloaded file.
    • Run the installer executable (e.g., CP210xVCPInstaller_x64.exe for 64-bit Windows).
    • Follow the on-screen prompts. A reboot is recommended to ensure the driver is fully loaded.

Once installed, when you plug in your ESP32, your computer will assign it a COM port, making it available to programming tools.


Step 2: Set Up Your Rust Environment for Embedded Development

Now, let's get the Rust toolchain ready. We need not only the standard Rust compiler but also specialized tools for building and flashing code for the ESP32's unique architecture.

Install the Rust Target

The ESP32 uses an Xtensa architecture, which is different from the x86 architecture of your PC. We need to tell Rust to download the necessary components to cross-compile our code for this target.

rustup update
rustup target add xtensa-esp32-espidf

Install espup

espup is the official installer for the Rust on ESP development toolchain. It simplifies the process of downloading the correct Rust compiler version, the ESP-IDF (Espressif's IoT Development Framework), and other necessary utilities.

The Purpose of This Step: espup ensures that you have a consistent and working set of tools tailored for ESP development, saving you from the headache of manually installing and configuring everything.

cargo install espup
espup install

This command will install the necessary toolchains, including the Clang compiler required by the ESP-IDF.

Install espflash and ldproxy

  • espflash is a utility for flashing (uploading) your compiled Rust application to the ESP32 and monitoring its output.
  • ldproxy is a tool that helps the Rust compiler link your code with the libraries provided by the ESP-IDF.
cargo install espflash
cargo install ldproxy

Step 3: Create Your First Rust Project with a Template

The best way to start a new project is by using the official esp-idf-template. This template comes pre-configured with everything you need to build a functional application.

The Purpose of This Step: Using a template saves you from writing boilerplate code and complex configuration files from scratch. It provides a solid, community-approved foundation for your project, letting you focus on writing application logic.

Generate the Project

  1. Use cargo-generate: This command will clone the template and customize it for your new project. If you don't have it installed, run cargo install cargo-generate.

    cargo generate esp-rs/esp-idf-template cargo
    
  2. Follow the Prompts: The generator will ask you a few questions:

    • Project Name: Enter a name, for example, esp-blink.
    • ESP-IDF Version: Choose the recommended version.
    • MCU: Select your specific chip. For this guide, choose esp32.
    • Configure advanced options?: You can say no for now.

This will create a new directory (esp-blink) with a ready-to-use Rust project.

Enter the Project Folder

Navigate into your newly created project directory:

cd esp-blink

Step 4: Configure, Build, and Flash!

The template has done most of the heavy lifting, but it's crucial to understand the configuration files it created.

Understanding the Configuration

Your project now contains two important configuration files:

  1. .cargo/config.toml: This file tells Cargo how to build and run your code.

    • target: Sets the default compilation target to xtensa-esp32-espidf.
    • runner: Specifies that espflash flash --monitor should be used to upload the code and open a serial monitor. This lets you run your entire flash-and-monitor workflow with a single cargo run command.
    • linker: Points to ldproxy to handle the final linking step.
  2. Cargo.toml: This is your standard Rust project manifest. The template populates it with essential dependencies:

    • esp-idf-sys: Provides the low-level bindings to the ESP-IDF.
    • esp-idf-hal: Gives you safe, high-level Rust abstractions for the ESP32's peripherals (like GPIO, Wi-Fi, etc.).
    • esp-idf-svc: Offers higher-level services like networking and event loops.

Build and Flash Your Application

Thanks to the runner configured in config.toml, you can build, flash, and monitor your application with a single command:

cargo run

When you run this, Cargo will:

  1. Build your Rust code for the xtensa-esp32-espidf target.
  2. Flash the resulting binary onto your ESP32 using espflash.
  3. Monitor the serial output from the device.

You should see the "Hello, World!" message from the template's main.rs file printed in your terminal. Success! 🎉

// src/main.rs
use std::thread::sleep;
use std::time::Duration;

use esp_idf_svc::sys::link_patches;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::gpio::*;

fn main() {
    // Ensure runtime patches are linked correctly
    link_patches();

    // Enable logging
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("Starting LED blink example...");

    // Access GPIO peripherals
    let peripherals = Peripherals::take().unwrap();
    let mut led = PinDriver::output(peripherals.pins.gpio2).unwrap();

    loop {
        log::info!("LED ON");
        led.set_high().unwrap();
        sleep(Duration::from_millis(500));

        log::info!("LED OFF");
        led.set_low().unwrap();
        sleep(Duration::from_millis(500));
    }
}