Project Organization

The esp-rs Crates

Unlike most other embedded platforms, Espressif supports the Rust standard library. Most notably, this means you'll have arbitrary-sized collections like Vec or HashMap at your disposal, as well as generic heap storage using Box. You're also free to spawn new threads, and use synchronization primitives like Arc and Mutex to safely share data between them. Still, memory is a scarce resource on embedded systems, and so you need to take care not to run out of it - threads in particular can become rather expensive.

Services like Wi-Fi, HTTP client/server, MQTT, OTA updates, logging etc. are exposed via Espressif's open source IoT Development Framework, ESP-IDF. It is mostly written in C and as such is exposed to Rust in the canonical split crate style:

  • a sys crate to provide the actual unsafe bindings (esp-idf-sys)
  • a higher level crate offering safe and comfortable Rust abstractions (esp-idf-svc)

The final piece of the puzzle is low-level hardware access, which is again provided in a split fashion:

  • esp-idf-hal implements the hardware-independent embedded-hal traits like analog/digital conversion, digital I/O pins, or SPI communication - as the name suggests, it also uses ESP-IDF as a foundation
  • if direct register manipulation is required, esp32c3 provides the peripheral access crate generated by svd2rust.

More information is available in the ecosystem chapter of The Rust on ESP Book.

Build Toolchain

🔎 As part of a project build, esp-idf-sys will download ESP-IDF, the C-based Espressif toolchain. The download destination is configurable. To save disk space and download time, all examples/exercises in the workshop repository are set to use one single global toolchain, installed in ~/.espressif (%USERPROFILE%\.espressif in Windows). See the ESP_IDF_TOOLS_INSTALL_DIR parameter in esp-idf-sys's README for other options.

Package Layout

On top of the usual contents of a Rust project created with cargo new, a few additional files and parameters are required. The examples/exercises in this workshop are already fully configured, and for creating new projects it is recommended to use the cargo-generate wizard based approach.

🔎 The rest of this page is optional knowledge that can come in handy should you wish to change some aspects of a project.

Some build dependencies must be set:

[build-dependencies]
embuild = "=0.31.2"
anyhow = "=1.0.71"

Additional Configuration Files

  • build.rs - Cargo build script. Here: sets environment variables required for building.
  • .cargo/config.toml - sets the target architecture, a custom runner to flash and monitor the device, and controls build details. This is the place to override ESP_IDF_TOOLS_INSTALL_DIR if you wish to do so.
  • sdkconfig.defaults - overrides ESP-IDF specific parameters such as stack size, log level, etc.