mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-25 19:39:32 +01:00
Add migration to 0.6 along with updated documentation
This commit is contained in:
parent
163edd7579
commit
9ca10b0d8c
14 changed files with 140 additions and 73 deletions
|
@ -9,7 +9,7 @@ is required to follow along.
|
||||||
|
|
||||||
[repository]: https://github.com/rtic-rs/cortex-m-rtic
|
[repository]: https://github.com/rtic-rs/cortex-m-rtic
|
||||||
|
|
||||||
To run the examples on your laptop / PC you'll need the `qemu-system-arm`
|
To run the examples on your computer you'll need the `qemu-system-arm`
|
||||||
program. Check [the embedded Rust book] for instructions on how to set up an
|
program. Check [the embedded Rust book] for instructions on how to set up an
|
||||||
embedded development environment that includes QEMU.
|
embedded development environment that includes QEMU.
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ The framework provides an abstraction to share data between any of the contexts
|
||||||
we saw in the previous section (task handlers, `init` and `idle`): resources.
|
we saw in the previous section (task handlers, `init` and `idle`): resources.
|
||||||
|
|
||||||
Resources are data visible only to functions declared within the `#[app]`
|
Resources are data visible only to functions declared within the `#[app]`
|
||||||
pseudo-module. The framework gives the user complete control over which context
|
module. The framework gives the user complete control over which context
|
||||||
can access which resource.
|
can access which resource.
|
||||||
|
|
||||||
All resources are declared as a single `struct` within the `#[app]`
|
All resources are declared as a single `struct` within the `#[app]`
|
||||||
pseudo-module. Each field in the structure corresponds to a different resource.
|
module. Each field in the structure corresponds to a different resource.
|
||||||
Resources can optionally be given an initial value using the `#[init]`
|
Resources can optionally be given an initial value using the `#[init]`
|
||||||
attribute. Resources that are not given an initial value are referred to as
|
attribute. Resources that are not given an initial value are referred to as
|
||||||
*late* resources and are covered in more detail in a follow-up section in this
|
*late* resources and are covered in more detail in a follow-up section in this
|
||||||
|
|
|
@ -92,7 +92,7 @@ following snippet:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(..)]
|
#[rtic::app(..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
#[init(spawn = [foo, bar])]
|
#[init(spawn = [foo, bar])]
|
||||||
fn init(cx: init::Context) {
|
fn init(cx: init::Context) {
|
||||||
cx.spawn.foo().unwrap();
|
cx.spawn.foo().unwrap();
|
||||||
|
@ -113,5 +113,5 @@ const APP: () = {
|
||||||
fn bar(cx: bar::Context, payload: i32) {
|
fn bar(cx: bar::Context, payload: i32) {
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -139,7 +139,7 @@ $ tail target/rtic-expansion.rs
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[doc = r" Implementation details"]
|
#[doc = r" Implementation details"]
|
||||||
const APP: () = {
|
mod app {
|
||||||
#[doc = r" Always include the device crate which contains the vector table"]
|
#[doc = r" Always include the device crate which contains the vector table"]
|
||||||
use lm3s6965 as _;
|
use lm3s6965 as _;
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -152,7 +152,7 @@ const APP: () = {
|
||||||
rtic::export::wfi()
|
rtic::export::wfi()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand
|
Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Types, Send and Sync
|
# Types, Send and Sync
|
||||||
|
|
||||||
Every function within the `APP` pseudo-module has a `Context` structure as its
|
Every function within the `app` module has a `Context` structure as its
|
||||||
first parameter. All the fields of these structures have predictable,
|
first parameter. All the fields of these structures have predictable,
|
||||||
non-anonymous types so you can write plain functions that take them as arguments.
|
non-anonymous types so you can write plain functions that take them as arguments.
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ To achieve the fine-grained access control where tasks can only access the
|
||||||
static variables (resources) that they have specified in their RTIC attribute
|
static variables (resources) that they have specified in their RTIC attribute
|
||||||
the RTIC framework performs a source code level transformation. This
|
the RTIC framework performs a source code level transformation. This
|
||||||
transformation consists of placing the resources (static variables) specified by
|
transformation consists of placing the resources (static variables) specified by
|
||||||
the user *inside* a `const` item and the user code *outside* the `const` item.
|
the user *inside* a module and the user code *outside* the module.
|
||||||
This makes it impossible for the user code to refer to these static variables.
|
This makes it impossible for the user code to refer to these static variables.
|
||||||
|
|
||||||
Access to the resources is then given to each task using a `Resources` struct
|
Access to the resources is then given to each task using a `Resources` struct
|
||||||
|
@ -29,7 +29,7 @@ happens behind the scenes:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
static mut X: u64: 0;
|
static mut X: u64: 0;
|
||||||
static mut Y: bool: 0;
|
static mut Y: bool: 0;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..
|
// ..
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The framework produces codes like this:
|
The framework produces codes like this:
|
||||||
|
@ -103,8 +103,8 @@ pub mod bar {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation details
|
/// Implementation details
|
||||||
const APP: () = {
|
mod app {
|
||||||
// everything inside this `const` item is hidden from user code
|
// everything inside this module is hidden from user code
|
||||||
|
|
||||||
static mut X: u64 = 0;
|
static mut X: u64 = 0;
|
||||||
static mut Y: bool = 0;
|
static mut Y: bool = 0;
|
||||||
|
@ -154,5 +154,5 @@ const APP: () = {
|
||||||
// ..
|
// ..
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -28,7 +28,7 @@ An example to illustrate the ceiling analysis:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
struct Resources {
|
struct Resources {
|
||||||
// accessed by `foo` (prio = 1) and `bar` (prio = 2)
|
// accessed by `foo` (prio = 1) and `bar` (prio = 2)
|
||||||
// -> CEILING = 2
|
// -> CEILING = 2
|
||||||
|
@ -80,5 +80,5 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..
|
// ..
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -32,7 +32,7 @@ The example below shows the different types handed out to each task:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mut app {
|
||||||
struct Resources {
|
struct Resources {
|
||||||
#[init(0)]
|
#[init(0)]
|
||||||
x: u64,
|
x: u64,
|
||||||
|
@ -57,7 +57,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..
|
// ..
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now let's see how these types are created by the framework.
|
Now let's see how these types are created by the framework.
|
||||||
|
@ -99,7 +99,7 @@ pub mod bar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
static mut x: u64 = 0;
|
static mut x: u64 = 0;
|
||||||
|
|
||||||
impl rtic::Mutex for resources::x {
|
impl rtic::Mutex for resources::x {
|
||||||
|
@ -129,7 +129,7 @@ const APP: () = {
|
||||||
// ..
|
// ..
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## `lock`
|
## `lock`
|
||||||
|
@ -225,7 +225,7 @@ Consider this program:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
struct Resources {
|
struct Resources {
|
||||||
#[init(0)]
|
#[init(0)]
|
||||||
x: u64,
|
x: u64,
|
||||||
|
@ -277,7 +277,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..
|
// ..
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The code generated by the framework looks like this:
|
The code generated by the framework looks like this:
|
||||||
|
@ -315,7 +315,7 @@ pub mod foo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
use cortex_m::register::basepri;
|
use cortex_m::register::basepri;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -368,7 +368,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// repeat for resource `y`
|
// repeat for resource `y`
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
At the end the compiler will optimize the function `foo` into something like
|
At the end the compiler will optimize the function `foo` into something like
|
||||||
|
@ -430,7 +430,7 @@ handler through preemption. This is best observed in the following example:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
struct Resources {
|
struct Resources {
|
||||||
#[init(0)]
|
#[init(0)]
|
||||||
x: u64,
|
x: u64,
|
||||||
|
@ -484,7 +484,7 @@ const APP: () = {
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would
|
IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would
|
||||||
|
@ -493,7 +493,7 @@ be a bug in the RTIC code generator.
|
||||||
``` rust
|
``` rust
|
||||||
// code generated by RTIC
|
// code generated by RTIC
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
// ..
|
// ..
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -513,7 +513,7 @@ const APP: () = {
|
||||||
// BUG: FORGOT to roll back the BASEPRI to the snapshot value we took before
|
// BUG: FORGOT to roll back the BASEPRI to the snapshot value we took before
|
||||||
basepri::write(initial);
|
basepri::write(initial);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The consequence is that `idle` will run at a dynamic priority of `2` and in fact
|
The consequence is that `idle` will run at a dynamic priority of `2` and in fact
|
||||||
|
|
|
@ -13,7 +13,7 @@ This example gives you an idea of the code that the RTIC framework runs:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = lm3s6965)]
|
#[rtic::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
#[init]
|
#[init]
|
||||||
fn init(c: init::Context) {
|
fn init(c: init::Context) {
|
||||||
// .. user code ..
|
// .. user code ..
|
||||||
|
@ -28,7 +28,7 @@ const APP: () = {
|
||||||
fn foo(c: foo::Context) {
|
fn foo(c: foo::Context) {
|
||||||
// .. user code ..
|
// .. user code ..
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The framework generates an entry point that looks like this:
|
The framework generates an entry point that looks like this:
|
||||||
|
|
|
@ -10,7 +10,7 @@ initialize late resources.
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
struct Resources {
|
struct Resources {
|
||||||
x: Thing,
|
x: Thing,
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..
|
// ..
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The code generated by the framework looks like this:
|
The code generated by the framework looks like this:
|
||||||
|
@ -69,7 +69,7 @@ pub mod foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation details
|
/// Implementation details
|
||||||
const APP: () = {
|
mod app {
|
||||||
// uninitialized static
|
// uninitialized static
|
||||||
static mut x: MaybeUninit<Thing> = MaybeUninit::uninit();
|
static mut x: MaybeUninit<Thing> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ const APP: () = {
|
||||||
// ..
|
// ..
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
An important detail here is that `interrupt::enable` behaves like a *compiler
|
An important detail here is that `interrupt::enable` behaves like a *compiler
|
||||||
|
|
|
@ -12,7 +12,7 @@ are discouraged from directly invoking an interrupt handler.
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
#[init]
|
#[init]
|
||||||
fn init(c: init::Context) { .. }
|
fn init(c: init::Context) { .. }
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ const APP: () = {
|
||||||
// in aliasing of the static variable `X`
|
// in aliasing of the static variable `X`
|
||||||
unsafe { UART0() }
|
unsafe { UART0() }
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The RTIC framework must generate the interrupt handler code that calls the user
|
The RTIC framework must generate the interrupt handler code that calls the user
|
||||||
|
@ -57,7 +57,7 @@ fn bar(c: bar::Context) {
|
||||||
// .. user code ..
|
// .. user code ..
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
// everything in this block is not visible to user code
|
// everything in this block is not visible to user code
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -69,7 +69,7 @@ const APP: () = {
|
||||||
unsafe fn USART1() {
|
unsafe fn USART1() {
|
||||||
bar(..);
|
bar(..);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## By hardware
|
## By hardware
|
||||||
|
|
|
@ -28,7 +28,7 @@ Consider this example:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
// ..
|
// ..
|
||||||
|
|
||||||
#[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])]
|
#[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])]
|
||||||
|
@ -51,7 +51,7 @@ const APP: () = {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART1();
|
fn UART1();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The framework produces the following task dispatcher which consists of an
|
The framework produces the following task dispatcher which consists of an
|
||||||
|
@ -62,7 +62,7 @@ fn bar(c: bar::Context) {
|
||||||
// .. user code ..
|
// .. user code ..
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
use heapless::spsc::Queue;
|
use heapless::spsc::Queue;
|
||||||
use cortex_m::register::basepri;
|
use cortex_m::register::basepri;
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ const APP: () = {
|
||||||
// BASEPRI invariant
|
// BASEPRI invariant
|
||||||
basepri::write(snapshot);
|
basepri::write(snapshot);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Spawning a task
|
## Spawning a task
|
||||||
|
@ -144,7 +144,7 @@ mod foo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
// ..
|
// ..
|
||||||
|
|
||||||
// Priority ceiling for the producer endpoint of the `RQ1`
|
// Priority ceiling for the producer endpoint of the `RQ1`
|
||||||
|
@ -194,7 +194,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Using `bar_FQ` to limit the number of `bar` tasks that can be spawned may seem
|
Using `bar_FQ` to limit the number of `bar` tasks that can be spawned may seem
|
||||||
|
@ -211,7 +211,7 @@ fn baz(c: baz::Context, input: u64) {
|
||||||
// .. user code ..
|
// .. user code ..
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
// ..
|
// ..
|
||||||
|
|
||||||
// Now we show the full contents of the `Ready` struct
|
// Now we show the full contents of the `Ready` struct
|
||||||
|
@ -263,13 +263,13 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
And now let's look at the real implementation of the task dispatcher:
|
And now let's look at the real implementation of the task dispatcher:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
const APP: () = {
|
mod app {
|
||||||
// ..
|
// ..
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -304,7 +304,7 @@ const APP: () = {
|
||||||
// BASEPRI invariant
|
// BASEPRI invariant
|
||||||
basepri::write(snapshot);
|
basepri::write(snapshot);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`INPUTS` plus `FQ`, the free queue, is effectively a memory pool. However,
|
`INPUTS` plus `FQ`, the free queue, is effectively a memory pool. However,
|
||||||
|
@ -357,7 +357,7 @@ Consider the following example:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
#[idle(spawn = [foo, bar])]
|
#[idle(spawn = [foo, bar])]
|
||||||
fn idle(c: idle::Context) -> ! {
|
fn idle(c: idle::Context) -> ! {
|
||||||
// ..
|
// ..
|
||||||
|
@ -382,7 +382,7 @@ const APP: () = {
|
||||||
fn quux(c: quux::Context) {
|
fn quux(c: quux::Context) {
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This is how the ceiling analysis would go:
|
This is how the ceiling analysis would go:
|
||||||
|
|
|
@ -12,7 +12,7 @@ Let's see how this in implemented in code. Consider the following program:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
// ..
|
// ..
|
||||||
|
|
||||||
#[task(capacity = 2, schedule = [foo])]
|
#[task(capacity = 2, schedule = [foo])]
|
||||||
|
@ -24,7 +24,7 @@ const APP: () = {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## `schedule`
|
## `schedule`
|
||||||
|
@ -46,7 +46,7 @@ mod foo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant;
|
type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant;
|
||||||
|
|
||||||
// all tasks that can be `schedule`-d
|
// all tasks that can be `schedule`-d
|
||||||
|
@ -100,7 +100,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This looks very similar to the `Spawn` implementation. In fact, the same
|
This looks very similar to the `Spawn` implementation. In fact, the same
|
||||||
|
@ -123,7 +123,7 @@ is up.
|
||||||
Let's see the associated code.
|
Let's see the associated code.
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
const APP: () = {
|
mod app {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn SysTick() {
|
fn SysTick() {
|
||||||
const PRIORITY: u8 = 1;
|
const PRIORITY: u8 = 1;
|
||||||
|
@ -146,7 +146,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This looks similar to a task dispatcher except that instead of running the
|
This looks similar to a task dispatcher except that instead of running the
|
||||||
|
@ -197,7 +197,7 @@ able to insert the task in the timer queue; this lets us omit runtime checks.
|
||||||
|
|
||||||
## System timer priority
|
## System timer priority
|
||||||
|
|
||||||
The priority of the system timer can't set by the user; it is chosen by the
|
The priority of the system timer can't be set by the user; it is chosen by the
|
||||||
framework. To ensure that lower priority tasks don't prevent higher priority
|
framework. To ensure that lower priority tasks don't prevent higher priority
|
||||||
tasks from running we choose the priority of the system timer to be the maximum
|
tasks from running we choose the priority of the system timer to be the maximum
|
||||||
of all the `schedule`-able tasks.
|
of all the `schedule`-able tasks.
|
||||||
|
@ -222,7 +222,7 @@ To illustrate, consider the following example:
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = ..)]
|
#[rtic::app(device = ..)]
|
||||||
const APP: () = {
|
mod app {
|
||||||
#[task(priority = 3, spawn = [baz])]
|
#[task(priority = 3, spawn = [baz])]
|
||||||
fn foo(c: foo::Context) {
|
fn foo(c: foo::Context) {
|
||||||
// ..
|
// ..
|
||||||
|
@ -237,7 +237,7 @@ const APP: () = {
|
||||||
fn baz(c: baz::Context) {
|
fn baz(c: baz::Context) {
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The ceiling analysis would go like this:
|
The ceiling analysis would go like this:
|
||||||
|
@ -246,7 +246,7 @@ The ceiling analysis would go like this:
|
||||||
`SysTick` must run at the highest priority between these two, that is `3`.
|
`SysTick` must run at the highest priority between these two, that is `3`.
|
||||||
|
|
||||||
- `foo::Spawn` (prio = 3) and `bar::Schedule` (prio = 2) contend over the
|
- `foo::Spawn` (prio = 3) and `bar::Schedule` (prio = 2) contend over the
|
||||||
consumer endpoind of `baz_FQ`; this leads to a priority ceiling of `3`.
|
consumer endpoint of `baz_FQ`; this leads to a priority ceiling of `3`.
|
||||||
|
|
||||||
- `bar::Schedule` (prio = 2) has exclusive access over the consumer endpoint of
|
- `bar::Schedule` (prio = 2) has exclusive access over the consumer endpoint of
|
||||||
`foo_FQ`; thus the priority ceiling of `foo_FQ` is effectively `2`.
|
`foo_FQ`; thus the priority ceiling of `foo_FQ` is effectively `2`.
|
||||||
|
@ -270,7 +270,7 @@ run; this `Instant` is read in the task dispatcher and passed to the user code
|
||||||
as part of the task context.
|
as part of the task context.
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
const APP: () = {
|
mod app {
|
||||||
// ..
|
// ..
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -303,7 +303,7 @@ const APP: () = {
|
||||||
// BASEPRI invariant
|
// BASEPRI invariant
|
||||||
basepri::write(snapshot);
|
basepri::write(snapshot);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Conversely, the `spawn` implementation needs to write a value to the `INSTANTS`
|
Conversely, the `spawn` implementation needs to write a value to the `INSTANTS`
|
||||||
|
@ -333,7 +333,7 @@ mod foo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: () = {
|
mod app {
|
||||||
impl<'a> foo::Spawn<'a> {
|
impl<'a> foo::Spawn<'a> {
|
||||||
/// Spawns the `baz` task
|
/// Spawns the `baz` task
|
||||||
pub fn baz(&self, message: u64) -> Result<(), u64> {
|
pub fn baz(&self, message: u64) -> Result<(), u64> {
|
||||||
|
@ -364,5 +364,5 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,14 +1,81 @@
|
||||||
# Migrating from v0.4.x to v0.5.0
|
# Migration of RTIC
|
||||||
|
|
||||||
|
## Migrating from v0.5.x to v0.6.0
|
||||||
|
|
||||||
|
This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framework.
|
||||||
|
|
||||||
|
### `Cargo.toml` - version bump
|
||||||
|
|
||||||
|
Change the version of `cortex-m-rtic` to `"0.6.0"`.
|
||||||
|
|
||||||
|
### Module instead of Const
|
||||||
|
|
||||||
|
With the support of attributes on modules the `const APP` workaround is not needed.
|
||||||
|
|
||||||
|
Change
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[rtic::app(/* .. */)]
|
||||||
|
const APP: () = {
|
||||||
|
[code here]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
into
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[rtic::app(/* .. */)]
|
||||||
|
mod app {
|
||||||
|
[code here]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that a regular Rust module is used it means it is possible to have custom
|
||||||
|
user code within that module.
|
||||||
|
Additionally, it means that `use`-statements for resources etc may be required.
|
||||||
|
|
||||||
|
### Init always returns late resources
|
||||||
|
|
||||||
|
In order to make the API more symmetric the #[init]-task always returns a late resource.
|
||||||
|
|
||||||
|
From this:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[rtic::app(device = lm3s6965)]
|
||||||
|
mod app {
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) {
|
||||||
|
rtic::pend(Interrupt::UART0);
|
||||||
|
}
|
||||||
|
[more code]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
to this:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[rtic::app(device = lm3s6965)]
|
||||||
|
mod app {
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) -> init::LateResources {
|
||||||
|
rtic::pend(Interrupt::UART0);
|
||||||
|
|
||||||
|
init::LateResources {}
|
||||||
|
}
|
||||||
|
[more code]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migrating from v0.4.x to v0.5.0
|
||||||
|
|
||||||
This section covers how to upgrade an application written against RTIC v0.4.x to
|
This section covers how to upgrade an application written against RTIC v0.4.x to
|
||||||
the version v0.5.0 of the framework.
|
the version v0.5.0 of the framework.
|
||||||
|
|
||||||
## `Cargo.toml`
|
### `Cargo.toml`
|
||||||
|
|
||||||
First, the version of the `cortex-m-rtic` dependency needs to be updated to
|
First, the version of the `cortex-m-rtic` dependency needs to be updated to
|
||||||
`"0.5.0"`. The `timer-queue` feature needs to be removed.
|
`"0.5.0"`. The `timer-queue` feature needs to be removed.
|
||||||
|
|
||||||
|
|
||||||
``` toml
|
``` toml
|
||||||
[dependencies.cortex-m-rtic]
|
[dependencies.cortex-m-rtic]
|
||||||
# change this
|
# change this
|
||||||
|
@ -22,7 +89,7 @@ features = ["timer-queue"]
|
||||||
# ^^^^^^^^^^^^^
|
# ^^^^^^^^^^^^^
|
||||||
```
|
```
|
||||||
|
|
||||||
## `Context` argument
|
### `Context` argument
|
||||||
|
|
||||||
All functions inside the `#[rtic::app]` item need to take as first argument a
|
All functions inside the `#[rtic::app]` item need to take as first argument a
|
||||||
`Context` structure. This `Context` type will contain the variables that were
|
`Context` structure. This `Context` type will contain the variables that were
|
||||||
|
@ -74,7 +141,7 @@ const APP: () = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## Resources
|
### Resources
|
||||||
|
|
||||||
The syntax used to declare resources has been changed from `static mut`
|
The syntax used to declare resources has been changed from `static mut`
|
||||||
variables to a `struct Resources`.
|
variables to a `struct Resources`.
|
||||||
|
@ -98,7 +165,7 @@ const APP: () = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## Device peripherals
|
### Device peripherals
|
||||||
|
|
||||||
If your application was accessing the device peripherals in `#[init]` through
|
If your application was accessing the device peripherals in `#[init]` through
|
||||||
the `device` variable then you'll need to add `peripherals = true` to the
|
the `device` variable then you'll need to add `peripherals = true` to the
|
||||||
|
@ -136,7 +203,7 @@ const APP: () = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## `#[interrupt]` and `#[exception]`
|
### `#[interrupt]` and `#[exception]`
|
||||||
|
|
||||||
The `#[interrupt]` and `#[exception]` attributes have been removed. To declare
|
The `#[interrupt]` and `#[exception]` attributes have been removed. To declare
|
||||||
hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument.
|
hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument.
|
||||||
|
@ -182,7 +249,7 @@ const APP: () = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## `schedule`
|
### `schedule`
|
||||||
|
|
||||||
The `timer-queue` feature has been removed. To use the `schedule` API one must
|
The `timer-queue` feature has been removed. To use the `schedule` API one must
|
||||||
first define the monotonic timer the runtime will use using the `monotonic`
|
first define the monotonic timer the runtime will use using the `monotonic`
|
||||||
|
|
Loading…
Reference in a new issue