Introduction

The goal of this book is to provide a comprehensive guide on using the Rust programming language with Espressif SoCs and modules.

Rust support for these devices is still in the early stages, but progress is being made rapidly. Because of this parts of this documentation may be out of date or change dramatically between readings.

For tools and libraries relating to Rust on ESP, please see the esp-rs organization on GitHub.

Status of This Book

This book is currently a work in progress. A number of sections may be missing information or be missing altogether. If there is a specific topic you would like to see documented please open an issue.

If you feel you can contribute something to this book, we encourage you to create a pull request!

Who This Book is For

This book assumes some experience with embedded development and the Rust programming language. Teaching these topics is outside the scope of this book.

If you are unfamiliar with either topic, please refer to the resources listed below to help you get started.

Additional Resources

Some additional resources can be found below which may prove useful for those less experienced with embedded Rust.

ResourceDescription
The Rust Programming LanguageIf you are not familiar with Rust we recommend reading this book first.
The Embedded Rust BookHere you can find several other resources provided by Rust's Embedded Working Group.
The EmbedonomiconThe nitty gritty details when doing embedded programming in Rust.

Ecosystem Overview

There are two approaches for using Rust on Espressif chips:

  1. With the full standard library available (std)
  2. Without the standard library available (no_std)

Both approaches have their advantages and disadvantages, so you should make a decision based on your project's needs. This chapter contains an overview of the two approaches followed by a brief comparison between them.

The esp-rs organization on GitHub is home to a number of repositories related to running Rust on Espressif chips. Most of the required crates have their source code hosted here.

Using the Rust Standard Library (std)

Espressif provides a C-based development framework called esp-idf which has support for all Espressif chips starting with the ESP32; note that this framework does not support the ESP8266.

esp-idf in turn provides a newlib environment with enough functionality to build the Rust standard library (std) on top of it. This is the approach that is being taken to enable std support on ESP devices.

Chip Support

In order for applications targeting std to be built for ESP devices, two things are required:

  1. LLVM/Clang support
  2. Support for the device in esp-idf

Refer to the table below to see if your chip is supported.

ChipSupported?
ESP32
ESP32-C2planned
ESP32-C3
ESP32-S2
ESP32-S3
ESP32-H2planned
ESP8266

Since esp-idf does not have support for the ESP8266, we unfortunately are unable to use these libraries with it. See the Bare Metal page for information on the no_std HAL for this chip.

Standard Library Features

The supported std features are as follows:

  • Threads
  • Mutexes and other synchronization primitives
  • Collections
  • Random number generation
  • Sockets

In addition to the std features there is an embedded-svc implementation for esp-idf, esp-idf-svc, which adds extra support for services/modules not available in the standard library, including:

  • Wi-Fi management
  • NVS (non-volatile storage)
  • Networking services like httpd and ping

In general, this approach should feel quite similar to developing for most normal PC environments.

Relevant esp-rs crates

RepositoryDescription
esp-rs/esp-idf-halAn implementation of the embedded-hal and other traits using the esp-idf framework.
esp-rs/esp-idf-svcAn implementation of embedded-svc using esp-idf drivers.
esp-rs/esp-idf-sysRust bindings to the esp-idf development framework. Gives raw (unsafe) access to drivers, Wi-Fi and more.
esp-rs/embedded-svcAbstraction traits for embedded services. (WiFi, Network, Httpd, Logging, etc.)

The aforementioned crates have interdependencies, and this relationship can be seen below.

graph TD;
    esp-idf-hal --> esp-idf-sys & embedded-svc
    esp-idf-svc --> esp-idf-sys & esp-idf-hal & embedded-svc

FAQ

I updated my sdkconfig.defaults file but it doesn't appear to have had any effect

You must clean your project and rebuild in order for changes in the sdkconfig.defaults to take effect:

$ cargo clean
$ cargo build

The documentation for the crates mentioned on this page is out of date or missing

Due to the resource limits imposed by docs.rs, internet access is blocked while building documentation and as such we are unable to build the documentation for esp-idf-sys or any crate depending on it.

