rtic/book/en/src/by-example/app.md

158 lines
6.6 KiB
Markdown
Raw Normal View History

2018-11-03 17:02:41 +01:00
# The `app` attribute
2020-06-11 19:18:29 +02:00
This is the smallest possible RTIC application:
2018-11-03 17:02:41 +01:00
``` rust
2019-02-11 21:40:53 +01:00
{{#include ../../../../examples/smallest.rs}}
2018-11-03 17:02:41 +01:00
```
2020-06-11 19:18:29 +02:00
All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute
2020-10-13 01:45:03 +02:00
must be applied to a `mod`-item. The `app` attribute has a mandatory `device`
argument that takes a *path* as a value. This must be a full path pointing to a
*peripheral access crate* (PAC) generated using [`svd2rust`] **v0.14.x** or
newer. More details can be found in the [Starting a new project](./new.md)
section.
The `app` attribute will expand into a suitable entry point so it's not required
to use the [`cortex_m_rt::entry`] attribute.
2018-11-03 17:02:41 +01:00
2020-06-11 19:18:29 +02:00
[`app`]: ../../../api/cortex_m_rtic_macros/attr.app.html
2018-11-03 17:02:41 +01:00
[`svd2rust`]: https://crates.io/crates/svd2rust
2019-09-17 19:55:55 +02:00
[`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html
2018-11-03 17:02:41 +01:00
## `init`
2020-10-01 18:59:27 +02:00
Within the `app` module the attribute expects to find an initialization
2018-11-03 17:02:41 +01:00
function marked with the `init` attribute. This function must have signature
2019-08-21 10:17:27 +02:00
`fn(init::Context) [-> init::LateResources]` (the return type is not always
required).
2018-11-03 17:02:41 +01:00
This initialization function will be the first part of the application to run.
The `init` function will run *with interrupts disabled* and has exclusive access
to Cortex-M where the `bare_metal::CriticalSection` token is available as `cs`.
And optionally, device specific peripherals through the `core` and `device` fields
of `init::Context`.
2018-11-03 17:02:41 +01:00
`static mut` variables declared at the beginning of `init` will be transformed
2020-11-12 18:20:16 +01:00
into `&'static mut` references that are safe to access. Notice, this feature may be deprecated in next release, see `task_local` resources.
2018-11-03 17:02:41 +01:00
2020-06-11 19:18:29 +02:00
[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
2018-11-03 17:02:41 +01:00
The example below shows the types of the `core`, `device` and `cs` fields, and
2019-08-21 10:17:27 +02:00
showcases safe access to a `static mut` variable. The `device` field is only
2020-11-12 18:20:16 +01:00
available when the `peripherals` argument is set to `true` (default). In the rare case you want to implement an ultra-slim application you can explicitly set `peripherals` to `false`.
2018-11-03 17:02:41 +01:00
``` rust
2019-02-11 21:40:53 +01:00
{{#include ../../../../examples/init.rs}}
2018-11-03 17:02:41 +01:00
```
Running the example will print `init` to the console and then exit the QEMU
process.
``` console
$ cargo run --example init
{{#include ../../../../ci/expected/init.run}}
```
2018-11-03 17:02:41 +01:00
## `idle`
A function marked with the `idle` attribute can optionally appear in the
2020-10-01 18:59:27 +02:00
module. This function is used as the special *idle task* and must have
2019-04-21 20:25:59 +02:00
signature `fn(idle::Context) - > !`.
2018-11-03 17:02:41 +01:00
When present, the runtime will execute the `idle` task after `init`. Unlike
`init`, `idle` will run *with interrupts enabled* and it's not allowed to return
2019-08-21 10:17:27 +02:00
so it must run forever.
2018-11-03 17:02:41 +01:00
When no `idle` function is declared, the runtime sets the [SLEEPONEXIT] bit and
then sends the microcontroller to sleep after running `init`.
2020-04-13 17:32:49 +02:00
[SLEEPONEXIT]: https://developer.arm.com/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit
2018-11-03 17:02:41 +01:00
Like in `init`, `static mut` variables will be transformed into `&'static mut`
2020-11-12 18:20:16 +01:00
references that are safe to access. Notice, this feature may be deprecated in the next release, see `task_local` resources.
2018-11-03 17:02:41 +01:00
The example below shows that `idle` runs after `init`.
2020-11-12 18:20:16 +01:00
**Note:** The `loop {}` in idle cannot be empty as this will crash the microcontroller due to
LLVM compiling empty loops to an `UDF` instruction in release mode. To avoid UB, the loop needs to imply a "side-effect" by inserting an assembly instruction (e.g., `WFI`) or a `continue`.
2018-11-03 17:02:41 +01:00
``` rust
2019-02-11 21:40:53 +01:00
{{#include ../../../../examples/idle.rs}}
2018-11-03 17:02:41 +01:00
```
``` console
$ cargo run --example idle
{{#include ../../../../ci/expected/idle.run}}
```
2018-11-03 17:02:41 +01:00
2019-08-21 10:17:27 +02:00
## Hardware tasks
2018-11-03 17:02:41 +01:00
2019-08-21 10:17:27 +02:00
To declare interrupt handlers the framework provides a `#[task]` attribute that
can be attached to functions. This attribute takes a `binds` argument whose
value is the name of the interrupt to which the handler will be bound to; the
2020-07-14 16:01:14 +02:00
function adorned with this attribute becomes the interrupt handler. Within the
2019-08-21 10:17:27 +02:00
framework these type of tasks are referred to as *hardware* tasks, because they
start executing in reaction to a hardware event.
The example below demonstrates the use of the `#[task]` attribute to declare an
interrupt handler. Like in the case of `#[init]` and `#[idle]` local `static
mut` variables are safe to use within a hardware task.
2018-11-03 17:02:41 +01:00
``` rust
2019-08-21 10:17:27 +02:00
{{#include ../../../../examples/hardware.rs}}
2018-11-03 17:02:41 +01:00
```
``` console
2020-01-24 16:34:41 +01:00
$ cargo run --example hardware
{{#include ../../../../ci/expected/hardware.run}}
```
2018-11-03 17:02:41 +01:00
2020-06-11 19:18:29 +02:00
So far all the RTIC applications we have seen look no different than the
2019-08-21 10:17:27 +02:00
applications one can write using only the `cortex-m-rt` crate. From this point
2020-06-11 19:18:29 +02:00
we start introducing features unique to RTIC.
2019-08-21 10:17:27 +02:00
## Priorities
The static priority of each handler can be declared in the `task` attribute
using the `priority` argument. Tasks can have priorities in the range `1..=(1 <<
NVIC_PRIO_BITS)` where `NVIC_PRIO_BITS` is a constant defined in the `device`
2020-05-13 13:35:51 +02:00
crate. When the `priority` argument is omitted, the priority is assumed to be
`1`. The `idle` task has a non-configurable static priority of `0`, the lowest priority.
2019-08-21 10:17:27 +02:00
> A higher number means a higher priority in RTIC, which is the opposite from what
> Cortex-M does in the NVIC peripheral.
> Explicitly, this means that number `10` has a **higher** priority than number `9`.
When several tasks are ready to be executed the one with highest static
2019-08-21 10:17:27 +02:00
priority will be executed first. Task prioritization can be observed in the
following scenario: an interrupt signal arrives during the execution of a low
priority task; the signal puts the higher priority task in the pending state.
The difference in priority results in the higher priority task preempting the
lower priority one: the execution of the lower priority task is suspended and
the higher priority task is executed to completion. Once the higher priority
task has terminated the lower priority task is resumed.
The following example showcases the priority based scheduling of tasks.
``` rust
{{#include ../../../../examples/preempt.rs}}
```
``` console
2020-01-24 16:34:41 +01:00
$ cargo run --example preempt
{{#include ../../../../ci/expected/preempt.run}}
```
2019-08-21 10:17:27 +02:00
2019-08-21 10:53:13 +02:00
Note that the task `gpiob` does *not* preempt task `gpioc` because its priority
2020-11-12 18:20:16 +01:00
is the *same* as `gpioc`'s. However, once `gpioc` returns, the execution of
task `gpiob` is prioritized over `gpioa` due to its higher priority. `gpioa`
is resumed only after `gpiob` returns.
2019-08-21 10:17:27 +02:00
One more note about priorities: choosing a priority higher than what the device
supports (that is `1 << NVIC_PRIO_BITS`) will result in a compile error. Due to
2020-05-13 13:35:51 +02:00
limitations in the language, the error message is currently far from helpful: it
2019-08-21 10:17:27 +02:00
will say something along the lines of "evaluation of constant value failed" and
the span of the error will *not* point out to the problematic interrupt value --
we are sorry about this!