mirror of
https://github.com/rtic-rs/rtic.git
synced 2025-12-18 05:45:19 +01:00
update russian translation of the book
This commit is contained in:
parent
83cdf00eec
commit
05bda2b1bd
28 changed files with 3108 additions and 418 deletions
|
|
@ -1,77 +1,84 @@
|
|||
# The `app` attribute
|
||||
# Атрибут `app`
|
||||
|
||||
Это наименьшая возможная программа на RTIC:
|
||||
Это простейшая из возможных программ на RTIC:
|
||||
|
||||
``` rust
|
||||
{{#include ../../../../examples/smallest.rs}}
|
||||
```
|
||||
|
||||
Все программы на RTIC используют атрибут [`app`] (`#[app(..)]`). Этот атрибут
|
||||
нужно применять к `const`-элементам, содержащим элементы. Атрибут `app` имеет
|
||||
обязательный аргумент `device`, в качестве значения которому передается *путь*.
|
||||
Этот путь должен указывать на библиотеку *устройства*, сгенерированную с помощью
|
||||
[`svd2rust`] **v0.14.x**. Атрибут `app` развернется в удобную точку входа,
|
||||
поэтому нет необходимости использовать атрибут [`cortex_m_rt::entry`].
|
||||
должен применяться к элементу `mod`. Атрибут `app` имеет обязательный аргумент `device`,
|
||||
который принимает *путь* как значение. Это должен быть полный путь, указывающий на
|
||||
*крейт доступа к периферии* (PAC), сгенерированный с помощью [`svd2rust`] версии **v0.14.x**
|
||||
или новее. Более подробно в разделе [Создание нового проекта](./new.md).
|
||||
|
||||
Атрибут `app` будет раскрыт в подходящую точку входа программы, поэтому
|
||||
атрибут [`cortex_m_rt::entry`] не нужен.
|
||||
|
||||
[`app`]: ../../../api/cortex_m_rtic_macros/attr.app.html
|
||||
[`svd2rust`]: https://crates.io/crates/svd2rust
|
||||
[`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html
|
||||
|
||||
> **ОТСТУПЛЕНИЕ**: Некоторые из вас удивятся, почему мы используем ключевое слово `const` как
|
||||
> модуль, а не правильное `mod`. Причина в том, что использование атрибутов на
|
||||
> модулях требует feature gate, который требует ночную сборку. Чтобы заставить
|
||||
> RTIC работать на стабильной сборке, мы используем вместо него слово `const`.
|
||||
> Когда большая часть макросов 1.2 стабилизируются, мы прейдем от `const` к `mod` и в конце концов в атрибуту уровне приложения (`#![app]`).
|
||||
|
||||
## `init`
|
||||
|
||||
Внутри псевдо-модуля атрибут `app` ожидает найти функцию инициализации, обозначенную
|
||||
атрибутом `init`. Эта функция должна иметь сигнатуру `[unsafe] fn()`.
|
||||
Внутри модуля `app` атрибут ожидает найти функцию инициализации, помеченную
|
||||
атрибутом `init`. Эта функция должна иметь сигнатуру
|
||||
`fn(init::Context) [-> init::LateResources]` (возвращаемый тип нужен не всегда).
|
||||
|
||||
Эта функция инициализации будет первой частью запускаемого приложения.
|
||||
Функция `init` запустится *с отключенными прерываниями* и будет иметь эксклюзивный
|
||||
доступ к периферии Cortex-M и специфичной для устройства периферии через переменные
|
||||
`core` and `device`, которые внедряются в область видимости `init` атрибутом `app`.
|
||||
Не вся периферия Cortex-M доступна в `core`, потому что рантайм RTIC принимает владение
|
||||
частью из неё -- более подробно см. структуру [`rtic::Peripherals`].
|
||||
Эта функция инициализации будет первой частью программы, выполняемой при запуске.
|
||||
Функция `init` будет запущена *с отключенными прерываниями* и будет иметь эксклюзивный доступ
|
||||
к Cortex-M, в котором токен `bare_metal::CriticalSection` доступен как `cs`.
|
||||
Опционально, устройство-специфичные периферия доступна через поля `core` и `device` структуры
|
||||
`init::Context`.
|
||||
|
||||
Переменные `static mut`, определённые в начале `init` будут преобразованы
|
||||
в ссылки `&'static mut` с безопасным доступом.
|
||||
`static mut` переменные, определенные в начале `init` будут преобразованы в
|
||||
`&'static mut` ссылки, безопасные для доступа. Обратите внимание, данная возможность может
|
||||
быть удалена в следующем релизе, см. `task_local` ресурсы.
|
||||
|
||||
[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
|
||||
|
||||
Пример ниже показывает типы переменных `core` и `device` и
|
||||
демонстрирует безопасный доступ к переменной `static mut`.
|
||||
Пример ниже показывает типы полей `core`, `device` и `cs`, и демонстрирует
|
||||
безопасный доступ к `static mut` переменной. Поле `device` доступно только
|
||||
когда аргумент `peripherals` установлен в `true` (по умолчанию).
|
||||
В редких случаях, когда вы захотите создать приложение с минимальным потреблением ресурсов,
|
||||
можно явно установить `peripherals` в `false`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../../examples/init.rs}}
|
||||
```
|
||||
|
||||
Запуск примера напечатает `init` в консоли и завершит процесс QEMU.
|
||||
Запуск примера напечатате `init` в консоли, а затем завершит процесс QEMU.
|
||||
|
||||
``` console
|
||||
$ cargo run --example init
|
||||
{{#include ../../../../ci/expected/init.run}}```
|
||||
{{#include ../../../../ci/expected/init.run}}
|
||||
```
|
||||
|
||||
## `idle`
|
||||
|
||||
Функция, помеченная атрибутом `idle` может присутствовать в псевдо-модуле
|
||||
опционально. Эта функция используется как специальная *задача ожидания* и должна иметь
|
||||
сигнатуру `[unsafe] fn() - > !`.
|
||||
Функцию, помеченную атрибутом `idle` может опционально добавить в модуль.
|
||||
Эта функция используется как специальная *задача ожидания* и должна иметь сигнатуру
|
||||
`fn(idle::Context) - > !`.
|
||||
|
||||
Когда она присутствует, рантайм запустит задачу `idle` после `init`. В отличие от
|
||||
`init`, `idle` запустится *с включенными прерываниями* и не может завершиться,
|
||||
поэтому будет работать бесконечно.
|
||||
Если она присутствует, задача `idle` будет запущена после `init`. В отличие от
|
||||
`init`, `idle` будет запущена *с включенными прерываниями* и она не может вернуть результат,
|
||||
а значит должна работать вечно.
|
||||
|
||||
Когда функция `idle` не определена, рантайм устанавливает бит [SLEEPONEXIT], после чего
|
||||
отправляет микроконтроллер в состояние сна после выполнения `init`.
|
||||
Если функция `idle` не определена, среда вполнения устанавливает бит [SLEEPONEXIT], а затем
|
||||
отправляет микроконтроллер в сон после запуска `init`.
|
||||
|
||||
[SLEEPONEXIT]: https://developer.arm.com/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit
|
||||
|
||||
Как и в `init`, переменные `static mut`будут преобразованы в ссылки `&'static mut`
|
||||
с безопасным доступом.
|
||||
Как и в `init`, `static mut` переменные будут трансформированы в `&'static mut` ссылки,
|
||||
безопасные для доступа. Обратите внимание, данная возможность может
|
||||
быть удалена в следующем релизе, см. `task_local` ресурсы.
|
||||
|
||||
В примере ниже показан запуск `idle` после `init`.
|
||||
Пример ниже показывает, что `idle` запускается после `init`.
|
||||
|
||||
**Примечание:** Цикл `loop {}` в функци ожидания не может быть пустым, так как это сломает
|
||||
микроконтроллер, из-за того, что LLVM компилирует пустые циклы в инструкцию `UDF` в release mode.
|
||||
Чтобы избежать неопределенного поведения, цикл должен включать "side-effect"
|
||||
путем вставки ассемблерной инструкции (например, `WFI`) или ключевого слова `continue`.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../../examples/idle.rs}}
|
||||
|
|
@ -79,23 +86,75 @@ $ cargo run --example init
|
|||
|
||||
``` console
|
||||
$ cargo run --example idle
|
||||
{{#include ../../../../ci/expected/idle.run}}```
|
||||
{{#include ../../../../ci/expected/idle.run}}
|
||||
```
|
||||
|
||||
## `interrupt` / `exception`
|
||||
## Аппаратные задачи
|
||||
|
||||
Как Вы бы сделали с помощью библиотеки `cortex-m-rt`, Вы можете использовать атрибуты
|
||||
`interrupt` и `exception` внутри псевдо-модуля `app`, чтобы определить обработчики
|
||||
прерываний и исключений. В RTIC, мы называем обработчики прерываний и исключений
|
||||
*аппаратными* задачами.
|
||||
Чтобы объявить обработчик прерывания, фреймворк предоставляет атрибут `#[task]`,
|
||||
который можно применять к функциям. Этот атрибут берет аргумент `binds`, чье значение -
|
||||
это имя прерывания, которому будет назначен обработчик;
|
||||
функция, декорированная этим атрибутом становится обработчиком прерывания.
|
||||
В фреймворке такие типы задач именуются *аппаратными*, потому что они начинают
|
||||
выполняться в ответ на аппаратное событие.
|
||||
|
||||
Пример ниже демонстрирует использование атрибута `#[task]`, чтобы объявить
|
||||
обработчик прерывания. Как и в случае с `#[init]` и `#[idle]` локальные `static
|
||||
mut` переменные безопасны для использования с аппаратной задачей.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../../examples/interrupt.rs}}
|
||||
{{#include ../../../../examples/hardware.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example interrupt
|
||||
{{#include ../../../../ci/expected/interrupt.run}}```
|
||||
$ cargo run --example hardware
|
||||
{{#include ../../../../ci/expected/hardware.run}}
|
||||
```
|
||||
|
||||
До сих пор программы RTIC, которые мы видели не отличались от программ, которые
|
||||
можно написать, используя только библиотеку `cortex-m-rt`. В следующем разделе
|
||||
мы начнем знакомиться с функционалом, присущим только RTIC.
|
||||
До сих пор все программы на RTIC, которые мы видели, не отличались от программ,
|
||||
которые можно написать, используя лишь крейт `cortex-m-rt`. С этого момента мы
|
||||
начинаем представлять возможности, уникальные для RTIC.
|
||||
|
||||
## Приоритеты
|
||||
|
||||
Статический приоритет каждого обработчика можно оределить в атрибуте `task`, используя
|
||||
аргумент `priority`. Задачи могут иметь приоритет в диапазоне `1..=(1 << NVIC_PRIO_BITS)`,
|
||||
где `NVIC_PRIO_BITS` - это константа, определенная в крейте `устройства`.
|
||||
Когда аргумент `priority` не указан, предполагается, что приоритет равен `1`.
|
||||
Задача `idle` имеет ненастраиваемый приоритет `0`, наименьший из возможных.
|
||||
|
||||
> Более высокое значение означает более высокий приоритет в RTIC, что противоположно тому,
|
||||
> что указано в периферии NVIC Cortex-M.
|
||||
> Точнее, это значит, что число `10` обозначает приоритет **выше**, чем число `9`.
|
||||
|
||||
Когда несколько задач готовы к запуску, задача с самым большим статическим
|
||||
приоритетом будет запущена первой. Приоритезацию задач можно рассматривать по
|
||||
такому сценарию: сигнал прерывания приходит во время выполнения задачи с низким приоритетом;
|
||||
сигнал переключает задачу с высоким приоритетом в режим ожидания.
|
||||
Разница в приоритетах приводи к тому, что задача с высоким приоритетом вытесняет задачу с низким:
|
||||
выполнение задачи с низким приоритетом замораживается и задача с высоким приоритетом выполняется,
|
||||
пока не будет завершена. Как только задача с высоким приоритетом будет остановлена,
|
||||
продолжится выполнение задачи с низким приоритетом.
|
||||
|
||||
Следующий пример демонстрирует диспетчеризацию на основе приоритетов задач.
|
||||
|
||||
``` rust
|
||||
{{#include ../../../../examples/preempt.rs}}
|
||||
```
|
||||
|
||||
``` console
|
||||
$ cargo run --example preempt
|
||||
{{#include ../../../../ci/expected/preempt.run}}
|
||||
```
|
||||
|
||||
Заметьте, что задача `gpiob` *не* вытесняет задачу `gpioc`, потому что ее приоритет
|
||||
*такой же*, как и у `gpioc`. Однако, как только `gpioc` возвращает результат,
|
||||
выполненяется задача `gpiob`, как более приоритетная по сравнению с `gpioa`.
|
||||
Выполнение `gpioa` возобновляется только после выхода из `gpiob`.
|
||||
|
||||
Еще одно замечание по поводу приоритетов: выбор приоритета большего, чем поддерживает устройство
|
||||
(а именно `1 << NVIC_PRIO_BITS`) приведет к ошибке компиляции.
|
||||
Из-за ограничений языка, сообщение об ошибке далеко от понимания:
|
||||
вам скажут что-то похожее на "evaluation of constant value failed", а указатель на ошибку
|
||||
*не* покажет на проблемное значение прерывания --
|
||||
мы извиняемся за это!
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue