Real-time UART CLI for ESP32, built in Rust (bare-metal, no_std).
A minimal interactive command-line interface that runs on an ESP32
microcontroller, receiving commands via serial and responding in real time. Built
with the Espressif Rust ecosystem (esp-hal, espup, Wokwi simulation).
The project targets xtensa-esp32-none-elf, Espressif's Xtensa architecture.
The standard Rust toolchain does not include this target.
Check if the esp toolchain is installed:
rustup toolchain list | grep espExpected output includes a line with esp.
Verify the target is available:
rustup run esp rustc --print target-list | grep xtensa-esp32-none-elfExpected output: xtensa-esp32-none-elf
The toolchain is managed by espup, not by
rustup's standard channel system.
Rust version:
| Key | Value |
|---|---|
| Channel | esp (Espressif Rust fork, nightly-based) |
| Rustc | ~1.95.0-nightly |
| Target | xtensa-esp32-none-elf |
| Defined in | rust-toolchain.toml |
The Xtensa linker and LLVM/Clang for ESP32 are installed alongside the esp
toolchain. Verify:
# Xtensa GCC linker should be on PATH after sourcing export-esp.sh
xtensa-esp32-elf-ld --versionThis project can use mise for environment management,
but it is not required. The esp toolchain is installed and managed by
espup, not by mise.
If you use mise:
- The project
mise.tomllists additional local tooling (if any). - Make sure mise does not override
RUSTUP_TOOLCHAIN— the project relies onrust-toolchain.tomlto select the correct channel.
cargo install espupespup install -t esp32The
-t esp32flag limits the installation to the ESP32 target (faster thanall). ESP32 classic (Xtensa LX6) is the chip used in this project.
Every new terminal needs the Espressif tools on PATH:
source $HOME/export-esp.shAlternatively, add this line to your shell rc file (e.g. ~/.zshrc):
alias get_esprs='. $HOME/export-esp.sh'# Active toolchain should be esp
rustup show active-toolchain
# Build should succeed
cargo build- Install the "Wokwi for VS Code" extension.
- Open the project in VS Code.
- Press
F1→Wokwi: Start Simulator.
The simulator uses wokwi.toml to locate the firmware binary and
diagram.json to define the hardware layout.
rust-demo-day/
├── .cargo/
│ └── config.toml # Target: xtensa-esp32-none-elf, build-std, rustflags
├── src/
│ ├── bin/
│ │ └── main.rs # Entry point and main loop
│ ├── lib.rs # Module declarations
│ ├── uart_handler.rs # UART0 configuration and (future) ISR registration
│ ├── ring_buffer.rs # (pending) Lock-free bbqueue producer/consumer
│ └── command_parser.rs # (pending) Line accumulator and command dispatch
├── docs/
│ ├── MILESTONES.md # Project milestones (English)
│ └── MILESTONES_ES.md # Project milestones (Spanish)
├── diagram.json # Wokwi hardware simulation layout
├── wokwi.toml # Wokwi firmware path configuration
├── build.rs # Linker script for esp-hal
├── rust-toolchain.toml # Toolchain channel: esp
├── Cargo.toml # Dependencies (esp-hal, bbqueue, heapless, etc.)
├── plan.md # Original project plan and architecture notes
└── mise.toml # Optional mise configuration (commented by default)
cargo buildThe binary is written to
target/xtensa-esp32-none-elf/debug/rust-demo-day.
espflash flash --monitor --chip esp32 target/xtensa-esp32-none-elf/debug/rust-demo-day- Open the project in VS Code.
- Press
F1→Wokwi: Start Simulator. - The serial monitor opens automatically — type characters and observe responses.
Cause: The active toolchain is a stable release, but .cargo/config.toml
uses nightly-only flags (-Z).
Fix: Make sure the esp toolchain is active:
# Check which toolchain is active
rustup show active-toolchain
# The output should show 'esp', not a stable version like '1.80.1'
# If it shows a stable version, unset the overridden variable or check mise
unset RUSTUP_TOOLCHAINThe project's rust-toolchain.toml sets channel = "esp", which rustup
respects unless overridden by RUSTUP_TOOLCHAIN (from mise, a shell rc file,
or similar).
Cause: The esp toolchain is missing the Xtensa target.
Fix: Re-run espup with the ESP32 target:
espup update -t esp32
source $HOME/export-esp.sh- Verify
wokwi.tomlpoints to the correct ELF path:target/xtensa-esp32-none-elf/debug/rust-demo-day - Run
cargo buildfirst so the binary exists. - Check
diagram.jsonfor correct pin assignments.
The current code does not drive GPIO pins — it only configures UART. LEDs
connected to GPIO26 and GPIO27 in diagram.json will light up once GPIO code
is added to the firmware. See the hardware diagram section below.
This project is built incrementally through five milestones. Each milestone has a dedicated branch, an owner, and a reviewer.
| Milestone | Branch | Owner | Status |
|---|---|---|---|
| 1 — UART Echo | feat/uart-echo | Ekojoe | ✅ Complete |
| 2 — Interrupt RX | feat/interrupt-rx | Juan | 🔄 In progress |
| 3 — Ring Buffer | feat/ring-buffer | Ekojoe | ⏳ Pending |
| 4 — Command Parser | feat/command-parser | Both | ⏳ Pending |
| 5 — Polish & Demo | feat/polish | Both | ⏳ Pending |
Full details for each milestone are in docs/MILESTONES.md
and docs/MILESTONES_ES.md.
🏗️ This section will be filled once the project is closer to completion. It will document pin assignments, the Wokwi parts layout, and wiring decisions.
For now, refer to diagram.json for the current Wokwi
simulation setup.
- Ekojoe Covenant Lemom
- Juan Sebastian Valencia Londoño
Repository: https://github.com/anidroid1184/rust_demo_day