## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Migrating from v0.4.x to v0.5.0

This section covers how to upgrade an application written against RTFM v0.4.x to the version v0.5.0 of the framework.

## Project name change RTFM -> RTIC

With release v0.5.2 the name was change to Real-Time Interrupt-driven Concurrency

All occurrences of `RTFM` needs to change to `RTIC`.

See migration guide RTFM to RTIC

## `Cargo.toml`

Change the version of `cortex-m-rtfm` to `"0.5.0"`, change `rtfm` to `rtic`. Remove the `timer-queue` feature.

    [dependencies.cortex-m-rtfm]
    # change this
    version = "0.4.3"

    # into this
    [dependencies.cortex-m-rtic]
    version = "0.5.0"

    # and remove this Cargo feature
    features = ["timer-queue"]
    #           ^^^^^^^^^^^^^

## `Context` argument

All functions inside the `#[rtfm::app]` item need to take as first argument a `Context` structure. This `Context` type will contain the variables that were magically injected into the scope of the function by version v0.4.x of the framework: `resources`, `spawn`, `schedule` -- these variables will become fields of the `Context` structure. Each function within the `#[rtfm::app]` item gets a different `Context` type.

    #![allow(unused)]
    fn main() {
    #[rtfm::app(/* .. */)]
    const APP: () = {
        // change this
        #[task(resources = [x], spawn = [a], schedule = [b])]
        fn foo() {
            resources.x.lock(|x| /* .. */);
            spawn.a(message);
            schedule.b(baseline);
        }

        // into this
        #[task(resources = [x], spawn = [a], schedule = [b])]
        fn foo(mut cx: foo::Context) {
            // ^^^^^^^^^^^^^^^^^^^^

            cx.resources.x.lock(|x| /* .. */);
        //  ^^^

            cx.spawn.a(message);
        //  ^^^

            cx.schedule.b(message, baseline);
        //  ^^^
        }

        // change this
        #[init]
        fn init() {
            // ..
        }

        // into this
        #[init]
        fn init(cx: init::Context) {
            //  ^^^^^^^^^^^^^^^^^
            // ..
        }

        // ..
    };
    }

## Resources

The syntax used to declare resources has changed from `static mut` variables to a `struct Resources`.

    #![allow(unused)]
    fn main() {
    #[rtfm::app(/* .. */)]
    const APP: () = {
        // change this
        static mut X: u32 = 0;
        static mut Y: u32 = (); // late resource

        // into this
        struct Resources {
            #[init(0)] // <- initial value
            X: u32, // NOTE: we suggest changing the naming style to `snake_case`

            Y: u32, // late resource
        }

        // ..
    };
    }

## Device peripherals

If your application was accessing the device peripherals in `#[init]` through the `device` variable then you'll need to add `peripherals = true` to the `#[rtfm::app]` attribute to continue to access the device peripherals through the `device` field of the `init::Context` structure.

Change this:

    #![allow(unused)]
    fn main() {
    #[rtfm::app(/* .. */)]
    const APP: () = {
        #[init]
        fn init() {
            device.SOME_PERIPHERAL.write(something);
        }

        // ..
    };
    }

Into this:

    #![allow(unused)]
    fn main() {
    #[rtfm::app(/* .. */, peripherals = true)]
    //                    ^^^^^^^^^^^^^^^^^^
    const APP: () = {
        #[init]
        fn init(cx: init::Context) {
            //  ^^^^^^^^^^^^^^^^^
            cx.device.SOME_PERIPHERAL.write(something);
        //  ^^^
        }

        // ..
    };
    }

## `#[interrupt]` and `#[exception]`

Remove the attributes `#[interrupt]` and `#[exception]`. To declare hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument instead.

Change this:

    #![allow(unused)]
    fn main() {
    #[rtfm::app(/* .. */)]
    const APP: () = {
        // hardware tasks
        #[exception]
        fn SVCall() { /* .. */ }

        #[interrupt]
        fn UART0() { /* .. */ }

        // software task
        #[task]
        fn foo() { /* .. */ }

        // ..
    };
    }

Into this:

    #![allow(unused)]
    fn main() {
    #[rtfm::app(/* .. */)]
    const APP: () = {
        #[task(binds = SVCall)]
        //     ^^^^^^^^^^^^^^
        fn svcall(cx: svcall::Context) { /* .. */ }
        // ^^^^^^ we suggest you use a `snake_case` name here

        #[task(binds = UART0)]
        //     ^^^^^^^^^^^^^
        fn uart0(cx: uart0::Context) { /* .. */ }

        #[task]
        fn foo(cx: foo::Context) { /* .. */ }

        // ..
    };
    }

## `schedule`

The `schedule` API no longer requires the `timer-queue` cargo feature. To use the `schedule` API one must first define the monotonic timer the runtime will use using the `monotonic` argument of the `#[rtfm::app]` attribute. To continue using the cycle counter (CYCCNT) as the monotonic timer, and match the behavior of version v0.4.x, add the `monotonic = rtfm::cyccnt::CYCCNT` argument to the `#[rtfm::app]` attribute.

Also, the `Duration` and `Instant` types and the `U32Ext` trait moved into the `rtfm::cyccnt` module. This module is only available on ARMv7-M+ devices. The removal of the `timer-queue` also brings back the `DWT` peripheral inside the core peripherals struct, if `DWT` is required, ensure it is enabled by the application inside `init`.

Change this:

    #![allow(unused)]
    fn main() {
    use rtfm::{Duration, Instant, U32Ext};

    #[rtfm::app(/* .. */)]
    const APP: () = {
        #[task(schedule = [b])]
        fn a() {
            // ..
        }
    };
    }

Into this:

    #![allow(unused)]
    fn main() {
    use rtfm::cyccnt::{Duration, Instant, U32Ext};
    //        ^^^^^^^^

    #[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)]
    //                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    const APP: () = {
        #[init]
        fn init(cx: init::Context) {
            cx.core.DWT.enable_cycle_counter();
            // optional, configure the DWT run without a debugger connected
            cx.core.DCB.enable_trace();
        }
        #[task(schedule = [b])]
        fn a(cx: a::Context) {
            // ..
        }
    };
    }