App initialization and the #[init] task

An RTIC application requires an init task setting up the system. The corresponding init function must have the signature fn(init::Context) -> (Shared, Local, init::Monotonics), where Shared and Local are the resource structures defined by the user.

The init task executes after system reset (after the optionally defined pre-init and internal RTIC initialization). The init task runs with interrupts disabled and has exclusive access to Cortex-M (the bare_metal::CriticalSection token is available as cs) while device specific peripherals are available through the core and device fields of init::Context.

Example

The example below shows the types of the core, device and cs fields, and showcases the use of a local variable with 'static lifetime. Such variables can be delegated from the init task to other tasks of the RTIC application.

The device field is available when the peripherals argument is set to the default value true. In the rare case you want to implement an ultra-slim application you can explicitly set peripherals to false.

#![allow(unused)]
fn main() {
//! examples/init.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965, peripherals = true)]
mod app {
    use cortex_m_semihosting::{debug, hprintln};

    #[shared]
    struct Shared {}

    #[local]
    struct Local {}

    #[init(local = [x: u32 = 0])]
    fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
        // Cortex-M peripherals
        let _core: cortex_m::Peripherals = cx.core;

        // Device specific peripherals
        let _device: lm3s6965::Peripherals = cx.device;

        // Locals in `init` have 'static lifetime
        let _x: &'static mut u32 = cx.local.x;

        // Access to the critical section token,
        // to indicate that this is a critical seciton
        let _cs_token: bare_metal::CriticalSection = cx.cs;

        hprintln!("init").unwrap();

        debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator

        (Shared {}, Local {}, init::Monotonics())
    }
}
}

Running the example will print init to the console and then exit the QEMU process.

$ cargo run --target thumbv7m-none-eabi --example init
init

NOTE: You can choose target device by passing a target triple to cargo (e.g. cargo run --example init --target thumbv7m-none-eabi) or configure a default target in .cargo/config.toml.

For running the examples, we use a Cortex M3 emulated in QEMU, so the target is thumbv7m-none-eabi.