Instead, we are building the documentation and hosting it ourselves on GitHub Pages:

***ERROR*** A stack overflow in task main has been detected.

If the second-stage bootloader reports this error, you likely need to increase the stack size for the main task. This can be accomplished by adding the following to the sdkconfig.defaults file:

CONFIG_ESP_MAIN_TASK_STACK_SIZE=7000

In this example, we are allocating 7kB for the main task's stack.

How can I completely disable the watchdog timer(s)?

Add to your sdkconfig.defaults file:

CONFIG_INT_WDT=n
CONFIG_ESP_TASK_WDT=n

Recall that you must clean your project before rebuilding when modifying these configuration files.

Bare Metal (no_std)

Using no_std may be more familiar to embedded Rust developers; it does not use std (the Rust standard library) but instead uses a subset, the core library. The official Rust embedded book has a great section on this.

It's important to note that in general a no_std crate can always compile in std environment but the inverse is not true. Therefore, when creating crates it's worth keeping in mind if it needs to the standard library to function.

Hardware Abstraction Layers

Previously, the primary focus of no_std development was the ESP32 and (to a lesser extent) the ESP8266, via esp-rs/esp32-hal and esp-rs/esp8266-hal.

While esp32-hal and esp8266-hal have great support for a lot of the onboard peripherals, Wi-Fi and Bluetooth are not currently supported in a no_std enviroment. esp-rs/esp32-wifi was created to explore getting it working, but it is not yet functional.

More recently, there has been a renewed effort to implement no_std support for the entire lineup of Espressif devices from the ESP32 and newer. These new HALs can be found in the esp-rs/esp-hal repository.

Chip Support

Chip support for no_std requires LLVM/Clang support just like for std. However, this has no dependency on esp-idf. In addition to compiler support, it's necessary to have peripheral access crates (PAC) and hardware abstraction layers (HAL) for your desired chip.

Refer to the table below to see if your chip is supported. Please note that the no_std HALs are still in the early phases of development, so not all peripherals have had drivers implemented.

ChipPACHAL
ESP32
ESP32-C2plannedplanned
ESP32-C3
ESP32-S2
ESP32-S3
ESP32-H2plannedplanned
ESP8266

Relevant esp-rs Crates

RepositoryDescription
esp-rs/esp-pacsA monorepo containing PACs for each supported device.
esp-rs/esp-halAn implementation of the embedded-hal traits and more for the ESP32, ESP32-C3, ESP32-S2, and ESP32-S3.
esp-rs/esp8266-halAn implementation of the embedded-hal traits and more for the ESP8266.

Comparing std and no_std

There are a number of factors which must be considered when choosing between std (esp-idf-hal) and no_std (eg. esp32-hal). As stated previously, each approach has its own unique set of advantages and disadvantages. While we can't decide for you, this section will hopefully allow you to make an educated decision.

At present, there are unfortunately certain technical restrictions which may dictate your choice; we hope to have these issues resolved soon. Currently you must use the std approach if you require any of the following:

  • Use of Wi-Fi or Bluetooth
  • The ability to target any chip other than the ESP32 or the ESP8266

Application Runtimes

In the case of applications (as opposed to libraries) the standard library provides a runtime which handles setting up stack overflow protection, spawning the main thread before an application's main function is invoked, and handling of command-line arguments.

Applications targeting no_std will be responsible for initializing their own runtimes instead. Runtime initialization is generally handled by an external dependency, in our case the riscv-rt and xtensa-lx-rt libraries. You can refer to their READMEs and documentation for more information.

One advantage of not including the default runtime is that you're able to write applications at a lower level. This is possible because the applications will have been linked again the core crate instead of std, which makes no assumptions about the system it is running on. As such, it's possible to write applications like bootloaders, firmware, or even operating system kernels using the no_std approach.

#![no_main]

Another interesting property of no_std applications is that we cannot use Rust's default main function as our entry point. It makes certain assumptions which are not neccessarily valid in an embedded context (for example, it expects that command-line arguments exist).

