2019-02-08 21:18:51 +01:00
|
|
|
|
# Советы и хитрости
|
|
|
|
|
|
2019-02-09 06:48:12 +01:00
|
|
|
|
## Обобщенное программирование (Generics)
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
2021-04-04 07:15:13 +02:00
|
|
|
|
Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`.
|
|
|
|
|
Если ресурс не реализует его, можно обернуть его в новый тип [`rtic::Exclusive`],
|
|
|
|
|
который реализует трейт `Mutex`. С помощью этого нового типа
|
|
|
|
|
можно написать обобщенную функцию, которая работает с обобщенным ресурсом и
|
|
|
|
|
вызывать его из различных задач, чтобы производить однотипные операции над
|
|
|
|
|
похожим множеством ресурсов.
|
|
|
|
|
Вот один такой пример:
|
|
|
|
|
|
|
|
|
|
[`rtic::Exclusive`]: ../../../api/rtic/struct.Exclusive.html
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
|
|
|
|
``` rust
|
2019-02-11 21:40:53 +01:00
|
|
|
|
{{#include ../../../../examples/generics.rs}}
|
2019-02-08 21:18:51 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
``` console
|
|
|
|
|
$ cargo run --example generics
|
2021-04-04 07:15:13 +02:00
|
|
|
|
{{#include ../../../../ci/expected/generics.run}}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Условная компиляция
|
|
|
|
|
|
|
|
|
|
Вы можете использовать условную компиляцию (`#[cfg]`) на ресурсах (полях структуры
|
|
|
|
|
`#[resources] struct Resources`) и задачах (элементах `fn`).
|
|
|
|
|
Эффект использования атрибутов `#[cfg]` в том, что ресурс/ задача
|
|
|
|
|
будут *не* доступны в соответствующих структурах `Context` если условие не выполняется.
|
|
|
|
|
|
|
|
|
|
В примере ниже выводится сообщение каждый раз, когда вызывается задача `foo`, но только
|
|
|
|
|
если программы скомпилирова с профилем `dev`.
|
|
|
|
|
|
|
|
|
|
``` rust
|
|
|
|
|
{{#include ../../../../examples/cfg.rs}}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
``` console
|
|
|
|
|
$ cargo run --example cfg --release
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
2021-04-04 07:15:13 +02:00
|
|
|
|
$ cargo run --example cfg
|
|
|
|
|
{{#include ../../../../ci/expected/cfg.run}}
|
|
|
|
|
```
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
2019-02-09 06:48:12 +01:00
|
|
|
|
## Запуск задач из ОЗУ
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
2020-06-11 19:18:29 +02:00
|
|
|
|
Главной целью переноса описания программы на RTIC в атрибуты в
|
|
|
|
|
RTIC v0.4.x была возможность взаимодействия с другими атрибутами.
|
2019-02-08 21:18:51 +01:00
|
|
|
|
Напримерe, атрибут `link_section` можно применять к задачам, чтобы разместить
|
2019-02-09 06:48:12 +01:00
|
|
|
|
их в ОЗУ; это может улучшить производительность в некоторых случаях.
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
|
|
|
|
> **ВАЖНО**: Обычно атрибуты `link_section`, `export_name` и `no_mangle`
|
|
|
|
|
> очень мощные, но их легко использовать неправильно. Неверное использование
|
|
|
|
|
> любого из этих атрибутов может вызвать неопределенное поведение;
|
|
|
|
|
> Вам следует всегда предпочитать использование безопасных, высокоуровневых
|
2021-04-04 07:15:13 +02:00
|
|
|
|
> атрибутов вместо них, таких как атрибуты `interrupt` и `exception`
|
2019-02-08 21:18:51 +01:00
|
|
|
|
> из `cortex-m-rt`.
|
|
|
|
|
>
|
2021-04-04 07:15:13 +02:00
|
|
|
|
> В особых функций, размещаемых в ОЗУ нет безопасной абстракции в `cortex-m-rt`
|
2019-02-08 21:18:51 +01:00
|
|
|
|
> v0.6.5 но создано [RFC] для добавления атрибута `ramfunc` в будущем релизе.
|
|
|
|
|
|
|
|
|
|
[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100
|
|
|
|
|
|
2019-02-09 06:48:12 +01:00
|
|
|
|
В примере ниже показано как разместить высокоприоритетную задачу `bar` в ОЗУ.
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
|
|
|
|
``` rust
|
2019-02-11 21:40:53 +01:00
|
|
|
|
{{#include ../../../../examples/ramfunc.rs}}
|
2019-02-08 21:18:51 +01:00
|
|
|
|
```
|
|
|
|
|
|
2021-04-04 07:15:13 +02:00
|
|
|
|
Запуск этой программы создаст ожидаемый вывод.
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
|
|
|
|
``` console
|
|
|
|
|
$ cargo run --example ramfunc
|
2021-04-04 07:15:13 +02:00
|
|
|
|
{{#include ../../../../ci/expected/ramfunc.run}}
|
|
|
|
|
```
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
2019-02-09 06:48:12 +01:00
|
|
|
|
Можно посмотреть на вывод `cargo-nm`, чтобы убедиться, что `bar` расположен в ОЗУ
|
2019-02-08 21:18:51 +01:00
|
|
|
|
(`0x2000_0000`), тогда как `foo` расположен во Flash (`0x0000_0000`).
|
|
|
|
|
|
|
|
|
|
``` console
|
|
|
|
|
$ cargo nm --example ramfunc --release | grep ' foo::'
|
2021-04-04 07:15:13 +02:00
|
|
|
|
{{#include ../../../../ci/expected/ramfunc.grep.foo}}
|
|
|
|
|
```
|
2019-02-08 21:18:51 +01:00
|
|
|
|
|
|
|
|
|
``` console
|
|
|
|
|
$ cargo nm --example ramfunc --release | grep ' bar::'
|
2021-04-04 07:15:13 +02:00
|
|
|
|
{{#include ../../../../ci/expected/ramfunc.grep.bar}}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Обходной путь для быстрой передачи сообщений
|
2019-02-24 05:38:21 +01:00
|
|
|
|
|
2021-04-04 07:15:13 +02:00
|
|
|
|
Передача сообщений всегда вызывает копирование от отправителя в
|
|
|
|
|
статическую переменную, а затем из статической переменной получателю.
|
|
|
|
|
Таким образом, при передаче большого буфера, например `[u8; 128]`, передача сообщения
|
|
|
|
|
вызывает два дорогих вызова `memcpy`. Чтобы минимизировать накладные расходы на передачу
|
|
|
|
|
сообщения, можно использовать обходной путь: вместо передачи буфера по значению,
|
|
|
|
|
можно передавать владеющий указатель на буфер.
|
2019-02-24 05:38:21 +01:00
|
|
|
|
|
2021-04-04 07:15:13 +02:00
|
|
|
|
Можно использовать глобальный аллокатор, чтобы реализовать данный трюк (`alloc::Box`,
|
|
|
|
|
`alloc::Rc`, и т.п.), либо использовать статически аллоцируемый пул памяти, например [`heapless::Pool`].
|
2019-02-24 05:38:21 +01:00
|
|
|
|
|
2021-04-04 07:15:13 +02:00
|
|
|
|
[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html
|
|
|
|
|
|
|
|
|
|
Здесь приведен пример использования `heapless::Pool` для "упаковки" буфера из 128 байт.
|
2019-02-24 05:38:21 +01:00
|
|
|
|
|
|
|
|
|
``` rust
|
2021-04-04 07:15:13 +02:00
|
|
|
|
{{#include ../../../../examples/pool.rs}}
|
2019-02-24 05:38:21 +01:00
|
|
|
|
```
|
2021-04-04 07:15:13 +02:00
|
|
|
|
|
2019-02-24 05:38:21 +01:00
|
|
|
|
``` console
|
2021-04-04 07:15:13 +02:00
|
|
|
|
$ cargo run --example pool
|
|
|
|
|
{{#include ../../../../ci/expected/pool.run}}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Инспектирование раскрываемого кода
|
|
|
|
|
|
|
|
|
|
`#[rtic::app]` - это процедурный макрос, который создает код.
|
|
|
|
|
Если по какой-то причине вам нужно увидеть код, сгенерированный этим макросом,
|
|
|
|
|
у вас есть два пути:
|
|
|
|
|
|
|
|
|
|
Вы можете изучить файл `rtic-expansion.rs` внутри папки `target`. Этот файл
|
|
|
|
|
содержит элемент `#[rtic::app]` в раскрытом виде (не всю вашу программу!)
|
|
|
|
|
из *последней сборки* (с помощью `cargo build` или `cargo check`) RTIC программы.
|
|
|
|
|
Раскрытый код не отформатирован по-умолчанию, но вы можете запустить `rustfmt`
|
|
|
|
|
на нем перед тем, как читать.
|
|
|
|
|
|
|
|
|
|
``` console
|
|
|
|
|
$ cargo build --example foo
|
|
|
|
|
|
|
|
|
|
$ rustfmt target/rtic-expansion.rs
|
|
|
|
|
|
|
|
|
|
$ tail target/rtic-expansion.rs
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
``` rust
|
|
|
|
|
#[doc = r" Implementation details"]
|
|
|
|
|
mod app {
|
|
|
|
|
#[doc = r" Always include the device crate which contains the vector table"]
|
|
|
|
|
use lm3s6965 as _;
|
|
|
|
|
#[no_mangle]
|
|
|
|
|
unsafe extern "C" fn main() -> ! {
|
|
|
|
|
rtic::export::interrupt::disable();
|
|
|
|
|
let mut core: rtic::export::Peripherals = core::mem::transmute(());
|
|
|
|
|
core.SCB.scr.modify(|r| r | 1 << 1);
|
|
|
|
|
rtic::export::interrupt::enable();
|
|
|
|
|
loop {
|
|
|
|
|
rtic::export::wfi()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Или, вы можете использовать подкоманду [`cargo-expand`]. Она раскроет
|
|
|
|
|
*все* макросы, включая атрибут `#[rtic::app]`, и модули в вашем крейте и
|
|
|
|
|
напечатает вывод в консоль.
|
|
|
|
|
|
|
|
|
|
[`cargo-expand`]: https://crates.io/crates/cargo-expand
|
|
|
|
|
|
|
|
|
|
``` console
|
|
|
|
|
$ # создаст такой же вывод, как выше
|
|
|
|
|
$ cargo expand --example smallest | tail
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Деструктуризация ресурса
|
|
|
|
|
|
|
|
|
|
Если задача требует нескольких ресурсов, разбиение структуры ресурсов
|
|
|
|
|
может улучшить читабельность. Вот два примера того, как это можно сделать:
|
|
|
|
|
|
|
|
|
|
``` rust
|
|
|
|
|
{{#include ../../../../examples/destructure.rs}}
|
|
|
|
|
```
|