From 0fc86d972c0305e73252dc20d702d647eb342ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Tj=C3=A4der?= Date: Fri, 24 Feb 2023 21:28:13 +0100 Subject: Book: Remove RTIC v1 Russian translation --- book/ru/src/by-example/app.md | 161 --------------------------- book/ru/src/by-example/new.md | 84 -------------- book/ru/src/by-example/resources.md | 140 ------------------------ book/ru/src/by-example/tasks.md | 116 -------------------- book/ru/src/by-example/timer-queue.md | 108 ------------------ book/ru/src/by-example/tips.md | 175 ------------------------------ book/ru/src/by-example/types-send-sync.md | 49 --------- 7 files changed, 833 deletions(-) delete mode 100644 book/ru/src/by-example/app.md delete mode 100644 book/ru/src/by-example/new.md delete mode 100644 book/ru/src/by-example/resources.md delete mode 100644 book/ru/src/by-example/tasks.md delete mode 100644 book/ru/src/by-example/timer-queue.md delete mode 100644 book/ru/src/by-example/tips.md delete mode 100644 book/ru/src/by-example/types-send-sync.md (limited to 'book/ru/src/by-example') diff --git a/book/ru/src/by-example/app.md b/book/ru/src/by-example/app.md deleted file mode 100644 index 5259bfa..0000000 --- a/book/ru/src/by-example/app.md +++ /dev/null @@ -1,161 +0,0 @@ -# Атрибут `app` - -Это простейшая из возможных программ на RTIC: - -``` rust -{{#include ../../../../examples/smallest.rs}} -``` - -Все программы на RTIC используют атрибут [`app`] (`#[app(..)]`). Этот атрибут -должен применяться к элементу `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 - -## `init` - -Внутри модуля `app` атрибут ожидает найти функцию инициализации, помеченную -атрибутом `init`. Эта функция должна иметь сигнатуру -`fn(init::Context) (-> init::LateResources, init::Monotonics)`. - -Эта функция инициализации будет первой частью программы, выполняемой при запуске. -Функция `init` будет запущена *с отключенными прерываниями* и будет иметь эксклюзивный доступ -к Cortex-M, в котором токен `bare_metal::CriticalSection` доступен как `cs`. -Опционально, устройство-специфичные периферия доступна через поля `core` и `device` структуры -`init::Context`. - -`static mut` переменные, определенные в начале `init` будут преобразованы в -`&'static mut` ссылки, безопасные для доступа. Обратите внимание, данная возможность может -быть удалена в следующем релизе, см. `task_local` ресурсы. - -[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html - -Пример ниже показывает типы полей `core`, `device` и `cs`, и демонстрирует -безопасный доступ к `static mut` переменной. Поле `device` доступно только -когда аргумент `peripherals` установлен в `true` (по умолчанию). -В редких случаях, когда вы захотите создать приложение с минимальным потреблением ресурсов, -можно явно установить `peripherals` в `false`. - -``` rust -{{#include ../../../../examples/init.rs}} -``` - -Запуск примера напечатате `init` в консоли, а затем завершит процесс QEMU. - -``` console -$ cargo run --example init -{{#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` может опционально добавить в модуль. -Эта функция используется как специальная *задача ожидания* и должна иметь сигнатуру -`fn(idle::Context) - > !`. - -Если она присутствует, задача `idle` будет запущена после `init`. В отличие от -`init`, `idle` будет запущена *с включенными прерываниями* и она не может вернуть результат, -а значит должна работать вечно. - -Как и в `init`, `static mut` переменные будут трансформированы в `&'static mut` ссылки, -безопасные для доступа. Обратите внимание, данная возможность может -быть удалена в следующем релизе, см. `task_local` ресурсы. - -Пример ниже показывает, что `idle` запускается после `init`. - -**Примечание:** Цикл `loop {}` в функци ожидания не может быть пустым, так как это сломает -микроконтроллер, из-за того, что LLVM компилирует пустые циклы в инструкцию `UDF` в release mode. -Чтобы избежать неопределенного поведения, цикл должен включать "side-effect" -путем вставки ассемблерной инструкции (например, `WFI`) или ключевого слова `continue`. - -``` rust -{{#include ../../../../examples/idle.rs}} -``` - -``` console -$ cargo run --example idle -{{#include ../../../../ci/expected/idle.run}} -``` - -## Аппаратные задачи - -Чтобы объявить обработчик прерывания, фреймворк предоставляет атрибут `#[task]`, -который можно применять к функциям. Этот атрибут берет аргумент `binds`, чье значение - -это имя прерывания, которому будет назначен обработчик; -функция, декорированная этим атрибутом становится обработчиком прерывания. -В фреймворке такие типы задач именуются *аппаратными*, потому что они начинают -выполняться в ответ на аппаратное событие. - -Пример ниже демонстрирует использование атрибута `#[task]`, чтобы объявить -обработчик прерывания. Как и в случае с `#[init]` и `#[idle]` локальные `static -mut` переменные безопасны для использования с аппаратной задачей. - -``` rust -{{#include ../../../../examples/hardware.rs}} -``` - -``` console -$ cargo run --example hardware -{{#include ../../../../ci/expected/hardware.run}} -``` - -До сих пор все программы на 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", а указатель на ошибку -*не* покажет на проблемное значение прерывания -- -мы извиняемся за это! diff --git a/book/ru/src/by-example/new.md b/book/ru/src/by-example/new.md deleted file mode 100644 index 0ff8d98..0000000 --- a/book/ru/src/by-example/new.md +++ /dev/null @@ -1,84 +0,0 @@ -# Создание нового проекта - -Теперь, когда Вы изучили основные возможности фреймворка RTIC, Вы можете -попробовать его использовать на Вашем оборудовании следуя этим инструкциям. - -1. Создайте экземпляр из шаблона [`cortex-m-quickstart`]. - -[`cortex-m-quickstart`]: https://github.com/rust-embedded/cortex-m-quickstart#cortex-m-quickstart - -``` console -$ # например используя `cargo-generate` -$ cargo generate \ - --git https://github.com/rust-embedded/cortex-m-quickstart \ - --name app - -$ # следуйте остальным инструкциям -``` - -2. Добавьте крейт доступа к периферии (PAC), сгенерированный с помощью[`svd2rust`] - **v0.14.x**, или крейт отладочной платы, у которой в зависимостях один из таких PAC'ов. - Убедитесь, что опция `rt` крейта включена. - -[`svd2rust`]: https://crates.io/crates/svd2rust - -В этом примере я буду использовать крейт устройства [`lm3s6965`]. -Эта библиотека не имеет Cargo-опции `rt`; эта опция всегда включена. - -[`lm3s6965`]: https://crates.io/crates/lm3s6965 - -Этот крейт устройства предоставляет линковочный скрипт с макетом памяти -целевого устройства, поэтому `memory.x` и `build.rs` нужно удалить. - -``` console -$ cargo add lm3s6965 --vers 0.1.3 - -$ rm memory.x build.rs -``` - -3. Добавьте крейт `cortex-m-rtic` как зависимость. - -``` console -$ cargo add cortex-m-rtic --allow-prerelease -``` - -4. Напишите свою RTIC программу. - -Здесь я буду использовать пример `init` из крейта `cortex-m-rtic`. - -Примеры находтся в папке `examples`, а содержание `init.rs` показано здесь: - -``` console -{{#include ../../../../examples/init.rs}} -``` - -Пример `init` использует устройство `lm3s6965`. Не забудьте настроить аргумент `device` -в атрибуте макроса app так, чтобы он соответствовал пути к PAC-крейту, если он отличается, -а также добавить перифериб и другие аргументы если необходимо. -Несмотря на то, что в программе могут использоваться псевдонимы типов, -здесь необходимо указать полный путь (из корня крейта). Для многих устройств, -есть общий подход в крейтах реализации HAL (с псевдонимом `hal`) и крейтах поддержки -отладочных плат реекспортиорвать PAC как `pac`, что приводит нас к образцу, аналогичному -приведенному ниже: - -```rust -use abcd123_hal as hal; -//... - -#[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] -mod app { /*...*/ } -``` - -Пример `init` также зависит от крейта `panic-semihosting`: - -``` console -$ cargo add panic-semihosting -``` - -5. Соберите его, загрузите в микроконтроллер и запустите. - -``` console -$ # ПРИМЕЧАНИЕ: Я раскомментировал опцию `runner` в `.cargo/config.toml` -$ cargo run -{{#include ../../../../ci/expected/init.run}} -``` diff --git a/book/ru/src/by-example/resources.md b/book/ru/src/by-example/resources.md deleted file mode 100644 index ed8904b..0000000 --- a/book/ru/src/by-example/resources.md +++ /dev/null @@ -1,140 +0,0 @@ -# Ресурсы - -Фреймворк предоставляет абстракцию для разделения данных между любыми контекстами, -с которыми мы встречались в предыдущей главе (задачами-обработчиками, `init` и `idle`): ресурсы. - -Ресурсы - это данные, видимые только функциями, определенными внутри модуля `#[app]`. -Фреймворк дает пользователю полный контроль за тем, какой контекст может -получить доступ к какому ресурсу. - -Все ресурсы определены в *двух* структурах внутри модуля `#[app]`. -Каждое поле этих структур соответствует отдельному ресурсу. -Одна `struct`-ура должна быть аннотирована атрибутом `#[local]`. -Другая `struct`-ура должна быть аннотирована атрибутом `#[shared]`. -Разница между этими двумя множествами ресурсов будет описана познее. - -Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым -он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя -либо аргумент `local`, либо `shared`. Этот аргумент принимает список имен ресурсов в качестве значения. -Перечисленные ресурсы становятся доступны в контексте через поля `local` и `shared` структуры `Context`. - -Во время выполнения при выходе из функции `#[init]` все ресурсы инициализированы. -Функция `#[init]` должна возвращать начальные значения для всех ресурсов; -отсюда следует, что тип возвращаемого ею значения включает типы -структур `#[shared]` и `#[local]`. -Поскольку ресурсы инициализированы в ходе функции `#[init]`, к ним нельзя -получить доступ внетри функции `#[init]`. - -Пример программы, показанной ниже содержит два обработчика прерывания. -Каждый обработчик имеет доступ к его собственному `#[local]` ресурсу. - -``` rust -{{#include ../../../../examples/resource.rs}} -``` - -``` console -$ cargo run --example resource -{{#include ../../../../ci/expected/resource.run}} -``` - -К ресурсу `#[local]` нельзя получить доступ извне задачи к которой он -привязан атрибутом `#[task]`. -Попытка обращения к одному и тому же ресурсу `#[local]` из более чем одной -задачи - ошибка компиляции. - -## `lock` - -Критические секции необходимы для доступа к ресурсам `#[shared]` таким образом, -чтобы избежать гонок данных. - -Поле `shared`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого -ресурса, доступного задаче. - -Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции. - -[`Mutex`]: ../../../api/rtic/trait.Mutex.html -[`lock`]: ../../../api/rtic/trait.Mutex.html#method.lock - -Критическая секция, создаваемая интерфейсом `lock` основана на динамических приоритетах: -она временно повышает динамический приоритет контекста до *максимального* приоритета, -что не дает другим задачам возможности вытеснить критическую секцию. -Этот протокол синхронизации известен как [Протокол немедленного максимального приоритета -(ICPP)][icpp], и компилируется диспетчером RTIC с [Политикой ресурсов стека(SRP)][srp]. - -[icpp]: https://en.wikipedia.org/wiki/Priority_ceiling_protocol -[srp]: https://en.wikipedia.org/wiki/Stack_Resource_Policy - -В примере ниже у нас есть три обработчика прерываний с приоритетами от одного до трех. -Два из обработчиков с более низким приоритетом соревнуются за ресурс `shared`, -поэтому должны блокировать доступа к данным ресурса. -Обработчик с наивысшим приоритетом, который не имеет доступа к ресурсу `shared`, -может свободно вытеснять критическую секцию, созданную обработчиком с низким приоритетом. - -``` rust -{{#include ../../../../examples/lock.rs}} -``` - -``` console -$ cargo run --example lock -{{#include ../../../../ci/expected/lock.run}} -``` - -## Множественное блокировка - -Это расширение к `lock`, чтобы уменьшить количесво отступов, блокируемые ресурсы можно объединять в кортежи. -Следующий пример это демонстрирует: - -``` rust -{{#include ../../../../examples/multilock.rs}} -``` - -## Только разделяемый (`&-`) доступ - -По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам, -но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса -`&resource_name` в списке `resources`. - -Преимущество указания разделяемого досупа (`&-`) к ресурсу в том, что для доступа к ресурсу -не нужна блокировка, даже если за ресурс соревнуются несколько задач, запускаемые с -разными приоритетами. Недостаток в том, что задача получает только разделяемую ссылку (`&-`) -на ресурс, и ограничена операциями, возможными с ней, но там, где разделяемой ссылки достаточно, -такой подход уменьшает количесво требуемых блокировок. -В дополнение к простым неизменяемым данным, такой разделяемый доступ может быть полезен для -ресурсов, безопасно реализующих внутреннюю мутабельность с самоблокировкой или атомарными операциями. - -Заметьте, что в этом релизе RTIC невозможно запросить и эксклюзивный доступ (`&mut-`) -и разделяемый (`&-`) для *одного и того же* ресурса из различных задач. -Попытка это сделать приведет к ошибке компиляции. - -В примере ниже ключ (например криптографический ключ) загружается (или создается) во время выполнения, -а затем используется двумя задачами, запускаемымы с различным приоритетом без каких-либо блокировок. - -``` rust -{{#include ../../../../examples/only-shared-access.rs}} -``` - -``` console -$ cargo run --example only-shared-access -{{#include ../../../../ci/expected/only-shared-access.run}} -``` - -## Неблокируемый доступ к изменяемым ресурсам - -Критическая секция *не* требуется для доступа к ресурсу `#[shared]`, -к которому обращаются только из задач с *одинаковым* приоритетом. -В этом случае вы можете избежать `lock` API, добавив атрибут поля `#[lock_free]` при объявдении ресурса (смотреть пример ниже). -Заметьте, что это лишь для удобства: даже если вы используете `lock` API, -во время выполнения фреймворк *не* создаст критическую секцию. -Еще одно ценное замечание: использование `#[lock_free]` на ресурсах, -разделяемых задачами, запускаемыми с разными приоритетами -приведет к ошибке *компиляции* -- не импользование `lock` API может -привести к гонке данных в этом случае. - -``` rust -{{#include ../../../../examples/lock-free.rs}} -``` - -``` console -$ cargo run --example lock-free -{{#include ../../../../ci/expected/lock-free.run}} -``` \ No newline at end of file diff --git a/book/ru/src/by-example/tasks.md b/book/ru/src/by-example/tasks.md deleted file mode 100644 index 3c99d00..0000000 --- a/book/ru/src/by-example/tasks.md +++ /dev/null @@ -1,116 +0,0 @@ -# Программные задачи - -В дополнение к аппаратным задачам, вызываемым в ответ на аппаратные события, -RTIC также поддерживает *программные* задачи, которые могут порождаться -приложением из любого контекста выполнения. - -Программным задачам можно также назначать приоритет и, под капотом, они -диспетчеризуются обработчиками прерываний. RTIC требует, чтобы свободные -прерывания, были указаны в аргументе `dispatchers` модуля `app`, если используются -программные задачи; часть из этих свободных прерываний будут использованы для -управления программными задачами. Преимущество программных задач над аппаратными -в том, что множество задач можно назначить на один обработчик прерывания. - -Программные задачи также определяются атрибутом `task`, но аргумент `binds` опускается. - -Пример ниже демонстрирует три программные задачи, запускаемых 2-х разных приоритетах. -Три программные задачи привязаны к 2-м обработчикам прерываний. - -``` rust -{{#include ../../../../examples/task.rs}} -``` - -``` console -$ cargo run --example task -{{#include ../../../../ci/expected/task.run}} -``` - -## Передача сообщений - -Другое преимущество программной задачи в том, что задачам можно передать сообщения -в момент их запуска. Тип передаваемого сообщения должен быть определен в сигнатуре -задачи-обработчика. - -Пример ниже демонстрирует три задачи, две из которых ожидают сообщение. - -``` rust -{{#include ../../../../examples/message.rs}} -``` - -``` console -$ cargo run --example message -{{#include ../../../../ci/expected/message.run}} -``` - -## Вместимость - -RTIC *не* производит никакого рода аллокаций памяти в куче. -Память, необходимая для размещения сообщения резервируется статически. -По-умолчанию фреймворк минимизирует выделение памяти программой таким образом, -что каждая задача имеет "вместимость" для сообщения равную 1: -это значит, что не более одного сообщения можно передать задаче перед тем, как -у нее появится возможность к запуску. Это значение по-умолчанию можно -изменить для каждой задачи, используя аргумент `capacity`. -Этот аргумент принимает положительное целое, которое определяет как много -сообщений буфер сообщений задачи может хранить. - -Пример ниже устанавливает вместимость программной задачи `foo` равной 4. -Если вместимость не установить, второй вызов `spawn.foo` в `UART0` приведет к ошибке (панике). - -``` rust -{{#include ../../../../examples/capacity.rs}} -``` - -``` console -$ cargo run --example capacity -{{#include ../../../../ci/expected/capacity.run}} -``` - -## Обработка ошибок - -Интерфейс `spawn` возвращает вариант `Err`, если для размещения сообщения нет места. -В большинстве сценариев возникающие ошибки обрабатываются одним из двух способов: - -- Паника, с помощью `unwrap`, `expect`, и т.п. Этот метод используется, чтобы обнаружить - ошибку программиста (например bug) выбора вместительности, которая оказалась недостаточна. - Когда эта паника встречается во время тестирования, выбирается большая вместительность, - и перекомпиляция программы может решить проблему, но иногда достаточно окунуться глубже - и провести анализ времени выполнения программы, чтобы выяснить, может ли платформа - обрабатывать пиковые нагрузки, или процессор необходимо заменить на более быстрый. - -- Игнорирование результата. В программах реального времени, как и в обычных, может быть - нормальным иногда терять данные, или не получать ответ на некоторые события в пиковых ситуациях. - В таких сценариях может быть допустимо игнорирование ошибки вызова `spawn`. - -Следует отметить, что повторная попытка вызова `spawn` обычно неверный подход, поскольку -такая операция на практике вероятно никогда не завершится успешно. -Так как у нас есть только переключения контекста на задачи с *более высоким* приоритетом, -повторение вызова `spawn` на задаче с низким приоритом никогда не позволит планировщику -вызвать задачу, что значит, что буфер никогда не будет очищен. Такая ситуация отражена в -следующем наброске: - -``` rust -#[rtic::app(..)] -mod app { - #[init(spawn = [foo, bar])] - fn init(cx: init::Context) { - cx.spawn.foo().unwrap(); - cx.spawn.bar().unwrap(); - } - - #[task(priority = 2, spawn = [bar])] - fn foo(cx: foo::Context) { - // .. - - // программа зависнет здесь - while cx.spawn.bar(payload).is_err() { - // повтор попытки вызова spawn, если произошла ошибка - } - } - - #[task(priority = 1)] - fn bar(cx: bar::Context, payload: i32) { - // .. - } -} -``` diff --git a/book/ru/src/by-example/timer-queue.md b/book/ru/src/by-example/timer-queue.md deleted file mode 100644 index c8818d7..0000000 --- a/book/ru/src/by-example/timer-queue.md +++ /dev/null @@ -1,108 +0,0 @@ -# Очередь таймера - -В отличие от интерфейса `spawn`, который немедленно передает программную задачу -планировщику для немедленного запуска, интерфейс `schedule` можно использовать -для планирования задачи к запуске через какое-то время в будущем. - -Чтобы использовать интерфейс `schedule`, предварительно должен быть определен -монотонный таймер с помощью аргумента `monotonic` атрибута `#[app]`. -Этот аргумент принимает путь к типу, реализующему трейт [`Monotonic`]. -Ассоциированный тип, `Instant`, этого трейта представляет метку времени в соответствущих -единицах измерения и широко используется в интерфейсе `schedule` -- предлагается смоделировать -этот тип позднее [один из таких есть в стандартной библиотеке][std-instant]. - -Хотя это не отражено в определении трейта (из-за ограничений системы типов / трейтов), -разница двух `Instant`ов должна возвращать какой-то тип `Duration` (см. [`core::time::Duration`]) -и этот `Duration` должен реализовывать трейт `TryInto`. -Реализация этого трейта должна конвертировать значение `Duration`, которое -использует какую-то определенную единицу измерения времени, в единицы измерения "тактов системного таймера -(SYST)". Результат преобразований должен быть 32-битным целым. -Если результат не соответствует 32-битному целому, тогда операция должна возвращать ошибку любого типа. - -[`Monotonic`]: ../../../api/rtic/trait.Monotonic.html -[std-instant]: https://doc.rust-lang.org/std/time/struct.Instant.html -[`core::time::Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html - -Для целевых платформ ARMv7+ крейт `rtic` предоставляет реализацию `Monotonic`, основанную на -встроенном CYCle CouNTer (CYCCNT). Заметьте, что это 32-битный таймер, работающий на -частоте центрального процессора, и поэтому не подходит для отслеживания интервалов времени в секундах. - -Когда планируется задача, (определенный пользователем) `Instant`, в который задача должна быть -выполнена, должен передаваться в качестве первого аргумента вызова `schedule`. - -К тому же, выбранный `monotonic` таймер, необходимо сконфигурировать и инициализировать в -фазе работы `#[init]`. Заметьте, что *также* касается случая использования `CYCCNT`, -предоставляемого крейтом `cortex-m-rtic`. - -Пример ниже планирует к выполнению две задачи из `init`: `foo` и `bar`. `foo` запланирована -к запуску через 8 миллионов циклов в будущем. Далее, `bar` запланировано запустить через -4 миллиона циклов в будущем. Таким образом, `bar` запустится до `foo`, так как и запланировано. - -> **DF:YJ**: Примеры, использующие интерфейс `schedule` или абстракцию `Instant` -> **не будут** правильно работать на эмуляторе QEMU, поскольку счетчик циклов Cortex-M -> функционально не был реализован в `qemu-system-arm`. - -``` rust -{{#include ../../../../examples/schedule.rs}} -``` - -Запусе программы на реальном оборудовании создает следующий вывод в консоли: - -``` text -{{#include ../../../../ci/expected/schedule.run}} -``` - -Когда интерфейс `schedule` используется, среда исполнения использует внутри -обработчик прерываний `SysTick` и периферию системного таймера (`SYST`), поэтому ни -тот ни другой нельзя использовать в программе. Это гарантируется изменением типа -`init::Context.core` с `cortex_m::Peripherals` на `rtic::Peripherals`. -Последняя структура содержит все поля из предыдущей кроме `SYST`. - -## Периодические задачи - -Программные задачи имеют доступ к моменту времени `Instant`, в который они были запланированы -на выполнение переменной `scheduled`. Эта информация и интерфейс `schedule` можно использовать, -чтобы реализовать периодические задачи, как показано ниже. - -``` rust -{{#include ../../../../examples/periodic.rs}} -``` - -Это вывод, создаваемый примером. Заметьте, что здесь пристствует небольшой дрейф / колебания -даже несмотря на то, что `schedule.foo` была вызвана в *конце* `foo`. Использование -`Instant::now` вместо `scheduled` вызвало бы дрейф / колебания. - -``` text -{{#include ../../../../ci/expected/periodic.run}} -``` - -## Базовое время - -Для задач, вызываемых из `init` мы имеем точную информацию о их `scheduled` времени. -Для аппаратных задач такого времени нет, поскольку они асинхронны по природе. -Для аппаратных задач среда исполнения предоставляет время запуска (`start`), которое отражает -время, в которое обработчик прерывания будет запущен. - -Заметьте, что `start` **не** равно времени прихода события, которое вызывает задачу. -В зависимости от приоритета задачи и загрузки системы, время `start` может сильно отдалиться от -времени прихода события. - -Какое по вашему мнению будет значение `scheduled` для программных задач, которые вызываются через -`spawn` вместо планирования? Ответ в том, что вызываемые задачи наследуют -*базовое* время того контекста, который их вызывает. Базовое время аппаратных задач - -это их время `start`, базовое время программных задач - их время `scheduled`, а -базовое время `init` - время старта системы, или нулевое -(`Instant::zero()`). `idle` на самом деле не имеет базового времени, но задачи вызываемые из нее, -используют `Instant::now()` в качестве базового. - -Пример ниже демонстрирует разные смыслы *базового времени*. - -``` rust -{{#include ../../../../examples/baseline.rs}} -``` - -Запуск программы на реальном оборудовании приведет к следующему выводу в консоли: - -``` text -{{#include ../../../../ci/expected/baseline.run}} -``` diff --git a/book/ru/src/by-example/tips.md b/book/ru/src/by-example/tips.md deleted file mode 100644 index 7d4fc2f..0000000 --- a/book/ru/src/by-example/tips.md +++ /dev/null @@ -1,175 +0,0 @@ -# Советы и хитрости - -Полные примеры для RTIC смотрите в репозитарии [rtic-examples][rtic-examples]. - -[rtic-examples]: https://github.com/rtic-rs/rtic-examples - -## Обобщенное программирование (Generics) - -Все объекты, предоставляющие ресурысы реализуют трейт `rtic::Mutex`. -Если ресурс не реализует его, можно обернуть его в новый тип [`rtic::Exclusive`], -который реализует трейт `Mutex`. С помощью этого нового типа -можно написать обобщенную функцию, которая работает с обобщенным ресурсом и -вызывать его из различных задач, чтобы производить однотипные операции над -похожим множеством ресурсов. -Вот один такой пример: - -[`rtic::Exclusive`]: ../../../api/rtic/struct.Exclusive.html - -``` rust -{{#include ../../../../examples/generics.rs}} -``` - -``` console -$ cargo run --example generics -{{#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 - -$ cargo run --example cfg -{{#include ../../../../ci/expected/cfg.run}} -``` - -## Запуск задач из ОЗУ - -Главной целью переноса описания программы на RTIC в атрибуты в -RTIC v0.4.x была возможность взаимодействия с другими атрибутами. -Напримерe, атрибут `link_section` можно применять к задачам, чтобы разместить -их в ОЗУ; это может улучшить производительность в некоторых случаях. - -> **ВАЖНО**: Обычно атрибуты `link_section`, `export_name` и `no_mangle` -> очень мощные, но их легко использовать неправильно. Неверное использование -> любого из этих атрибутов может вызвать неопределенное поведение; -> Вам следует всегда предпочитать использование безопасных, высокоуровневых -> атрибутов вместо них, таких как атрибуты `interrupt` и `exception` -> из `cortex-m-rt`. -> -> В особых функций, размещаемых в ОЗУ нет безопасной абстракции в `cortex-m-rt` -> v0.6.5 но создано [RFC] для добавления атрибута `ramfunc` в будущем релизе. - -[RFC]: https://github.com/rust-embedded/cortex-m-rt/pull/100 - -В примере ниже показано как разместить высокоприоритетную задачу `bar` в ОЗУ. - -``` rust -{{#include ../../../../examples/ramfunc.rs}} -``` - -Запуск этой программы создаст ожидаемый вывод. - -``` console -$ cargo run --example ramfunc -{{#include ../../../../ci/expected/ramfunc.run}} -``` - -Можно посмотреть на вывод `cargo-nm`, чтобы убедиться, что `bar` расположен в ОЗУ -(`0x2000_0000`), тогда как `foo` расположен во Flash (`0x0000_0000`). - -``` console -$ cargo nm --example ramfunc --release | grep ' foo::' -{{#include ../../../../ci/expected/ramfunc.run.grep.foo}} -``` - -``` console -$ cargo nm --example ramfunc --release | grep ' bar::' -{{#include ../../../../ci/expected/ramfunc.run.grep.bar}} -``` - -## Обходной путь для быстрой передачи сообщений - -Передача сообщений всегда вызывает копирование от отправителя в -статическую переменную, а затем из статической переменной получателю. -Таким образом, при передаче большого буфера, например `[u8; 128]`, передача сообщения -вызывает два дорогих вызова `memcpy`. Чтобы минимизировать накладные расходы на передачу -сообщения, можно использовать обходной путь: вместо передачи буфера по значению, -можно передавать владеющий указатель на буфер. - -Можно использовать глобальный аллокатор, чтобы реализовать данный трюк (`alloc::Box`, -`alloc::Rc`, и т.п.), либо использовать статически аллоцируемый пул памяти, например [`heapless::Pool`]. - -[`heapless::Pool`]: https://docs.rs/heapless/0.5.0/heapless/pool/index.html - -Здесь приведен пример использования `heapless::Pool` для "упаковки" буфера из 128 байт. - -``` rust -{{#include ../../../../examples/pool.rs}} -``` - -``` console -$ 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}} -``` diff --git a/book/ru/src/by-example/types-send-sync.md b/book/ru/src/by-example/types-send-sync.md deleted file mode 100644 index 755a379..0000000 --- a/book/ru/src/by-example/types-send-sync.md +++ /dev/null @@ -1,49 +0,0 @@ -# Типы, Send и Sync - -Каждая функция в модуле `app` принимает структуру `Context` в качесте первого параметра. -Все поля этих структур имеют предсказуемые, неанонимные типы, -поэтому вы можете написать обычные функции, принимающие их как аргументы. - -Справочник по API определяет как эти типы генерируются на основе входных данных. -Вы можете также сгенерировать документацию к вашему крейту программы (`cargo doc --bin `); -в документации вы найдете структуры `Context` (например `init::Context` и -`idle::Context`). - -Пример ниже показывает различные типы, сгенерированные атрибутом `app`. - -``` rust -{{#include ../../../../examples/types.rs}} -``` - -## `Send` - -[`Send`] - это маркерный трейт для "типов, которые можно передавать через границы -потоков", как это определено в `core`. В контексте RTIC трейт `Send` необходим -только там, где возможна передача значения между задачами, запускаемыми на -*разных* приоритетах. Это возникает в нескольких случаях: при передаче сообщений, -в разделяемых `static mut` ресурсах и при инициализации поздних ресурсов. - -[`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html - -Атрибут `app` проверит, что `Send` реализован, где необходимо, поэтому вам не -стоит волноваться об этом. В настоящий момент все передаваемые типы в RTIC должны быть `Send`, но -это ограничение возможно будет ослаблено в будущем. - -## `Sync` - -Аналогично, [`Sync`] - маркерный трейт для "типов, на которые можно безопасно разделять между потоками", -как это определено в `core`. В контексте RTIC типаж `Sync` необходим только там, -где возможно для двух или более задач, запускаемых на разных приоритетах получить разделяемую ссылку (`&-`) на -ресурс. Это возникает только (`&-`) ресурсах с разделяемым доступом. - -[`Sync`]: https://doc.rust-lang.org/core/marker/trait.Sync.html - -Атрибут `app` проверит, что `Sync` реализован, где необходимо, но важно знать, -где ограничение `Sync` не требуется: в (`&-`) ресурсах с разделяемым доступом, за которые -соперничают задачи с *одинаковым* приоритетом. - -В примере ниже показано, где можно использовать типы, не реализующие `Sync`. - -``` rust -{{#include ../../../../examples/not-sync.rs}} -``` -- cgit v1.2.3