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 WiFi, 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 create generated by svd2rust.

More information is available in the ecosystem chapter of the esp-rs 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. 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.

Cargo.toml

This workshop is written around the native build system. Alternatively you may use PlatformIO/pio, however this is currently being deprecated.

[features]
default = ["native"]
native = ["esp-idf-sys/native"]

Some build dependencies must be set:

[build-dependencies]
embuild = "0.28"
anyhow = "1"

Additional configuration files

  • build.rs - Cargo build script. Here: sets environment variables required for building.
  • .cargo/config.toml - sets the target architecture 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 or log level.