Date: 13.05.2022
So, you got a shiny new esp32-c3 dev-board and want to get started programming it. But you also want to use the best™ programming language to do so?
Boy do I got a quick start for you!
Before we are starting, keep in mind that it is mid-2022. This information might be outdated at some point in the future. Currently, it works and also uses only the latest tech from the rust embedded world.
In the rust embedded world most hardware programming is done through
HAL (Hardware Abstraction
Layer) crates. They provide common peripherals based on
the embedded-hal
crate. This allows sensor implementations to share only the
ebedded-hal
crate. Drivers are only implemented against
this embedded-hal
once and can be shared across multiple
architectures and chips.
Finding the prefect abstraction for hardware however is not always easy. This is one of the reasons why at least two HALs exist for esp32 controllers. One is esp32-hal and one is esp-hal.
esp32-hal
is the old HAL. We don’t want to use
old stuff. The new esp-hal
however is still in development,
so we can’t find it on crates.io yet. At some
point it will be released there.
The first thing you’ll have to do whenever you are starting out with new hardware and rust-embedded dev is installing a toolchain for the hardware you are using. In our case this is done via
$ rustup target add riscv32imc-unknown-none-elf
Now we are able to build a project. However, we still have to flash our board. Luckily there is espflash, which is similar to the similarly named python script, but in rust.
You can install it via
$ cargo install espflash
It can be called either via espflash
, or, if you have
the cargo
subcommand installed via cargo espflash
.
If you don’t want to use screen
for reading back output
via USB (or you are on Windows), you can also install espmonitor.
The one time setup is done at this point. Setting up a rust project is nearly as easy as it usually is. We start out with
$ cargo new --bin new_project
If you start to program using esp-hal
and
embedded-hal
you would get an error telling you that
esp-hal
is emitting wrong (RiscV) instructions. So we need
a way to tell the compiler to use the correct toolchain.
We do this by creating:
new_project/.cargo/config.toml
with the following content:
[target.riscv32imc-unknown-none-elf]
runner = "espflash --monitor"
rustflags = [
"-C", "link-arg=-Tlinkall.x"
]
# for testing: you can specify this target to see atomic emulation in action
[target.riscv32imac-unknown-none-elf]
runner = "espflash --monitor"
rustflags = [
"-C", "link-arg=-Tlinkall.x"
]
[build]
target = "riscv32imc-unknown-none-elf"
[unstable]
build-std = [ "core" ]
The last thing to do is setting up our
new_project/src/main.rs
file.
A really simple main.rs
might look like this:
#![no_std]
#![no_main]
#[entry]
fn main() -> {
//your code
}
For completeness, the hello_world example looks like this:
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32c3_hal::{pac::Peripherals, prelude::*, RtcCntl, Serial, Timer};
use nb::block;
use panic_halt as _;
use riscv_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut timer1 = Timer::new(peripherals.TIMG1);
// Disable watchdog timers
.set_super_wdt_enable(false);
rtc_cntl.set_wdt_enable(false);
rtc_cntl.disable();
timer0.disable();
timer1
.start(10_000_000u64);
timer0
loop {
writeln!(serial0, "Hello world!").unwrap();
block!(timer0.wait()).unwrap();
}
}
Usually we use cargo run
to execute our program. In this
case, it is a two-step procedure. First we flash the program to the
board, and second, monitoring its serial output.
Make sure to have the board connected. Then check
/dev/tty*
for a USB connect. Usually this is
/dev/ttyUSB0
. Assuming it is USB0
the flash
command looks like this
$ cargo espflash --release /dev/ttyUSB0
Now you can use screen
or espmonitor
to
check the serial output of your board on USB0
via
$ cargo espmonitor /dev/ttyUSB0
At this point you are ready to program using your esp32-c3. Have fun, maybe you need a flow sensor?