Because of this, you will often see the #![no_main] attribute used to instruct the Rust compiler not to use the default entry point. Runtime crates will provide an #[entry] attribute which can be used to mark a diverging function as the application's entry point instead. For example a minimal application might look something like this:

#![no_std]
#![no_main]

use riscv_rt::entry;

#[entry]
fn main() -> ! {
    loop {}
}

Panic Handlers

In addition to specifying the application's entry point, for no_std we must also define a panic handler. The default panic behaviour relies on std, as it prints to standard output.

You are able to define a panic handler manually using the #[panic_handler] attribute. Note that this function's signature must match the example below.

#![no_std]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    // Your implementation goes here!
}

Alternatively, there are a number of external dependencies which define various panic handlers for us. Some possible choices are panic-halt, panic-semihosting, or panic-never.

These can be used simply by installing the relevant dependency, and then importing the crate:

#![no_std]

use panic_halt as _;

Required Dependencies

With an understanding of the ecosystem surrounding Rust on Espressif chips, we're able to move on to actual development. If you are not aware of the two possible development approaches, or do not understand the differences between writing std and no_std applications, please first read the Ecosystem Overview chapter.

In this chapter we will cover the installation of the correct Rust compiler and toolchain as well as creating applications.

Installing Rust

In order to develop for ESP devices using Rust you must first install the Rust compiler along with the appropriate toolchain and target(s). Depending on your device it may be one of two architectures, each requiring different setup.

If you have not yet installed Rust on your system, you can do so easily using rustup. For macOS and Linux it can be installed by runing the following command:

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

For installation on Windows or alternative installation methods, please refer to the instructions on the rustup website.

With Rust installed we next need to ensure that the nightly toolchain is installed and set as the default:

$ rustup toolchain install nightly
$ rustup default nightly

You can read more about toolchains in the rustup book.

Prerequisites

git

git must be installed on your system in order to clone repositories. This should be available via your system's package manager, or for Windows users Git for Windows can be used.

Visual Studio Build Tools

If you are running Windows as your host operating system, you must install the Visual Studio Build Tools, which can be downloaded from the Microsoft website.

Xtensa Toolchain

If you are developing for an Xtensa chip (ESP32, ESP32-S2, ESP32-S3) you must also install the appropriate Xtensa toolchain. Pre-built toolchains can be downloaded from the crosstool-NG repository for the most common operating systems and architectures.

Ensure that you have downloaded the required toolchain and added its directory to your PATH environment variable prior to building your application.

RISC-V (ESP32-C3)

The RISC-V architecture has support in the mainline Rust compiler so setup is relatively simple, all we must do is add the appropriate compilation target.

There are two suitable targets for this chip:

  • For bare-metal (no_std) applications, use riscv32imc-unknown-none-elf
  • For applications which require std, use riscv32imc-esp-espidf

The bare-metal target can be installed by running:

$ rustup target add riscv32imc-unknown-none-elf

The standard library target (riscv32imc-esp-espidf) is currently Tier 3, and does not have prebuilt objects distributed through rustup, therefore the -Z build-std unstable cargo feature is required within your project. See an example usage in rust-esp32-std-mini.

At this point you are ready to build applications for the ESP32-C3.

Xtensa (ESP32, ESP32-S2, ESP32-S3)

Because there is no Xtensa support in the mainline Rust compiler you must use the esp-rs/rust fork instead. There are a few options available for installing this compiler fork.

The forked compiler can coexist with the standard Rust compiler, so it is possible to have both installed on your system. The forked compiler is invoked when using the esp channel instead of the defaults, stable or nightly.

Using a Pre-Built Release

Pre-built releases are available for a number of platforms on GitHub under the esp-rs/rust-build repository. The following operating systems and architectures are currently supported:

  • macOS (x86_64, aarch64)
  • Windows (x86_64)
  • Linux (x86_64)

The aforementioned repository also contains Bash and PowerShell scripts to automate the installation process.

macOS and Linux

