Skip to content
xoviat edited this page Mar 27, 2021 · 15 revisions

To begin, you should:

  • Have an MCU that embassy supports. We currently support stm32f4, stm32l0, and nrf series MCUs. We aim to support all common stm32 families.
  • Know how to compile, load, and debug a rust program on an embedded target.
  • Have an embedded probe that your IDE supports.
  • Have the nightly rust compiler with the applicable eabi target, for example thumbv7em-none-eabi.

If you're not familiar with embedded development, consult the rust embedded development book.

Because embassy uses some unstable features to support async, embassy requires the rust nightly compiler. Even though embassy currently requires the nightly compiler, you can be confident that software written with embassy will continue to be supported into the future as the required compiler features become stabilized.

Hello, World

Embassy has two options for creating a project: the basic and advanced API. The basic API assumes that every task runs at the same priority and that delays will be needed. The advanced API allows multiple-priority tasks and usage with other frameworks such as RTIC, but is more complex to set-up. Here, we will begin with the simple API.

Though embassy does not require a particular HAL, the stm32-rs HAL is used to configure clocks if the basic API is used. Other HALs may be used with other peripherals, provided that they also use the standard svd2rust PAC.

The main Function

To begin, let's create our main function:

#[embassy::main(use_hse = 48)]
async fn main(spawner: Spawner) {
    let (dp, clocks) = embassy_stm32::Peripherals::take().unwrap();

    spawner.spawn(run1()).unwrap();
}

First, we the write main function and add an embassy::main attribute. The embassy::main attribute sets-up a simple clock and executor configuration using the specified arguments. In this case we use a high-speed external oscillator running at 48 Mhz. Then, we take our device peripherals with embassy_stm32::Peripherals::take(). This replaces the standard pac::Peripherals::take() call, because embassy takes some of the peripherals during set-up. If the basic set-up is used, pac::Peripherals::take() will panic, though cortex_m::Peripherals::take() can be used as normal. Finally, we use the spawner to spawn a task.

Declaring a task

Every task is declared with the task macro, as such. Every task is a standard async function defined with the task attribute. Only functions defined with the task attribute can be spawned with the spawner. Tasks can accept any number of arguments, but they cannot be defined with generic parameters.

#[task]
async fn run1() {
    loop {
        info!("tick");
        Timer::after(Duration::from_ticks(13000 as u64)).await;
    }
}
Clone this wiki locally