mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-01 16:04:33 +01:00
Merge #508
508: update russian book r=AfoHT a=burrbull Co-authored-by: Andrey Zgarbul <zgarbul.andrey@gmail.com>
This commit is contained in:
commit
74b3964978
7 changed files with 288 additions and 125 deletions
|
@ -50,10 +50,16 @@
|
||||||
|
|
||||||
- Приложения должны быть написаны в редакции 2018.
|
- Приложения должны быть написаны в редакции 2018.
|
||||||
|
|
||||||
|
## [Руководство пользователя](https://rtic.rs) - [(Версия в разработке)](https://rtic.rs/dev)
|
||||||
|
|
||||||
## [Документация пользователя](https://rtic.rs)
|
## [Документация пользователя](https://rtic.rs)
|
||||||
|
|
||||||
## [Справочник по API](https://rtic.rs/stable/api/)
|
## [Справочник по API](https://rtic.rs/stable/api/)
|
||||||
|
|
||||||
|
## [Сборник примеров, предоставляемы сообществом][examples]
|
||||||
|
|
||||||
|
[examples]: https://github.com/rtic-rs/rtic-examples
|
||||||
|
|
||||||
## Чат
|
## Чат
|
||||||
|
|
||||||
Присоединяйтесь к нам, чтобы говорить о RTIC [в Matrix-комнате][matrix-room].
|
Присоединяйтесь к нам, чтобы говорить о RTIC [в Matrix-комнате][matrix-room].
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
Внутри модуля `app` атрибут ожидает найти функцию инициализации, помеченную
|
Внутри модуля `app` атрибут ожидает найти функцию инициализации, помеченную
|
||||||
атрибутом `init`. Эта функция должна иметь сигнатуру
|
атрибутом `init`. Эта функция должна иметь сигнатуру
|
||||||
`fn(init::Context) [-> init::LateResources]` (возвращаемый тип нужен не всегда).
|
`fn(init::Context) (-> init::LateResources, init::Monotonics)`.
|
||||||
|
|
||||||
Эта функция инициализации будет первой частью программы, выполняемой при запуске.
|
Эта функция инициализации будет первой частью программы, выполняемой при запуске.
|
||||||
Функция `init` будет запущена *с отключенными прерываниями* и будет иметь эксклюзивный доступ
|
Функция `init` будет запущена *с отключенными прерываниями* и будет иметь эксклюзивный доступ
|
||||||
|
@ -54,6 +54,12 @@ $ cargo run --example init
|
||||||
{{#include ../../../../ci/expected/init.run}}
|
{{#include ../../../../ci/expected/init.run}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **ПРИМЕЧАНИЕ**: Не забывайте указывать выбранное вами целевое устройство, передавая параметр target
|
||||||
|
> в cargo (например `cargo run --example init --target thumbv7m-none-eabi`) или
|
||||||
|
> настроив устройство, используемое по умолчанию для сборки примеров в `.cargo/config.toml`.
|
||||||
|
> В нашем случае используется Cortex M3, эмулируемый с помощью QEMU, поэтому пишем `thumbv7m-none-eabi`.
|
||||||
|
> Смотрите [`Создание нового проекта`](./new.md) для большей информации.
|
||||||
|
|
||||||
## `idle`
|
## `idle`
|
||||||
|
|
||||||
Функцию, помеченную атрибутом `idle` может опционально добавить в модуль.
|
Функцию, помеченную атрибутом `idle` может опционально добавить в модуль.
|
||||||
|
|
|
@ -7,21 +7,26 @@
|
||||||
Фреймворк дает пользователю полный контроль за тем, какой контекст может
|
Фреймворк дает пользователю полный контроль за тем, какой контекст может
|
||||||
получить доступ к какому ресурсу.
|
получить доступ к какому ресурсу.
|
||||||
|
|
||||||
Все ресурсы определены в одной структуре внутри модуля `#[app]`.
|
Все ресурсы определены в *двух* структурах внутри модуля `#[app]`.
|
||||||
Каждое поле структуры соответствует отдельному ресурсу.
|
Каждое поле этих структур соответствует отдельному ресурсу.
|
||||||
`struct`-ура должна быть аннотирована следующим атрибутом: `#[resources]`.
|
Одна `struct`-ура должна быть аннотирована атрибутом `#[local]`.
|
||||||
|
Другая `struct`-ура должна быть аннотирована атрибутом `#[shared]`.
|
||||||
Ресурсам могут быть опционально даны начальные значения с помощью атрибута `#[init]`.
|
Разница между этими двумя множествами ресурсов будет описана познее.
|
||||||
Ресурсы, которым не передано начально значение, называются
|
|
||||||
*поздними* ресурсами, более детально они описаны в одном из разделов на этой странице.
|
|
||||||
|
|
||||||
Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым
|
Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым
|
||||||
он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя
|
он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя
|
||||||
аргумент `resources`. Этот аргумент принимает список имен ресурсов в качестве значения.
|
либо аргумент `local`, либо `shared`. Этот аргумент принимает список имен ресурсов в качестве значения.
|
||||||
Перечисленные ресурсы становятся доступны в контексте через поле `resources` структуры `Context`.
|
Перечисленные ресурсы становятся доступны в контексте через поля `local` и `shared` структуры `Context`.
|
||||||
|
|
||||||
Пример программы, показанной ниже содержит два обработчика прерывания, которые разделяют
|
Во время выполнения при выходе из функции `#[init]` все ресурсы инициализированы.
|
||||||
доступ к ресурсу под названием `shared`.
|
Функция `#[init]` должна возвращать начальные значения для всех ресурсов;
|
||||||
|
отсюда следует, что тип возвращаемого ею значения включает типы
|
||||||
|
структур `#[shared]` и `#[local]`.
|
||||||
|
Поскольку ресурсы инициализированы в ходе функции `#[init]`, к ним нельзя
|
||||||
|
получить доступ внетри функции `#[init]`.
|
||||||
|
|
||||||
|
Пример программы, показанной ниже содержит два обработчика прерывания.
|
||||||
|
Каждый обработчик имеет доступ к его собственному `#[local]` ресурсу.
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
{{#include ../../../../examples/resource.rs}}
|
{{#include ../../../../examples/resource.rs}}
|
||||||
|
@ -32,15 +37,17 @@ $ cargo run --example resource
|
||||||
{{#include ../../../../ci/expected/resource.run}}
|
{{#include ../../../../ci/expected/resource.run}}
|
||||||
```
|
```
|
||||||
|
|
||||||
Заметьте, что к ресурсу `shared` нельзя получить доступ из `idle`. Попытка сделать это
|
К ресурсу `#[local]` нельзя получить доступ извне задачи к которой он
|
||||||
приведет к ошибке компиляции.
|
привязан атрибутом `#[task]`.
|
||||||
|
Попытка обращения к одному и тому же ресурсу `#[local]` из более чем одной
|
||||||
|
задачи - ошибка компиляции.
|
||||||
|
|
||||||
## `lock`
|
## `lock`
|
||||||
|
|
||||||
Критические секции необходимы для разделения изменяемых данных таким образом,
|
Критические секции необходимы для доступа к ресурсам `#[shared]` таким образом,
|
||||||
чтобы избежать гонок данных.
|
чтобы избежать гонок данных.
|
||||||
|
|
||||||
Поле `resources`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
|
Поле `shared`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
|
||||||
ресурса, доступного задаче.
|
ресурса, доступного задаче.
|
||||||
|
|
||||||
Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции.
|
Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции.
|
||||||
|
@ -81,33 +88,7 @@ $ cargo run --example lock
|
||||||
{{#include ../../../../examples/multilock.rs}}
|
{{#include ../../../../examples/multilock.rs}}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Поздние ресурсы
|
## Только разделяемый (`&-`) доступ
|
||||||
|
|
||||||
Поздние ресурсы - такие ресурсы, которым не передано начальное значение во время компиляции
|
|
||||||
с помощью атрибута `#[init]`, но которые вместо этого инициализируются во время выполнения
|
|
||||||
с помощью значений из структуры `init::LateResources`, возвращаемой функцией `init`.
|
|
||||||
|
|
||||||
Поздние ресурсы полезны, например, для *move* (передача владения) периферии,
|
|
||||||
инициализированной в `init`, в задачи.
|
|
||||||
|
|
||||||
Пример ниже использует поздние ресурсы, чтобы установить неблокируемый односторонний канал
|
|
||||||
между обработчиком прерывания `UART0` и задачей `idle`. Для канала использована очередь типа
|
|
||||||
один производитель-один потребитель [`Queue`]. Структура очереди разделяется на потребителя
|
|
||||||
и производителя в `init`, а затем каждая из частей располагается в отдельном ресурсу;
|
|
||||||
`UART0` владеет ресурсом производителя, а `idle` владеет ресурсом потребителя.
|
|
||||||
|
|
||||||
[`Queue`]: ../../../api/heapless/spsc/struct.Queue.html
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
{{#include ../../../../examples/late.rs}}
|
|
||||||
```
|
|
||||||
|
|
||||||
``` console
|
|
||||||
$ cargo run --example late
|
|
||||||
{{#include ../../../../ci/expected/late.run}}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Только разделяемый доступ
|
|
||||||
|
|
||||||
По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам,
|
По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам,
|
||||||
но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса
|
но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса
|
||||||
|
@ -139,11 +120,21 @@ $ cargo run --example only-shared-access
|
||||||
|
|
||||||
## Неблокируемый доступ к изменяемым ресурсам
|
## Неблокируемый доступ к изменяемым ресурсам
|
||||||
|
|
||||||
Есть две других возможности доступа к ресурсам
|
Критическая секция *не* требуется для доступа к ресурсу `#[shared]`,
|
||||||
|
к которому обращаются только из задач с *одинаковым* приоритетом.
|
||||||
|
В этом случае вы можете избежать `lock` API, добавив атрибут поля `#[lock_free]` при объявдении ресурса (смотреть пример ниже).
|
||||||
|
Заметьте, что это лишь для удобства: даже если вы используете `lock` API,
|
||||||
|
во время выполнения фреймворк *не* создаст критическую секцию.
|
||||||
|
Еще одно ценное замечание: использование `#[lock_free]` на ресурсах,
|
||||||
|
разделяемых задачами, запускаемыми с разными приоритетами
|
||||||
|
приведет к ошибке *компиляции* -- не импользование `lock` API может
|
||||||
|
привести к гонке данных в этом случае.
|
||||||
|
|
||||||
* `#[lock_free]`: могут быть несколько задач с одинаковым приоритетом,
|
``` rust
|
||||||
получающие доступ к ресурсу без критических секций. Так как задачи с
|
{{#include ../../../../examples/lock-free.rs}}
|
||||||
одинаковым приоритетом никогда не могут вытеснить друг друга, это безопасно.
|
```
|
||||||
* `#[task_local]`: в этом случае должна быть только одна задача, использующая
|
|
||||||
этот ресурс, так же как локальный `static mut` ресурс задачи, но (опционально) устанавливаемая с в init.
|
|
||||||
|
|
||||||
|
``` console
|
||||||
|
$ cargo run --example lock-free
|
||||||
|
{{#include ../../../../ci/expected/lock-free.run}}
|
||||||
|
```
|
|
@ -1,5 +1,9 @@
|
||||||
# Советы и хитрости
|
# Советы и хитрости
|
||||||
|
|
||||||
|
Полные примеры для RTIC смотрите в репозитарии [rtic-examples][rtic-examples].
|
||||||
|
|
||||||
|
[rtic-examples]: https://github.com/rtic-rs/rtic-examples
|
||||||
|
|
||||||
## Обобщенное программирование (Generics)
|
## Обобщенное программирование (Generics)
|
||||||
|
|
||||||
Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`.
|
Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`.
|
||||||
|
|
|
@ -103,8 +103,7 @@ mod app {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Важная деталь здесь то, что `interrupt::enable` ведет себя как like a *compiler
|
Важная деталь здесь то, что `interrupt::enable` ведет себя как *барьер компиляции*, который не дает компилятору переставить запись в `X` *после*
|
||||||
fence*, которое не дает компилятору пореставить запись в `X` *после*
|
|
||||||
`interrupt::enable`. Если бы компилятор мог делать такие перестановки появились
|
`interrupt::enable`. Если бы компилятор мог делать такие перестановки появились
|
||||||
бы гонки данных между этой записью и любой операцией `foo`, взаимодействующей с `X`.
|
бы гонки данных между этой записью и любой операцией `foo`, взаимодействующей с `X`.
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ mod app {
|
||||||
}
|
}
|
||||||
|
|
||||||
// очередь готовности диспетчера задач
|
// очередь готовности диспетчера задач
|
||||||
// `U4` - целое число, представляющее собой емкость этой очереди
|
// `5-1=4` - представляет собой емкость этой очереди
|
||||||
static mut RQ1: Queue<Ready<T1>, U4> = Queue::new();
|
static mut RQ1: Queue<Ready<T1>, 5> = Queue::new();
|
||||||
|
|
||||||
// обработчик прерывания, выбранный для диспетчеризации задач с приоритетом `1`
|
// обработчик прерывания, выбранный для диспетчеризации задач с приоритетом `1`
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -151,9 +151,9 @@ mod app {
|
||||||
const RQ1_CEILING: u8 = 2;
|
const RQ1_CEILING: u8 = 2;
|
||||||
|
|
||||||
// используется, чтобы отследить сколько еще сообщений для `bar` можно поставить в очередь
|
// используется, чтобы отследить сколько еще сообщений для `bar` можно поставить в очередь
|
||||||
// `U2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь
|
// `3-1=2` - емкость задачи `bar`; максимум 2 экземпляра можно добавить в очередь
|
||||||
// эта очередь заполняется фреймворком до того, как запустится `init`
|
// эта очередь заполняется фреймворком до того, как запустится `init`
|
||||||
static mut bar_FQ: Queue<(), U2> = Queue::new();
|
static mut bar_FQ: Queue<(), 3> = Queue::new();
|
||||||
|
|
||||||
// Поиск максимального приоритета для конечного потребителя `bar_FQ`
|
// Поиск максимального приоритета для конечного потребителя `bar_FQ`
|
||||||
const bar_FQ_CEILING: u8 = 2;
|
const bar_FQ_CEILING: u8 = 2;
|
||||||
|
@ -227,7 +227,7 @@ mod app {
|
||||||
|
|
||||||
// список свободной памяти: используется для отслеживания свободных ячеек в массиве `baz_INPUTS`
|
// список свободной памяти: используется для отслеживания свободных ячеек в массиве `baz_INPUTS`
|
||||||
// эта очередь инициализируется значениями `0` и `1` перед запуском `init`
|
// эта очередь инициализируется значениями `0` и `1` перед запуском `init`
|
||||||
static mut baz_FQ: Queue<u8, U2> = Queue::new();
|
static mut baz_FQ: Queue<u8, 3> = Queue::new();
|
||||||
|
|
||||||
// Поиск максимального приоритета для конечного потребителя `baz_FQ`
|
// Поиск максимального приоритета для конечного потребителя `baz_FQ`
|
||||||
const baz_FQ_CEILING: u8 = 2;
|
const baz_FQ_CEILING: u8 = 2;
|
||||||
|
|
|
@ -30,7 +30,46 @@ mod app {
|
||||||
|
|
||||||
Так как теперь используется обычный модуль Rust, это значит, что можно использовать
|
Так как теперь используется обычный модуль Rust, это значит, что можно использовать
|
||||||
обычный пользовательский код в этом модуле.
|
обычный пользовательский код в этом модуле.
|
||||||
Также жто значит, что `use`-выражения для ресурсов (и т.п.) могут понадобиться.
|
Также это значит, что `use`-выражения для ресурсов, используемые
|
||||||
|
в пользовательском коде должны быть перемещены внутрь `mod app`,
|
||||||
|
либо на них можно сослаться с помощью `super`. Например, измените:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use some_crate::some_func;
|
||||||
|
|
||||||
|
#[rtic::app(/* .. */)]
|
||||||
|
const APP: () = {
|
||||||
|
fn func() {
|
||||||
|
some_crate::some_func();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
на
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[rtic::app(/* .. */)]
|
||||||
|
mod app {
|
||||||
|
use some_crate::some_func;
|
||||||
|
|
||||||
|
fn func() {
|
||||||
|
some_crate::some_func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
или
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use some_crate::some_func;
|
||||||
|
|
||||||
|
#[rtic::app(/* .. */)]
|
||||||
|
mod app {
|
||||||
|
fn func() {
|
||||||
|
super::some_crate::some_func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Перенос диспетчеров из `extern "C"` в аргументы app.
|
## Перенос диспетчеров из `extern "C"` в аргументы app.
|
||||||
|
|
||||||
|
@ -63,6 +102,182 @@ mod app {
|
||||||
Это работает и для ОЗУ-функций, см. examples/ramfunc.rs
|
Это работает и для ОЗУ-функций, см. examples/ramfunc.rs
|
||||||
|
|
||||||
|
|
||||||
|
## Структуры ресурсов - `#[shared]`, `#[local]`
|
||||||
|
|
||||||
|
Ранее ресурсы RTIC должны были размещаться в структуре с именем "Resources":
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
struct Resources {
|
||||||
|
// Ресурсы определяются здесь
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Начиная с RTIC v0.6.0 структуры ресурсов аннотируются подобно
|
||||||
|
`#[task]`, `#[init]`, `#[idle]`: аттрибутами `#[shared]` и `#[local]`
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[shared]
|
||||||
|
struct MySharedResources {
|
||||||
|
// Разделяемые задачами ресурсы определены здесь
|
||||||
|
}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct MyLocalResources {
|
||||||
|
// Ресурсы, определенные здесь нельзя передавать между задачами; каждый из них локальный для единственной задачи
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Эти структуры разработчик может называть по своему желанию.
|
||||||
|
|
||||||
|
## `shared` и `local` аргументы в `#[task]`'ах
|
||||||
|
|
||||||
|
В v0.6.0 ресурсы разделены на `shared` ресурсы и `local` ресурсы.
|
||||||
|
`#[task]`, `#[init]` и `#[idle]` больше не имеют аргумента `resources`;
|
||||||
|
они должны использовать аргументы `shared` и `local`.
|
||||||
|
|
||||||
|
В v0.5.x:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
struct Resources {
|
||||||
|
local_to_b: i64,
|
||||||
|
shared_by_a_and_b: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(resources = [shared_by_a_and_b])]
|
||||||
|
fn a(_: a::Context) {}
|
||||||
|
|
||||||
|
#[task(resources = [shared_by_a_and_b, local_to_b])]
|
||||||
|
fn b(_: b::Context) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
В v0.6.0:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[shared]
|
||||||
|
struct Shared {
|
||||||
|
shared_by_a_and_b: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {
|
||||||
|
local_to_b: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(shared = [shared_by_a_and_b])]
|
||||||
|
fn a(_: a::Context) {}
|
||||||
|
|
||||||
|
#[task(shared = [shared_by_a_and_b], local = [local_to_b])]
|
||||||
|
fn b(_: b::Context) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Симметричные блокировки
|
||||||
|
|
||||||
|
Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
|
||||||
|
всех доступов к `shared` ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
|
||||||
|
в старом коде можно было следующее:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[task(priority = 2, resources = [r])]
|
||||||
|
fn foo(cx: foo::Context) {
|
||||||
|
cx.resources.r = /* ... */;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(resources = [r])]
|
||||||
|
fn bar(cx: bar::Context) {
|
||||||
|
cx.resources.r.lock(|r| r = /* ... */);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
С симметричными блокировками нужно вызывать `lock` для обоих задач:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[task(priority = 2, shared = [r])]
|
||||||
|
fn foo(cx: foo::Context) {
|
||||||
|
cx.shared.r.lock(|r| r = /* ... */);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(shared = [r])]
|
||||||
|
fn bar(cx: bar::Context) {
|
||||||
|
cx.shared.r.lock(|r| r = /* ... */);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Заметьте, что скорость работы не изменяется благодаря оптимизациям LLVM, которые убирают ненужные блокировки.
|
||||||
|
|
||||||
|
## Неблокирующий доступ к ресурсам
|
||||||
|
|
||||||
|
В RTIC 0.5 к ресурсам разделяемым задачами, запускаемыми с одинаковым
|
||||||
|
приоритетом, можно получить доступ *без* `lock` API.
|
||||||
|
Это все еще возможно в 0.6: ресурс `#[shared]` должен быть аннотирован
|
||||||
|
аттрибутом поля `#[lock_free]`.
|
||||||
|
|
||||||
|
v0.5 код:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
struct Resources {
|
||||||
|
counter: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(resources = [counter])]
|
||||||
|
fn a(cx: a::Context) {
|
||||||
|
*cx.resources.counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(resources = [counter])]
|
||||||
|
fn b(cx: b::Context) {
|
||||||
|
*cx.resources.counter += 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
v0.6 код:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[shared]
|
||||||
|
struct Shared {
|
||||||
|
#[lock_free]
|
||||||
|
counter: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(shared = [counter])]
|
||||||
|
fn a(cx: a::Context) {
|
||||||
|
*cx.shared.counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(shared = [counter])]
|
||||||
|
fn b(cx: b::Context) {
|
||||||
|
*cx.shared.counter += 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## нет преобразования `static mut`
|
||||||
|
|
||||||
|
`static mut` переменные больше не преобразуются в безопасные `&'static mut` ссылки.
|
||||||
|
Вместо этого синтаксиса используйте аргумент `local` в `#[init]`.
|
||||||
|
|
||||||
|
v0.5.x code:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) {
|
||||||
|
static mut BUFFER: [u8; 1024] = [0; 1024];
|
||||||
|
let buffer: &'static mut [u8; 1024] = BUFFER;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
v0.6.0 code:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#[init(local = [
|
||||||
|
buffer: [u8; 1024] = [0; 1024]
|
||||||
|
// type ^^^^^^^^^^^^ ^^^^^^^^^ initial value
|
||||||
|
])]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
|
let buffer: &'static mut [u8; 1024] = cx.local.buffer;
|
||||||
|
|
||||||
|
(Shared {}, Local {}, init::Monotonics())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Init всегда возвращает поздние ресурсы
|
## Init всегда возвращает поздние ресурсы
|
||||||
|
|
||||||
С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.
|
С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.
|
||||||
|
@ -83,51 +298,27 @@ mod app {
|
||||||
|
|
||||||
на это:
|
на это:
|
||||||
|
|
||||||
|
|
||||||
``` rust
|
``` rust
|
||||||
#[rtic::app(device = lm3s6965)]
|
#[rtic::app(device = lm3s6965)]
|
||||||
mod app {
|
mod app {
|
||||||
|
#[shared]
|
||||||
|
struct MySharedResources {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct MyLocalResources {}
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(_: init::Context) -> init::LateResources {
|
fn init(_: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
|
||||||
rtic::pend(Interrupt::UART0);
|
rtic::pend(Interrupt::UART0);
|
||||||
|
|
||||||
init::LateResources {}
|
(MySharedResources, MyLocalResources, init::Monotonics())
|
||||||
}
|
}
|
||||||
|
|
||||||
// [еще код]
|
// [more code]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Структура Resources - `#[resources]`
|
|
||||||
|
|
||||||
Ранее ресурсы RTIC должны были располагаться в структуре с именем "Resources":
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
struct Resources {
|
|
||||||
// Ресурсы определены здесь
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
В RTIC v0.6.0 структура ресурсов аннотируется также, как и
|
|
||||||
`#[task]`, `#[init]`, `#[idle]`: атрибутом `#[resources]`
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
#[resources]
|
|
||||||
struct Resources {
|
|
||||||
// Ресурсы определены здесь
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
На самом деле, имя структуры предоставлено на усмотрение разработчика:
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
#[resources]
|
|
||||||
struct Whateveryouwant {
|
|
||||||
// Ресурсы определены здесь
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
будет работать так же хороршо.
|
|
||||||
|
|
||||||
## Вызов/планирование откуда угодно
|
## Вызов/планирование откуда угодно
|
||||||
|
|
||||||
С этой новой возвожностью, старый код, такой как:
|
С этой новой возвожностью, старый код, такой как:
|
||||||
|
@ -161,40 +352,6 @@ fn bar(_c: bar::Context) {
|
||||||
|
|
||||||
Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
|
Заметьте, что атрибуты `spawn` и `schedule` больше не нужны.
|
||||||
|
|
||||||
## Симметричные блокировки
|
|
||||||
|
|
||||||
Теперь RTIC использует симметричные блокировки, это значит, что метод `lock` нужно использовать для
|
|
||||||
всех доступов к ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу,
|
|
||||||
в старом коде можно было следующее:
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
#[task(priority = 2, resources = [r])]
|
|
||||||
fn foo(cx: foo::Context) {
|
|
||||||
cx.resources.r = /* ... */;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task(resources = [r])]
|
|
||||||
fn bar(cx: bar::Context) {
|
|
||||||
cx.resources.r.lock(|r| r = /* ... */);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
С симметричными блокировками нужно вызывать `lock` для обоих задач:
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
#[task(priority = 2, resources = [r])]
|
|
||||||
fn foo(cx: foo::Context) {
|
|
||||||
cx.resources.r.lock(|r| r = /* ... */);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task(resources = [r])]
|
|
||||||
fn bar(cx: bar::Context) {
|
|
||||||
cx.resources.r.lock(|r| r = /* ... */);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Заметьте, что скорость работы не изменяется благодаря оптимизациям LLVM, которые убирают ненужные блокировки.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Дополнительно
|
## Дополнительно
|
||||||
|
|
Loading…
Reference in a new issue