aboutsummaryrefslogtreecommitdiff
path: root/ru/src/by-example/resources.md
blob: 096c803b1bea6edb4c796df1aaacc9023ccc8632 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
## Ресурсы

Одно из ограничений атрибутов, предоставляемых библиотекой `cortex-m-rt` является
то, что совместное использование данных (или периферии) между прерываниями,
или прерыванием и функцией `init`, требуют `cortex_m::interrupt::Mutex`, который
*всегда* требует отключения *всех* прерываний для доступа к данным. Отключение всех
прерываний не всегда необходимо для безопасности памяти, но компилятор не имеет
достаточно информации, чтобы оптимизировать доступ к разделяемым данным.

Атрибут `app` имеет полную картину приложения, поэтому может оптимизировать доступ к
`static`-переменным. В RTFM мы обращаемся к `static`-переменным, объявленным внутри
псевдо-модуля `app` как к *ресурсам*. Чтобы получить доступ к ресурсу, контекст
(`init`, `idle`, `interrupt` или `exception`) должен сначала определить
аргумент `resources` в соответствующем атрибуте.

В примере ниже два обработчика прерываний имеют доступ к одному и тому же ресурсу.
Никакого `Mutex` в этом случае не требуется, потому что оба обработчика запускаются
с одним приоритетом и никакого вытеснения быть не может.
К ресурсу `SHARED` можно получить доступ только из этих двух прерываний.

``` rust
{{#include ../../../examples/resource.rs}}
```

``` console
$ cargo run --example resource
{{#include ../../../ci/expected/resource.run}}
```

## Приоритеты

Приоритет каждого прерывания можно определить в атрибутах `interrupt` и `exception`.
Невозможно установить приоритет любым другим способом, потому что рантайм
забирает владение прерыванием `NVIC`; также невозможно изменить приоритет
обработчика / задачи в рантайме. Благодаря этому ограничению у фреймворка
есть знание о *статических* приоритетах всех обработчиков прерываний и исключений.

Прерывания и исключения могут иметь приоритеты в интервале `1..=(1 << NVIC_PRIO_BITS)`,
где `NVIC_PRIO_BITS` - константа, определённая в библиотеке `device`.
Задача `idle` имеет приоритет `0`, наименьший.

Ресурсы, совместно используемые обработчиками, работающими на разных приоритетах,
требуют критических секций для безопасности памяти. Фреймворк проверяет, что
критические секции используются, но *только где необходимы*: например,
критические секции не нужны для обработчика с наивысшим приоритетом, имеющим
доступ к ресурсу.

API критической секции, предоставляемое фреймворком RTFM (см. [`Mutex`]),
основано на динамических приоритетах вместо отключения прерываний. Из этого следует,
что критические секции не будут допускать *запуск некоторых* обработчиков,
включая все соперничающие за ресурс, но будут позволять запуск обработчиков с
большим приоритетом не соперничащих за ресурс.

[`Mutex`]: ../../api/rtfm/trait.Mutex.html

В примере ниже у нас есть 3 обработчика прерываний с приоритетами от одного
до трех. Два обработчика с низким приоритетом соперничают за ресурс `SHARED`.
Обработчик с низшим приоритетом должен заблокировать ([`lock`]) ресурс
`SHARED`, чтобы получить доступ к его данным, в то время как обработчик со
средним приоритетом может напрямую получать доступ к его данным. Обработчик
с наивысшим приоритетом может свободно вытеснять критическую секцию,
созданную обработчиком с низшим приоритетом.

[`lock`]: ../../api/rtfm/trait.Mutex.html#method.lock

``` rust
{{#include ../../../examples/lock.rs}}
```

``` console
$ cargo run --example lock
{{#include ../../../ci/expected/lock.run}}```

## Поздние ресурсы

В отличие от обычных `static`-переменных, к которым должно быть присвоено
начальное значение, ресурсы можно инициализировать в рантайме.
Мы называем ресурсы, инициализируемые в рантайме *поздними*. Поздние ресурсы
полезны для *переноса* (как при передаче владения) периферии из `init` в
обработчики прерываний и исключений.

Поздние ресурсы определяются как обычные ресурсы, но им присваивается начальное
значение `()` (the unit value). Поздние ресурсы необходимо инициализировать в конце
функции `init` используя обычное присвоение (например `FOO = 1`).

В примере ниже использованы поздние ресурсы, чтобы установить неблокированный,
односторонний канал между обработчиком прерывания `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}}```

## `static`-ресурсы

Переменные типа `static` также можно использовать в качестве ресурсов. Задачи
могут получать только (разделяемые) `&` ссылки на ресурсы, но блокировки не
нужны для доступа к данным. Вы можете думать о `static`-ресурсах как о простых
`static`-переменных, которые можно инициализировать в рантайме и иметь лучшие
правила видимости: Вы можете контролировать, какие задачи получают доступ к
переменной, чтобы переменная не была видна всем фунциям в область видимости,
где она была объявлена.

В примере ниже ключ загружен (или создан) в рантайме, а затем использован в двух
задачах, запущенных на разных приоритетах.

``` rust
{{#include ../../../examples/static.rs}}
```

``` console
$ cargo run --example static
{{#include ../../../ci/expected/static.run}}```