$ curl -LO https://raw.githubusercontent.com/esp-rs/rust-build/main/install-rust-toolchain.sh
$ chmod +x install-rust-toolchain.sh
$ ./install-rust-toolchain.sh

Windows

With GUI installer: https://github.com/espressif/idf-installer/releases

With PowerShell:

PS> Invoke-WebRequest https://raw.githubusercontent.com/esp-rs/rust-build/main/Install-RustToolchain.ps1 -OutFile Install-RustToolchain.ps1
PS> ./Install-RustToolchain.ps1

To confirm the esp toolchain has been installed:

$ rustup toolchain list
stable-x86_64-apple-darwin
nightly-x86_64-apple-darwin (default)
esp

Building From Source

You can also build the Rust compiler with Xtensa support from source. This process is computationally expensive and can take one or more hours to complete depending on your system. It is recommended that you have at least 6GB of RAM and 25GB+ of available storage space.

To check out the repository and build the compiler:

$ git clone https://github.com/esp-rs/rust
$ cd rust
$ ./configure --experimental-targets=Xtensa
$ ./x.py build --stage 2

Note that you should not rename the rust directory to avoid issues while building.

Once the build has completed, you can link the toolchain using rustup (your architecture/operating system may be different):

$ rustup toolchain link esp $PWD/build/x86_64-apple-darwin/stage2

Once the compiler fork has been installed using one of the above methods, to confirm the esp toolchain has been installed:

$ rustup toolchain list
stable-x86_64-apple-darwin
nightly-x86_64-apple-darwin (default)
esp

To view the installed Xtensa targets:

$ rustc +esp --print target-list | grep xtensa
xtensa-esp32-espidf
xtensa-esp32-none-elf
xtensa-esp32s2-espidf
xtensa-esp32s2-none-elf
xtensa-esp8266-none-elf
xtensa-none-elf

Using Containers

As an alternative to installing the compiler fork to your local system directly, it's also possible to run it inside of a container.

A number of container runtimes are available, and which should be used depends on your operating system. Some of the popular options are:

Espressif provides the idf-rust container image which contains esp-idf and the pre-built Rust compiler fork.

Build Tools

ldproxy

When building applications using the Rust standard library, std, the build tool ldproxy is required and must be installed first; this tool can be found in the embuild repository. This tool is not required for no_std applications.

ldproxy is a simple tool to forward linker arguments given to ldproxy to the actual linker executable.

To install:

$ cargo install ldproxy

Text Editors and IDEs

While an often contentious subject, using the right development environment can make a significant impact on your productivity with a given programming language. Below can be found a curated list of what we feel are the best options.

Visual Studio Code

One of the more common development environents is Microsoft's Visual Studio Code text editor along with the Rust Analyzer extension.

Visual Studio Code is an open-source and cross-platform graphical text editor with a rich ecosystem of extensions. The Rust Analyzer extension provides an implementation of the Language Server Protocol for Rust, and additionally includes features like autocompletion, go to definition, and more.

Visual Studio Code can be installed via most popular package managers, and installers are available on the official website. The Rust Analyzer extension can be installed in Visual Studo Code via the built-in extension manager.

Tips and Tricks

If you are developing for a target which does not have std support Rust Analyzer can behave strangely, often reporting various errors. This can be resolved by creating a .vscode/settings.json file in your project and populating it with the following:

{
  "rust-analyzer.checkOnSave.allTargets": false
}

If you are using a custom toolchain, as you would with Xtensa targets, you can provide some hints to cargo via the rust-toolchain.toml file to improve the user experience:

[toolchain]
channel = "esp"
components = ["rustfmt", "rustc-dev"]
targets = ["xtensa-esp32-none-elf"]

CLion

CLion is a cross-platform IDE for C and C++ from JetBrains.

IntelliJ

vim

espflash

A serial flasher utility for ESP devices. Supports flashing ESP32, ESP32-C3, ESP32-S2, and ESP8266.

The esp-rs/espflash repository contains two crates, cargo-espflash and espflash. You can find more information on both of these in their respective sections below.

