intro
I've recently decided to migrate to risc-v for my embedded hobby project, most notable of which is the abc-8. Setting it up a rust development environment was fairly straight forward, but there were some gotchas.
Despite recently migrating to nixos I see no reason to use flakes for it, in fact I found it overly complicated the project. Not to mention that very few people actually use nix, even less flakes. So I went with the trusty old podman / docker.
This is the most minimal setup I managed to create, it's possible I'll shave some more fat off as we go along but for now I'm quite happy with it. Beyond this you also need cargo-espflash (or just espflash) to flash the --release binary.
The only thing that might be a bit controversial is that I'm using the root account in the container. But I'm running podman rootless so it just maps 1:1 to my user account. If you use docker you might want to change it (or not).
Do note that this makes [~/.cargo, ~/.rustup, rust-target] ephemeral. You will likely want to mount them as docker volumes.
Dockerfile
FROM ubuntu:22.04
RUN apt-get update && apt full-upgrade -y && apt-get install -y \
file \
curl \
clang \
python3-pip \
python3-venv \
git
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
RUN rustup toolchain install nightly-2024-03-01 --component rust-src
RUN rustup target add riscv32imc-unknown-none-elf --toolchain nightly-2024-03-01
RUN cargo install ldproxy
ENV USER=root
Cargo.toml
[package]
name = "blinky"
version = "0.1.0"
edition = "2021"
authors = ["Anders Tonfeldt"]
[profile.release]
opt-level = "s" # optimize for binary size
[profile.dev]
debug = true
opt-level = "z"
[dependencies]
esp-idf-svc = { version="0.48", default-features=false, features=["std", "binstart"] }
esp-idf-hal = { version="0.43.1", default-features=false }
anyhow = { version="1.0.80" }
[build-dependencies]
embuild = { version="0.31.3", default-features=false }
.cargo/config.toml
[build]
target = "riscv32imc-esp-espidf"
target-dir = "/target"
[target.riscv32imc-esp-espidf]
linker = "ldproxy"
rustflags = [ "--cfg", "espidf_time64"]
[unstable]
build-std = ["std", "panic_abort"]
[env]
MCU="esp32c3"
ESP_IDF_VERSION = "v5.1.2"
rust-toolchain.toml
[toolchain]
channel = "nightly-2024-03-01"
components = ["rust-src"]
targets = ["riscv32imc-unknown-none-elf"]
build.rs
fn main() {
embuild::espidf::sysenv::output();
}
src/main.rs
//! Blinks an LED
//!
//! This assumes that a LED is connected to GPIO4.
//! Depending on your target and the board you are using you should change the pin.
//! If your board doesn't have on-board LEDs don't forget to add an appropriate resistor.
//!
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::gpio::*;
use esp_idf_hal::peripherals::Peripherals;
fn main() -> anyhow::Result<()> {
esp_idf_hal::sys::link_patches();
let peripherals = Peripherals::take()?;
let mut led = PinDriver::output(peripherals.pins.gpio5)?;
loop {
led.set_high()?;
// we are sleeping here to make sure the watchdog isn't triggered
FreeRtos::delay_ms(1000);
led.set_low()?;
FreeRtos::delay_ms(1000);
}
}