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
|
2018-11-03 17:02:41 +01:00
|
|
|
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
|
2018-12-16 21:19:19 +01:00
|
|
|
point to a *peripheral access crate* (PAC) generated using [`svd2rust`]
|
2019-08-21 12:33:04 +02:00
|
|
|
**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.
|
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
|
|
|
|
|
|
|
> **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
|
2020-06-11 19:18:29 +02:00
|
|
|
> RTIC work on stable we use the `const` item instead. When more parts of macros
|
2018-11-03 17:02:41 +01:00
|
|
|
> 1.2 are stabilized we'll move from a `const` item to a `mod` item and
|
|
|
|
> eventually to a crate level attribute (`#![app]`).
|
|
|
|
|
|
|
|
## `init`
|
|
|
|
|
|
|
|
Within the pseudo-module the `app` attribute expects to find an initialization
|
|
|
|
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
|
2019-08-21 10:17:27 +02:00
|
|
|
to Cortex-M 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
|
|
|
|
into `&'static mut` references that are safe to access.
|
|
|
|
|
2020-06-11 19:18:29 +02:00
|
|
|
[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
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
|
|
|
|
available when the `peripherals` argument is set to `true` (it defaults 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
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#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
|
|
|
|
pseudo-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`
|
|
|
|
references that are safe to access.
|
|
|
|
|
|
|
|
The example below shows that `idle` runs after `init`.
|
|
|
|
|
|
|
|
``` 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
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#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
|
|
|
|
function adornated with this attribute becomes the interrupt handler. Within the
|
|
|
|
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
|
2019-08-21 10:17:27 +02:00
|
|
|
{{#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
|
2019-08-21 10:17:27 +02:00
|
|
|
`1`. The `idle` task has a non-configurable static priority of `0`, the lowest
|
|
|
|
priority.
|
|
|
|
|
|
|
|
When several tasks are ready to be executed the one with *highest* static
|
|
|
|
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
|
2019-08-21 10:17:27 +02:00
|
|
|
{{#include ../../../../ci/expected/preempt.run}}```
|
|
|
|
|
2019-08-21 10:53:13 +02:00
|
|
|
Note that the task `gpiob` does *not* preempt task `gpioc` because its priority
|
|
|
|
is the *same* as `gpioc`'s. However, once `gpioc` terminates the execution of
|
2020-05-13 13:35:51 +02:00
|
|
|
task, `gpiob` is prioritized over `gpioa` due to its higher priority. `gpioa`
|
2019-08-21 10:53:13 +02:00
|
|
|
is resumed only after `gpiob` terminates.
|
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!
|