cargo-espflash

Provides a subcommand for cargo which handles cross-compilation and flashing. Note that this requires the unstable build-std cargo feature; for more information on this please refer to the cargo documentation.

To install:

$ cargo install cargo-espflash

This command must be run within a Cargo project, ie.) a directory containing a Cargo.toml file. For example, to build an example named 'blinky' in release mode, flash the resulting binary to a device, and then subsequently start a serial monitor:

$ cargo espflash --example=blinky --release --monitor

For more information please see to the cargo-espflash README.

espflash

Provides a standalone command-line application which flashes an ELF file to a device.

To install:

$ cargo install espflash

Assuming you have built an ELF binary by other means already, espflash can be used to download it to your device. For example, if you have built the getting-started/blinky example from esp-idf using idf.py you might run something like:

$ espflash build/blinky

For more information please see to the espflash README.

espmonitor

The esp-rs/espmonitor repository contains two crates, cargo-espmonitor and espmonitor.

cargo-espmonitor

$ cargo install cargo-espmonitor

espmonitor

$ cargo install espmonitor

probe-rs

The probe-rs project is a set of tools to interact with embedded MCU's using various debug probes. It is similar to openOCD, PyOCD, Segger tools etc. There is support for ARM & RISCV architectures along with a collection of tools, including but not limited to:

  • Debugger
    • GDB support.
    • CLI for interactive debugging.
    • VSCode extension.
  • RTT (Real Time Transfer)
    • Similar to app_trace component of IDF.
  • Flashing algorithms

More info about probe-rs & how to set up a project, can be found on the probe.rs website.

USB-JTAG-SERIAL peripheral for ESP32-C3

Starting from probe-rs v0.12, it is possible to flash and debug the ESP32-C3 with the builtin USB-JTAG-SERIAL peripheral, no need for any external hardware debugger. More info on configuring the interface can be found in the official documentation.

Support for Espressif chips

probe-rs currently only supports ARM & RISCV, therefore this limits the number of Espressif chips that can be used at the moment.

ChipFlashingDebugging
ESP32-C3⚠️

Note: items marked with ⚠️ are currently work in progress, usable but expect bugs.

Permissions - Linux

On linux you may run into permission issues trying to interact with Espressif probes. Installing the following udev rules and reloading should fix that issue.

# Espressif dev kit FTDI
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess"

# Espressif USB JTAG/serial debug unit
ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess"

# Espressif USB Bridge
ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE="660", GROUP="plugdev", TAG+="uaccess"

OpenOCD

Similar to probe-rs, OpenOCD does not have support for the Xtensa architecture. However, Espressif does maintain a fork of OpenOCD under espressif/openocd-esp32 which has support for Espressif's chips.

Instructions on how to install openocd-esp32 for your platform can be found in the Espressif documentation.

Setup for Espressif chips

Once installed, it's as simple as running openocd with the correct scripts. For chips with the builtin USB JTAG, there is normally a config that will work out of the box, for example on the ESP32-C3:

openocd -f board/esp32c3-builtin.cfg

For other configurations it may require specifying the chip and the interface separately, for example ESP32 with a J-Link:

openocd -f interface/jlink.cfg -f target/esp32.cfg

Debugging in Visual Studio Code

There is also a possibility to debug with graphical output directly in Visual Studio Code.

ESP32

Hardware Setup

ESP32 doesn't have a built-in JTAG interface so you have to connect an external JTAG adapter with the ESP32 board, for example ESP-Prog can be used.

ESP32 PinJTAG Signal
MTDO/GPIO15TDO
MTDI/GPIO12TDI
MTCK/GPIO13TCK
MTMS/GPIO14TMS
3V3VJTAG
GNDGND

Note: On Windows USB Serial Converter A 0403 6010 00 driver should be WinUSB.

