mirror of
https://github.com/rtic-rs/rtic.git
synced 2025-12-18 13:55:23 +01:00
Rename RTFM to RTIC
This commit is contained in:
parent
4a0393f756
commit
602a5b4374
129 changed files with 454 additions and 454 deletions
|
|
@ -2,4 +2,4 @@
|
|||
authors = ["Jorge Aparicio"]
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "Real Time For the Masses"
|
||||
title = "Real-Time Interrupt-driven Concurrency"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Summary
|
||||
|
||||
[Preface](./preface.md)
|
||||
- [RTFM by example](./by-example.md)
|
||||
- [RTIC by example](./by-example.md)
|
||||
- [The `app` attribute](./by-example/app.md)
|
||||
- [Resources](./by-example/resources.md)
|
||||
- [Software tasks](./by-example/tasks.md)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
# RTFM by example
|
||||
# RTIC by example
|
||||
|
||||
This part of the book introduces the Real Time For the Masses (RTFM) framework
|
||||
This part of the book introduces the Real-Time Interrupt-driven Concurrency (RTIC) framework
|
||||
to new users by walking them through examples of increasing complexity.
|
||||
|
||||
All examples in this part of the book can be found in the GitHub [repository] of
|
||||
the project, and most of the examples can be run on QEMU so no special hardware
|
||||
is required to follow along.
|
||||
|
||||
[repository]: https://github.com/rtfm-rs/cortex-m-rtfm
|
||||
[repository]: https://github.com/rtic-rs/cortex-m-rtic
|
||||
|
||||
To run the examples on your laptop / PC you'll need the `qemu-system-arm`
|
||||
program. Check [the embedded Rust book] for instructions on how to set up an
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
# The `app` attribute
|
||||
|
||||
This is the smallest possible RTFM application:
|
||||
This is the smallest possible RTIC application:
|
||||
|
||||
``` rust
|
||||
{{#include ../../../../examples/smallest.rs}}
|
||||
```
|
||||
|
||||
All RTFM applications use the [`app`] attribute (`#[app(..)]`). This attribute
|
||||
All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute
|
||||
must be applied to a `const` item that contains items. The `app` attribute has
|
||||
a mandatory `device` argument that takes a *path* as a value. This path must
|
||||
point to a *peripheral access crate* (PAC) generated using [`svd2rust`]
|
||||
**v0.14.x** or newer. The `app` attribute will expand into a suitable entry
|
||||
point so it's not required to use the [`cortex_m_rt::entry`] attribute.
|
||||
|
||||
[`app`]: ../../../api/cortex_m_rtfm_macros/attr.app.html
|
||||
[`app`]: ../../../api/cortex_m_rtic_macros/attr.app.html
|
||||
[`svd2rust`]: https://crates.io/crates/svd2rust
|
||||
[`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html
|
||||
|
||||
> **ASIDE**: Some of you may be wondering why we are using a `const` item as a
|
||||
> module and not a proper `mod` item. The reason is that using attributes on
|
||||
> modules requires a feature gate, which requires a nightly toolchain. To make
|
||||
> RTFM work on stable we use the `const` item instead. When more parts of macros
|
||||
> RTIC work on stable we use the `const` item instead. When more parts of macros
|
||||
> 1.2 are stabilized we'll move from a `const` item to a `mod` item and
|
||||
> eventually to a crate level attribute (`#![app]`).
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ to Cortex-M and, optionally, device specific peripherals through the `core` and
|
|||
`static mut` variables declared at the beginning of `init` will be transformed
|
||||
into `&'static mut` references that are safe to access.
|
||||
|
||||
[`rtfm::Peripherals`]: ../../api/rtfm/struct.Peripherals.html
|
||||
[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
|
||||
|
||||
The example below shows the types of the `core` and `device` fields and
|
||||
showcases safe access to a `static mut` variable. The `device` field is only
|
||||
|
|
@ -106,9 +106,9 @@ mut` variables are safe to use within a hardware task.
|
|||
$ cargo run --example hardware
|
||||
{{#include ../../../../ci/expected/hardware.run}}```
|
||||
|
||||
So far all the RTFM applications we have seen look no different than the
|
||||
So far all the RTIC applications we have seen look no different than the
|
||||
applications one can write using only the `cortex-m-rt` crate. From this point
|
||||
we start introducing features unique to RTFM.
|
||||
we start introducing features unique to RTIC.
|
||||
|
||||
## Priorities
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Starting a new project
|
||||
|
||||
Now that you have learned about the main features of the RTFM framework you can
|
||||
Now that you have learned about the main features of the RTIC framework you can
|
||||
try it out on your hardware by following these instructions.
|
||||
|
||||
1. Instantiate the [`cortex-m-quickstart`] template.
|
||||
|
|
@ -36,19 +36,19 @@ $ cargo add lm3s6965 --vers 0.1.3
|
|||
$ rm memory.x build.rs
|
||||
```
|
||||
|
||||
3. Add the `cortex-m-rtfm` crate as a dependency.
|
||||
3. Add the `cortex-m-rtic` crate as a dependency.
|
||||
|
||||
``` console
|
||||
$ cargo add cortex-m-rtfm --allow-prerelease
|
||||
$ cargo add cortex-m-rtic --allow-prerelease
|
||||
```
|
||||
|
||||
4. Write your RTFM application.
|
||||
4. Write your RTIC application.
|
||||
|
||||
Here I'll use the `init` example from the `cortex-m-rtfm` crate.
|
||||
Here I'll use the `init` example from the `cortex-m-rtic` crate.
|
||||
|
||||
``` console
|
||||
$ curl \
|
||||
-L https://github.com/rtfm-rs/cortex-m-rtfm/raw/v0.5.0/examples/init.rs \
|
||||
-L https://github.com/rtic-rs/cortex-m-rtic/raw/v0.5.0/examples/init.rs \
|
||||
> src/main.rs
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ instead of a reference. This resource proxy is a structure that implements the
|
|||
[`Mutex`] trait. The only method on this trait, [`lock`], runs its closure
|
||||
argument in a critical section.
|
||||
|
||||
[`Mutex`]: ../../../api/rtfm/trait.Mutex.html
|
||||
[`lock`]: ../../../api/rtfm/trait.Mutex.html#method.lock
|
||||
[`Mutex`]: ../../../api/rtic/trait.Mutex.html
|
||||
[`lock`]: ../../../api/rtic/trait.Mutex.html#method.lock
|
||||
|
||||
The critical section created by the `lock` API is based on dynamic priorities:
|
||||
it temporarily raises the dynamic priority of the context to a *ceiling*
|
||||
|
|
@ -113,7 +113,7 @@ shared reference (`&-`) to the resource, limiting the operations it can perform
|
|||
on it, but where a shared reference is enough this approach reduces the number
|
||||
of required locks.
|
||||
|
||||
Note that in this release of RTFM it is not possible to request both exclusive
|
||||
Note that in this release of RTIC it is not possible to request both exclusive
|
||||
access (`&mut-`) and shared access (`&-`) to the *same* resource from different
|
||||
tasks. Attempting to do so will result in a compile error.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
# Software tasks
|
||||
|
||||
In addition to hardware tasks, which are invoked by the hardware in response to
|
||||
hardware events, RTFM also supports *software* tasks which can be spawned by the
|
||||
hardware events, RTIC also supports *software* tasks which can be spawned by the
|
||||
application from any execution context.
|
||||
|
||||
Software tasks can also be assigned priorities and, under the hood, are
|
||||
dispatched from interrupt handlers. RTFM requires that free interrupts are
|
||||
dispatched from interrupt handlers. RTIC requires that free interrupts are
|
||||
declared in an `extern` block when using software tasks; some of these free
|
||||
interrupts will be used to dispatch the software tasks. An advantage of software
|
||||
tasks over hardware tasks is that many tasks can be mapped to a single interrupt
|
||||
|
|
@ -45,7 +45,7 @@ $ cargo run --example message
|
|||
|
||||
## Capacity
|
||||
|
||||
RTFM does *not* perform any form of heap-based memory allocation. The memory
|
||||
RTIC does *not* perform any form of heap-based memory allocation. The memory
|
||||
required to store messages is statically reserved. By default the framework
|
||||
minimizes the memory footprint of the application so each task has a message
|
||||
"capacity" of 1: meaning that at most one message can be posted to the task
|
||||
|
|
@ -91,7 +91,7 @@ its message buffer will never be emptied. This situation is depicted in the
|
|||
following snippet:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(..)]
|
||||
#[rtic::app(..)]
|
||||
const APP: () = {
|
||||
#[init(spawn = [foo, bar])]
|
||||
fn init(cx: init::Context) {
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ type (see [`core::time::Duration`]) and this `Duration` type must implement the
|
|||
integer. If the result of the conversion doesn't fit in a 32-bit number then the
|
||||
operation must return an error, any error type.
|
||||
|
||||
[`Monotonic`]: ../../../api/rtfm/trait.Monotonic.html
|
||||
[`Monotonic`]: ../../../api/rtic/trait.Monotonic.html
|
||||
[std-instant]: https://doc.rust-lang.org/std/time/struct.Instant.html
|
||||
[`core::time::Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html
|
||||
|
||||
For ARMv7+ targets the `rtfm` crate provides a `Monotonic` implementation based
|
||||
For ARMv7+ targets the `rtic` crate provides a `Monotonic` implementation based
|
||||
on the built-in CYCle CouNTer (CYCCNT). Note that this is a 32-bit timer clocked
|
||||
at the frequency of the CPU and as such it is not suitable for tracking time
|
||||
spans in the order of seconds.
|
||||
|
|
@ -36,7 +36,7 @@ executed must be passed as the first argument of the `schedule` invocation.
|
|||
|
||||
Additionally, the chosen `monotonic` timer must be configured and initialized
|
||||
during the `#[init]` phase. Note that this is *also* the case if you choose to
|
||||
use the `CYCCNT` provided by the `cortex-m-rtfm` crate.
|
||||
use the `CYCCNT` provided by the `cortex-m-rtic` crate.
|
||||
|
||||
The example below schedules two tasks from `init`: `foo` and `bar`. `foo` is
|
||||
scheduled to run 8 million clock cycles in the future. Next, `bar` is scheduled
|
||||
|
|
@ -61,7 +61,7 @@ console:
|
|||
When the `schedule` API is being used the runtime internally uses the `SysTick`
|
||||
interrupt handler and the system timer peripheral (`SYST`) so neither can be
|
||||
used by the application. This is accomplished by changing the type of
|
||||
`init::Context.core` from `cortex_m::Peripherals` to `rtfm::Peripherals`. The
|
||||
`init::Context.core` from `cortex_m::Peripherals` to `rtic::Peripherals`. The
|
||||
latter structure contains all the fields of the former minus the `SYST` one.
|
||||
|
||||
## Periodic tasks
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ appear as *different* types in different contexts one cannot refactor a common
|
|||
operation that uses resources into a plain function; however, such refactor is
|
||||
possible using *generics*.
|
||||
|
||||
All resource proxies implement the `rtfm::Mutex` trait. On the other hand,
|
||||
All resource proxies implement the `rtic::Mutex` trait. On the other hand,
|
||||
unique references (`&mut-`) do *not* implement this trait (due to limitations in
|
||||
the trait system) but one can wrap these references in the [`rtfm::Exclusive`]
|
||||
the trait system) but one can wrap these references in the [`rtic::Exclusive`]
|
||||
newtype which does implement the `Mutex` trait. With the help of this newtype
|
||||
one can write a generic function that operates on generic resources and call it
|
||||
from different tasks to perform some operation on the same set of resources.
|
||||
Here's one such example:
|
||||
|
||||
[`rtfm::Exclusive`]: ../../../api/rtfm/struct.Exclusive.html
|
||||
[`rtic::Exclusive`]: ../../../api/rtic/struct.Exclusive.html
|
||||
|
||||
``` rust
|
||||
{{#include ../../../../examples/generics.rs}}
|
||||
|
|
@ -51,8 +51,8 @@ $ cargo run --example cfg
|
|||
|
||||
## Running tasks from RAM
|
||||
|
||||
The main goal of moving the specification of RTFM applications to attributes in
|
||||
RTFM v0.4.0 was to allow inter-operation with other attributes. For example, the
|
||||
The main goal of moving the specification of RTIC applications to attributes in
|
||||
RTIC v0.4.0 was to allow inter-operation with other attributes. For example, the
|
||||
`link_section` attribute can be applied to tasks to place them in RAM; this can
|
||||
improve performance in some cases.
|
||||
|
||||
|
|
@ -119,22 +119,22 @@ $ cargo run --example pool
|
|||
|
||||
## Inspecting the expanded code
|
||||
|
||||
`#[rtfm::app]` is a procedural macro that produces support code. If for some
|
||||
`#[rtic::app]` is a procedural macro that produces support code. If for some
|
||||
reason you need to inspect the code generated by this macro you have two
|
||||
options:
|
||||
|
||||
You can inspect the file `rtfm-expansion.rs` inside the `target` directory. This
|
||||
file contains the expansion of the `#[rtfm::app]` item (not your whole program!)
|
||||
of the *last built* (via `cargo build` or `cargo check`) RTFM application. The
|
||||
You can inspect the file `rtic-expansion.rs` inside the `target` directory. This
|
||||
file contains the expansion of the `#[rtic::app]` item (not your whole program!)
|
||||
of the *last built* (via `cargo build` or `cargo check`) RTIC application. The
|
||||
expanded code is not pretty printed by default so you'll want to run `rustfmt`
|
||||
over it before you read it.
|
||||
|
||||
``` console
|
||||
$ cargo build --example foo
|
||||
|
||||
$ rustfmt target/rtfm-expansion.rs
|
||||
$ rustfmt target/rtic-expansion.rs
|
||||
|
||||
$ tail target/rtfm-expansion.rs
|
||||
$ tail target/rtic-expansion.rs
|
||||
```
|
||||
|
||||
``` rust
|
||||
|
|
@ -144,19 +144,19 @@ const APP: () = {
|
|||
use lm3s6965 as _;
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn main() -> ! {
|
||||
rtfm::export::interrupt::disable();
|
||||
let mut core: rtfm::export::Peripherals = core::mem::transmute(());
|
||||
rtic::export::interrupt::disable();
|
||||
let mut core: rtic::export::Peripherals = core::mem::transmute(());
|
||||
core.SCB.scr.modify(|r| r | 1 << 1);
|
||||
rtfm::export::interrupt::enable();
|
||||
rtic::export::interrupt::enable();
|
||||
loop {
|
||||
rtfm::export::wfi()
|
||||
rtic::export::wfi()
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Or, you can use the [`cargo-expand`] subcommand. This subcommand will expand
|
||||
*all* the macros, including the `#[rtfm::app]` attribute, and modules in your
|
||||
*all* the macros, including the `#[rtic::app]` attribute, and modules in your
|
||||
crate and print the output to the console.
|
||||
|
||||
[`cargo-expand`]: https://crates.io/crates/cargo-expand
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ The example below shows the different types generates by the `app` attribute.
|
|||
## `Send`
|
||||
|
||||
[`Send`] is a marker trait for "types that can be transferred across thread
|
||||
boundaries", according to its definition in `core`. In the context of RTFM the
|
||||
boundaries", according to its definition in `core`. In the context of RTIC the
|
||||
`Send` trait is only required where it's possible to transfer a value between
|
||||
tasks that run at *different* priorities. This occurs in a few places: in
|
||||
message passing, in shared resources and in the initialization of late
|
||||
|
|
@ -57,7 +57,7 @@ the `Send` trait.
|
|||
|
||||
Similarly, [`Sync`] is a marker trait for "types for which it is safe to share
|
||||
references between threads", according to its definition in `core`. In the
|
||||
context of RTFM the `Sync` trait is only required where it's possible for two,
|
||||
context of RTIC the `Sync` trait is only required where it's possible for two,
|
||||
or more, tasks that run at different priorities and may get a shared reference
|
||||
(`&-`) to a resource. This only occurs with shared access (`&-`) resources.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Heterogeneous multi-core support
|
||||
|
||||
This section covers the *experimental* heterogeneous multi-core support provided
|
||||
by RTFM behind the `heterogeneous` Cargo feature.
|
||||
by RTIC behind the `heterogeneous` Cargo feature.
|
||||
|
||||
**Content coming soon**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Homogeneous multi-core support
|
||||
|
||||
This section covers the *experimental* homogeneous multi-core support provided
|
||||
by RTFM behind the `homogeneous` Cargo feature.
|
||||
by RTIC behind the `homogeneous` Cargo feature.
|
||||
|
||||
**Content coming soon**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Under the hood
|
||||
|
||||
This section describes the internals of the RTFM framework at a *high level*.
|
||||
This section describes the internals of the RTIC framework at a *high level*.
|
||||
Low level details like the parsing and code generation done by the procedural
|
||||
macro (`#[app]`) will not be explained here. The focus will be the analysis of
|
||||
the user specification and the data structures used by the runtime.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Access control
|
||||
|
||||
One of the core foundations of RTFM is access control. Controlling which parts
|
||||
One of the core foundations of RTIC is access control. Controlling which parts
|
||||
of the program can access which static variables is instrumental to enforcing
|
||||
memory safety.
|
||||
|
||||
|
|
@ -12,8 +12,8 @@ resides in the same scope in which they are declared. Modules give some control
|
|||
over how a static variable can be accessed by they are not flexible enough.
|
||||
|
||||
To achieve the fine-grained access control where tasks can only access the
|
||||
static variables (resources) that they have specified in their RTFM attribute
|
||||
the RTFM framework performs a source code level transformation. This
|
||||
static variables (resources) that they have specified in their RTIC attribute
|
||||
the RTIC framework performs a source code level transformation. This
|
||||
transformation consists of placing the resources (static variables) specified by
|
||||
the user *inside* a `const` item and the user code *outside* the `const` item.
|
||||
This makes it impossible for the user code to refer to these static variables.
|
||||
|
|
@ -28,7 +28,7 @@ The code below is an example of the kind of source level transformation that
|
|||
happens behind the scenes:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
static mut X: u64: 0;
|
||||
static mut Y: bool: 0;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
A resource *priority ceiling*, or just *ceiling*, is the dynamic priority that
|
||||
any task must have to safely access the resource memory. Ceiling analysis is
|
||||
relatively simple but critical to the memory safety of RTFM applications.
|
||||
relatively simple but critical to the memory safety of RTIC applications.
|
||||
|
||||
To compute the ceiling of a resource we must first collect a list of tasks that
|
||||
have access to the resource -- as the RTFM framework enforces access control to
|
||||
have access to the resource -- as the RTIC framework enforces access control to
|
||||
resources at compile time it also has access to this information at compile
|
||||
time. The ceiling of the resource is simply the highest logical priority among
|
||||
those tasks.
|
||||
|
|
@ -27,7 +27,7 @@ gets a unique reference (`&mut-`) to resources.
|
|||
An example to illustrate the ceiling analysis:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
struct Resources {
|
||||
// accessed by `foo` (prio = 1) and `bar` (prio = 2)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
When a resource (static variable) is shared between two, or more, tasks that run
|
||||
at different priorities some form of mutual exclusion is required to mutate the
|
||||
memory in a data race free manner. In RTFM we use priority-based critical
|
||||
memory in a data race free manner. In RTIC we use priority-based critical
|
||||
sections to guarantee mutual exclusion (see the [Immediate Ceiling Priority
|
||||
Protocol][icpp]).
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ task we give it a *resource proxy*, whereas we give a unique reference
|
|||
The example below shows the different types handed out to each task:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
|
|
@ -102,7 +102,7 @@ pub mod bar {
|
|||
const APP: () = {
|
||||
static mut x: u64 = 0;
|
||||
|
||||
impl rtfm::Mutex for resources::x {
|
||||
impl rtic::Mutex for resources::x {
|
||||
type T = u64;
|
||||
|
||||
fn lock<R>(&mut self, f: impl FnOnce(&mut u64) -> R) -> R {
|
||||
|
|
@ -161,7 +161,7 @@ In this particular example we could implement the critical section as follows:
|
|||
> **NOTE:** this is a simplified implementation
|
||||
|
||||
``` rust
|
||||
impl rtfm::Mutex for resources::x {
|
||||
impl rtic::Mutex for resources::x {
|
||||
type T = u64;
|
||||
|
||||
fn lock<R, F>(&mut self, f: F) -> R
|
||||
|
|
@ -224,7 +224,7 @@ provides extra information to the compiler.
|
|||
Consider this program:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
|
|
@ -235,7 +235,7 @@ const APP: () = {
|
|||
|
||||
#[init]
|
||||
fn init() {
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART0);
|
||||
}
|
||||
|
||||
#[interrupt(binds = UART0, priority = 1, resources = [x, y])]
|
||||
|
|
@ -338,7 +338,7 @@ const APP: () = {
|
|||
|
||||
// similarly for `UART0` / `foo` and `UART2` / `baz`
|
||||
|
||||
impl<'a> rtfm::Mutex for resources::x<'a> {
|
||||
impl<'a> rtic::Mutex for resources::x<'a> {
|
||||
type T = u64;
|
||||
|
||||
fn lock<R>(&mut self, f: impl FnOnce(&mut u64) -> R) -> R {
|
||||
|
|
@ -419,7 +419,7 @@ fn foo(c: foo::Context) {
|
|||
|
||||
## The BASEPRI invariant
|
||||
|
||||
An invariant that the RTFM framework has to preserve is that the value of the
|
||||
An invariant that the RTIC framework has to preserve is that the value of the
|
||||
BASEPRI at the start of an *interrupt* handler must be the same value it has
|
||||
when the interrupt handler returns. BASEPRI may change during the execution of
|
||||
the interrupt handler but running an interrupt handler from start to finish
|
||||
|
|
@ -429,7 +429,7 @@ This invariant needs to be preserved to avoid raising the dynamic priority of a
|
|||
handler through preemption. This is best observed in the following example:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
|
|
@ -439,7 +439,7 @@ const APP: () = {
|
|||
#[init]
|
||||
fn init() {
|
||||
// `foo` will run right after `init` returns
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART0);
|
||||
}
|
||||
|
||||
#[task(binds = UART0, priority = 1)]
|
||||
|
|
@ -447,7 +447,7 @@ const APP: () = {
|
|||
// BASEPRI is `0` at this point; the dynamic priority is currently `1`
|
||||
|
||||
// `bar` will preempt `foo` at this point
|
||||
rtfm::pend(Interrupt::UART1);
|
||||
rtic::pend(Interrupt::UART1);
|
||||
|
||||
// BASEPRI is `192` at this point (due to a bug); the dynamic priority is now `2`
|
||||
// this function returns to `idle`
|
||||
|
|
@ -472,7 +472,7 @@ const APP: () = {
|
|||
|
||||
// this has no effect due to the BASEPRI value
|
||||
// the task `foo` will never be executed again
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
||||
loop {
|
||||
// ..
|
||||
|
|
@ -488,10 +488,10 @@ const APP: () = {
|
|||
```
|
||||
|
||||
IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would
|
||||
be a bug in the RTFM code generator.
|
||||
be a bug in the RTIC code generator.
|
||||
|
||||
``` rust
|
||||
// code generated by RTFM
|
||||
// code generated by RTIC
|
||||
|
||||
const APP: () = {
|
||||
// ..
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
# Interrupt configuration
|
||||
|
||||
Interrupts are core to the operation of RTFM applications. Correctly setting
|
||||
Interrupts are core to the operation of RTIC applications. Correctly setting
|
||||
interrupt priorities and ensuring they remain fixed at runtime is a requisite
|
||||
for the memory safety of the application.
|
||||
|
||||
The RTFM framework exposes interrupt priorities as something that is declared at
|
||||
The RTIC framework exposes interrupt priorities as something that is declared at
|
||||
compile time. However, this static configuration must be programmed into the
|
||||
relevant registers during the initialization of the application. The interrupt
|
||||
configuration is done before the `init` function runs.
|
||||
|
||||
This example gives you an idea of the code that the RTFM framework runs:
|
||||
This example gives you an idea of the code that the RTIC framework runs:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = lm3s6965)]
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init]
|
||||
fn init(c: init::Context) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ The example below shows the kind of code that the framework generates to
|
|||
initialize late resources.
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
struct Resources {
|
||||
x: Thing,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Non-reentrancy
|
||||
|
||||
In RTFM, tasks handlers are *not* reentrant. Reentering a task handler can break
|
||||
In RTIC, tasks handlers are *not* reentrant. Reentering a task handler can break
|
||||
Rust aliasing rules and lead to *undefined behavior*. A task handler can be
|
||||
reentered in one of two ways: in software or by hardware.
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ invoked using FFI (see example below). FFI requires `unsafe` code so end users
|
|||
are discouraged from directly invoking an interrupt handler.
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
#[init]
|
||||
fn init(c: init::Context) { .. }
|
||||
|
|
@ -42,7 +42,7 @@ const APP: () = {
|
|||
};
|
||||
```
|
||||
|
||||
The RTFM framework must generate the interrupt handler code that calls the user
|
||||
The RTIC framework must generate the interrupt handler code that calls the user
|
||||
defined task handlers. We are careful in making these handlers impossible to
|
||||
call from user code.
|
||||
|
||||
|
|
@ -76,5 +76,5 @@ const APP: () = {
|
|||
|
||||
A task handler can also be reentered without software intervention. This can
|
||||
occur if the same handler is assigned to two or more interrupts in the vector
|
||||
table but there's no syntax for this kind of configuration in the RTFM
|
||||
table but there's no syntax for this kind of configuration in the RTIC
|
||||
framework.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Software tasks
|
||||
|
||||
RTFM supports software tasks and hardware tasks. Each hardware task is bound to
|
||||
RTIC supports software tasks and hardware tasks. Each hardware task is bound to
|
||||
a different interrupt handler. On the other hand, several software tasks may be
|
||||
dispatched by the same interrupt handler -- this is done to minimize the number
|
||||
of interrupts handlers used by the framework.
|
||||
|
|
@ -27,7 +27,7 @@ Let's first take a look the code generated by the framework to dispatch tasks.
|
|||
Consider this example:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
// ..
|
||||
|
||||
|
|
@ -183,7 +183,7 @@ const APP: () = {
|
|||
});
|
||||
|
||||
// pend the interrupt that runs the task dispatcher
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART0);
|
||||
}
|
||||
|
||||
None => {
|
||||
|
|
@ -252,7 +252,7 @@ const APP: () = {
|
|||
});
|
||||
|
||||
// pend the interrupt that runs the task dispatcher
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART0);
|
||||
}
|
||||
|
||||
None => {
|
||||
|
|
@ -315,7 +315,7 @@ lock-free.
|
|||
|
||||
## Queue capacity
|
||||
|
||||
The RTFM framework uses several queues like ready queues and free queues. When
|
||||
The RTIC framework uses several queues like ready queues and free queues. When
|
||||
the free queue is empty trying to `spawn` a task results in an error; this
|
||||
condition is checked at runtime. Not all the operations performed by the
|
||||
framework on these queues check if the queue is empty / full. For example,
|
||||
|
|
@ -356,7 +356,7 @@ endpoint is owned by a task dispatcher.
|
|||
Consider the following example:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
#[idle(spawn = [foo, bar])]
|
||||
fn idle(c: idle::Context) -> ! {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ appropriate ready queue.
|
|||
Let's see how this in implemented in code. Consider the following program:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
// ..
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ mod foo {
|
|||
}
|
||||
|
||||
const APP: () = {
|
||||
type Instant = <path::to::user::monotonic::timer as rtfm::Monotonic>::Instant;
|
||||
type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant;
|
||||
|
||||
// all tasks that can be `schedule`-d
|
||||
enum T {
|
||||
|
|
@ -141,7 +141,7 @@ const APP: () = {
|
|||
});
|
||||
|
||||
// pend the task dispatcher
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ timeout interrupt to the `SysTick` handler.
|
|||
|
||||
## Resolution and range of `cyccnt::Instant` and `cyccnt::Duration`
|
||||
|
||||
RTFM provides a `Monotonic` implementation based on the `DWT`'s (Data Watchpoint
|
||||
RTIC provides a `Monotonic` implementation based on the `DWT`'s (Data Watchpoint
|
||||
and Trace) cycle counter. `Instant::now` returns a snapshot of this timer; these
|
||||
DWT snapshots (`Instant`s) are used to sort entries in the timer queue. The
|
||||
cycle counter is a 32-bit counter clocked at the core clock frequency. This
|
||||
|
|
@ -221,7 +221,7 @@ analysis.
|
|||
To illustrate, consider the following example:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(device = ..)]
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
#[task(priority = 3, spawn = [baz])]
|
||||
fn foo(c: foo::Context) {
|
||||
|
|
@ -353,7 +353,7 @@ const APP: () = {
|
|||
});
|
||||
});
|
||||
|
||||
rtfm::pend(Interrupt::UART0);
|
||||
rtic::pend(Interrupt::UART0);
|
||||
}
|
||||
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
# Migrating from v0.4.x to v0.5.0
|
||||
|
||||
This section covers how to upgrade an application written against RTFM 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.
|
||||
|
||||
## `Cargo.toml`
|
||||
|
||||
First, the version of the `cortex-m-rtfm` 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.
|
||||
|
||||
|
||||
``` toml
|
||||
[dependencies.cortex-m-rtfm]
|
||||
[dependencies.cortex-m-rtic]
|
||||
# change this
|
||||
version = "0.4.3"
|
||||
|
||||
|
|
@ -24,15 +24,15 @@ features = ["timer-queue"]
|
|||
|
||||
## `Context` argument
|
||||
|
||||
All functions inside the `#[rtfm::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
|
||||
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
|
||||
fields of the `Context` structure. Each function within the `#[rtic::app]` item
|
||||
gets a different `Context` type.
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(/* .. */)]
|
||||
#[rtic::app(/* .. */)]
|
||||
const APP: () = {
|
||||
// change this
|
||||
#[task(resources = [x], spawn = [a], schedule = [b])]
|
||||
|
|
@ -80,7 +80,7 @@ The syntax used to declare resources has been changed from `static mut`
|
|||
variables to a `struct Resources`.
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(/* .. */)]
|
||||
#[rtic::app(/* .. */)]
|
||||
const APP: () = {
|
||||
// change this
|
||||
static mut X: u32 = 0;
|
||||
|
|
@ -102,13 +102,13 @@ const APP: () = {
|
|||
|
||||
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
|
||||
`#[rtic::app]` attribute to continue to access the device peripherals through
|
||||
the `device` field of the `init::Context` structure.
|
||||
|
||||
Change this:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(/* .. */)]
|
||||
#[rtic::app(/* .. */)]
|
||||
const APP: () = {
|
||||
#[init]
|
||||
fn init() {
|
||||
|
|
@ -122,7 +122,7 @@ const APP: () = {
|
|||
Into this:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(/* .. */, peripherals = true)]
|
||||
#[rtic::app(/* .. */, peripherals = true)]
|
||||
// ^^^^^^^^^^^^^^^^^^
|
||||
const APP: () = {
|
||||
#[init]
|
||||
|
|
@ -144,7 +144,7 @@ hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument.
|
|||
Change this:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(/* .. */)]
|
||||
#[rtic::app(/* .. */)]
|
||||
const APP: () = {
|
||||
// hardware tasks
|
||||
#[exception]
|
||||
|
|
@ -164,7 +164,7 @@ const APP: () = {
|
|||
Into this:
|
||||
|
||||
``` rust
|
||||
#[rtfm::app(/* .. */)]
|
||||
#[rtic::app(/* .. */)]
|
||||
const APP: () = {
|
||||
#[task(binds = SVCall)]
|
||||
// ^^^^^^^^^^^^^^
|
||||
|
|
@ -186,12 +186,12 @@ const APP: () = {
|
|||
|
||||
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`
|
||||
argument of the `#[rtfm::app]` attribute. To continue using the cycle counter
|
||||
argument of the `#[rtic::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.
|
||||
the `monotonic = rtic::cyccnt::CYCCNT` argument to the `#[rtic::app]` attribute.
|
||||
|
||||
Also, the `Duration` and `Instant` types and the `U32Ext` trait have been moved
|
||||
into the `rtfm::cyccnt` module. This module is only available on ARMv7-M+
|
||||
into the `rtic::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, this will need to be enabled by the application
|
||||
inside `init`.
|
||||
|
|
@ -199,9 +199,9 @@ inside `init`.
|
|||
Change this:
|
||||
|
||||
``` rust
|
||||
use rtfm::{Duration, Instant, U32Ext};
|
||||
use rtic::{Duration, Instant, U32Ext};
|
||||
|
||||
#[rtfm::app(/* .. */)]
|
||||
#[rtic::app(/* .. */)]
|
||||
const APP: () = {
|
||||
#[task(schedule = [b])]
|
||||
fn a() {
|
||||
|
|
@ -213,10 +213,10 @@ const APP: () = {
|
|||
Into this:
|
||||
|
||||
``` rust
|
||||
use rtfm::cyccnt::{Duration, Instant, U32Ext};
|
||||
use rtic::cyccnt::{Duration, Instant, U32Ext};
|
||||
// ^^^^^^^^
|
||||
|
||||
#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)]
|
||||
#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
const APP: () = {
|
||||
#[init]
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<h1 align="center">Real Time For the Masses</h1>
|
||||
<h1 align="center">Real-Time Interrupt-driven Concurrency</h1>
|
||||
|
||||
<p align="center">A concurrency framework for building real time systems</p>
|
||||
|
||||
# Preface
|
||||
|
||||
This book contains user level documentation for the Real Time For the Masses
|
||||
(RTFM) framework. The API reference can be found [here](../../api/).
|
||||
This book contains user level documentation for the Real-Time Interrupt-driven Concurrency
|
||||
(RTIC) framework. The API reference can be found [here](../../api/).
|
||||
|
||||
There is a translation of this book in [Russian].
|
||||
|
||||
[Russian]: ../ru/index.html
|
||||
|
||||
This is the documentation of v0.5.x of RTFM; for the documentation of version
|
||||
This is the documentation of v0.5.x of RTIC; for the documentation of version
|
||||
v0.4.x go [here](/0.4).
|
||||
|
||||
{{#include ../../../README.md:5:44}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue