This guide will demonstrate how to set up Rust for ESP32 development and write a simple blinking LED program.
Setting Up Your Development Environment
Step 1: Install Rust
# Install Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Reload your shell
source ~/.bashrc
# Verify installation
rustc --version
cargo --version
Step 2: Install ESP Rust Toolchain
The ESP chips use Xtensa or RISC-V architectures, which require special toolchain support:
# Install espup (ESP Rust installer)
cargo install espup
# Install ESP toolchains
espup install
# This creates ~/.espressif and installs the Xtensa Rust compiler
Add the ESP environment to your shell:
# Add to ~/.bashrc
echo 'source $HOME/export-esp.sh' >> ~/.bashrc
source ~/.bashrc
Step 3: Install Flashing Tools
# Install espflash for uploading firmware
cargo install espflash
# Install cargo-espflash wrapper
cargo install cargo-espflash
Creating Your First Project
Generate Project with esp-generate
# Install project generator
cargo install esp-generate
# Create new project
cd ~/Documents/rust-embedded
esp-generate --chip esp32 esp32-blink
Project Structure
esp32-blink/
├── Cargo.toml # Dependencies and project config
├── src/
│ └── main.rs # Your code goes here
├── .cargo/
│ └── config.toml # Build configuration
└── rust-toolchain.toml # Specifies Rust toolchain
Writing the Blink Code
Open src/main.rs in your favorite editor:
#![no_std]
#![no_main]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer."
)]
use esp_hal::{
clock::CpuClock,
gpio::{Level, Output, OutputConfig},
main,
time::{Duration, Instant},
};
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}
extern crate alloc;
// This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see:
esp_bootloader_esp_idf::esp_app_desc!();
#[main]
fn main() -> ! {
// generator version: 1.0.1
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 98768);
let mut led2 = Output::new(peripherals.GPIO2, Level::Low, OutputConfig::default());
loop {
led2.toggle();
let delay_start = Instant::now();
while delay_start.elapsed() < Duration::from_millis(500) {}
}
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0/examples/src/bin
}
Building and Flashing
Build the Project
# Build in release mode (optimized)
cargo build --release
Flash to ESP32
# Build and flash in one command
cargo run --release
You should see:
[INFO] Serial port: '/dev/ttyUSB0'
[INFO] Connecting...
[INFO] Using flash stub
Chip type: esp32 (revision v3.1)
...
[INFO] Flashing has completed!
Troubleshooting Common Issues
“Path ‘/dev/ttyUSB0’ is not readable”
Solution: Permission issue
sudo usermod -a -G dialout $USER
# Log out and back in