Set up VSCode

  1. Install Cortex-Debug extension for VScode.
  2. Create the .vscode/launch.json file in the project tree you want to debug. This can be used as a template file.
  3. Update executable, svdFile, serverpath paths and toolchainPrefix field.
    {
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
            {
                // more info at: https://github.com/Marus/cortex-debug/blob/master/package.json
                "name": "Attach",
                "type": "cortex-debug",
                "request": "attach", // attach instead of launch, because otherwise flash write is attempted, but fails
                "cwd": "${workspaceRoot}",
                "executable": "target/xtensa-esp32-none-elf/debug/.....",
                "servertype": "openocd",
                "interface": "jtag",
                "svdFile": "../../esp-pacs/esp32/svd/esp32.svd",
                "toolchainPrefix": "xtensa-esp32-elf",
                "openOCDPreConfigLaunchCommands": [
                    "set ESP_RTOS none"
                ],
                "serverpath": "C:/Espressif/tools/openocd-esp32/v0.11.0-esp32-20220411/openocd-esp32/bin/openocd.exe",
                "configFiles": [
                    "board/esp32-wrover-kit-3.3v.cfg"
                ],
                "overrideAttachCommands": [
                    "set remote hardware-watchpoint-limit 2",
                    "mon halt",
                    "flushregs"
                ],
                "overrideRestartCommands": [
                    "mon reset halt",
                    "flushregs",
                    "c",
                ]
            },
        ]
    }

ESP32-C3

Older versions with revision < 3 doesn't have built-in JTAG interface.

ESP32-C3 with revision 3 does have a built-in JTAG interface and you don't have to connect an external device to be able to debug. To get the chip revision, run the cargo espflash board-info command.

Hardware Setup

If your ESP32-C3's revision is lesser than 3, follow these instructions, if you have revision 3 you can jump to the Set up VSCode step.

ESP32-C3 revision 1 and revision 2 don't have a built-in JTAG interface so you have to connect an external JTAG adapter with the ESP32-C3 board, for example ESP-Prog can be used.

ESP32-C3 PinJTAG Signal
MTDO/GPIO7TDO
MTDI/GPIO5TDI
MTCK/GPIO6TCK
MTMS/GPIO4TMS
3V3VJTAG
GNDGND

Note: On Windows USB Serial Converter A 0403 6010 00 driver should be WinUSB.

Set up VSCode

  1. Install Cortex-Debug extension for VScode.
  2. Create the .vscode/launch.json file in the project tree you want to debug. This can be used as a template file.
  3. Update executable, svdFile, serverpath paths and toolchainPrefix field.
    {
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
            {
                // more info at: https://github.com/Marus/cortex-debug/blob/master/package.json
                "name": "Attach",
                "type": "cortex-debug",
                "request": "attach", // attach instead of launch, because otherwise flash write is attempted, but fails
                "cwd": "${workspaceRoot}",
                "executable": "target/riscv32imc-unknown-none-elf/debug/examples/usb_serial_jtag", //
                "servertype": "openocd",
                "interface": "jtag",
                "svdFile": "../../esp-pacs/esp32c3/svd/esp32c3.svd",
                "toolchainPrefix": "riscv32-esp-elf",
                "openOCDPreConfigLaunchCommands": [
                    "set ESP_RTOS none"
                ],
                "serverpath": "C:/Espressif/tools/openocd-esp32/v0.11.0-esp32-20220411/openocd-esp32/bin/openocd.exe",
                "configFiles": [
                    "board/esp32c3-builtin.cfg"
                ],
                "overrideAttachCommands": [
                    "set remote hardware-watchpoint-limit 2",
                    "mon halt",
                    "flushregs"
                ],
                "overrideRestartCommands": [
                    "mon reset halt",
                    "flushregs",
                    "c",
                ]
            },
        ]
    }

Creating Applications

With the appropriate Rust compiler and toolchain installed, you're now ready to create an application. As outlined below, there are essentially two ways to do this: generating from a template or starting from scratch using only cargo.

Using cargo-generate

The cargo-generate subcommand allows you to create a new project based on some existing template. In our case esp-idf-template or esp-template can be used to generate an application with all the required configuration and dependencies.

cargo generate can be installed by running:

$ cargo install cargo-generate

When the cargo generate subcommand is invoked, you will be prompted to answer a number of questions regarding the target of your application. Upon completion of this process you will have a buildable project with all the correct configuration.

The generated application can be built as normal using the appropriate toolchain and target simply by running cargo build when using either template.

esp-idf-template

When using the Rust standard library (std) you can use the esp-idf-template template, which will look something like:

$ cargo generate --git https://github.com/esp-rs/esp-idf-template cargo
🤷   Project Name : esp-rust-app
🔧   Generating template ...
✔ 🤷   Rust toolchain (beware: nightly works only for esp32c3!) · esp
✔ 🤷   STD support · true
✔ 🤷   ESP-IDF native build version (stable = 4.3.1, upcoming = 4.4, master = 5.0; applicable only with `cargo build --features native`) · stable
✔ 🤷   MCU · esp32
[1/9]   Done: .cargo/config.toml
[2/9]   Done: .cargo
[3/9]   Done: .gitignore
[4/9]   Done: Cargo.toml
[5/9]   Done: build.rs
[6/9]   Done: rust-toolchain.toml
[7/9]   Done: sdkconfig.defaults
[8/9]   Done: src/main.rs
[9/9]   Done: src
🔧   Moving generated files into: `/Users/alice/esp-rust-app`...
✨   Done! New project created /Users/alice/esp-rust-app

esp-template

For bare-metal applications (no_std) you can instead use the esp-template template:

$ cargo generate --git https://github.com/esp-rs/esp-template
🤷   Project Name : esp-rust-app
🔧   Generating template ...
✔ 🤷   Which MCU to target? · esp32c3
✔ 🤷   Configure project to use Dev Containers (VS Code, GitHub Codespaces and Gitpod)? · true
[ 1/25]   Done: .cargo/config.toml
[ 2/25]   Done: .cargo
[ 3/25]   Done: .devcontainer/Dockerfile
[ 4/25]   Done: .devcontainer/devcontainer.json
[ 5/25]   Done: .devcontainer
[ 6/25]   Done: .dockerignore
[ 7/25]   Done: .gitdpod.Dockerfile
[ 8/25]   Done: .gitdpod.yml
[ 9/25]   Done: .gitignore
[10/25]   Done: .vscode/launch.json
[11/25]   Done: .vscode/settings.json
[12/25]   Done: .vscode/tasks.json
[13/25]   Done: .vscode
[14/25]   Done: Cargo.toml
[15/25]   Done: LICENSE-APACHE
[16/25]   Done: LICENSE-MIT
[17/25]   Done: docs/README.md
[18/25]   Done: docs
[19/25]   Done: rust-toolchain.toml
[20/25]   Done: scripts/build.sh
[21/25]   Done: scripts/flash.sh
[22/25]   Done: scripts/run-wokwi.sh
[23/25]   Done: scripts
[24/25]   Done: src/main.rs
[25/25]   Done: src
🔧   Moving generated files into: `/Users/alice/esp-rust-app`...
✨   Done! New project created /Users/alice/esp-rust-app

See the rust-esp32-std-demo.

Appendix A: Glossary

A number of acronyms are used in the embedded development space. This glossary attempts to define any acronyms used in this book.

SVD

System View Description.

The CMSIS-SVD specification formalizes the description of the system contained within a microcontroller. This specification was designed with ARM Cortex-M microcontrollers in mind, however it is still applicable to other architectures.

SVD files are XML and contain definitions for peripherals which can be consumed by tools such a svd2rust to generate Peripheral Access Crates.

PAC

Peripheral Access Crate.

Provides a type-safe, low-level API for interacting with the device's hardware peripherals. For more information on the generated API please refer to the svd2rust documentation.

HAL

Hardware Abstraction Layer.

Provides higher-level abstractions over hardware peripherals which are more easily used by developers. These libraries are generally implemented on top of Peripheral Access Crates, and often implement the various traits provided by embedded-hal.