diff options
Diffstat (limited to 'book/ru/src/migration')
| -rw-r--r-- | book/ru/src/migration/migration_rtic.md | 48 | ||||
| -rw-r--r-- | book/ru/src/migration/migration_v4.md | 230 | ||||
| -rw-r--r-- | book/ru/src/migration/migration_v5.md | 208 |
3 files changed, 486 insertions, 0 deletions
diff --git a/book/ru/src/migration/migration_rtic.md b/book/ru/src/migration/migration_rtic.md new file mode 100644 index 0000000..28813fe --- /dev/null +++ b/book/ru/src/migration/migration_rtic.md @@ -0,0 +1,48 @@ +# Миграция с RTFM на RTIC + +В этом разделе описано, как обновить приложение, написанное на RTFM v0.5.x на RTIC той же версии. +Это необходимо из-за переименования фреймворка в соответствии с [RFC #33]. + +**Примечание:** Между RTFM v0.5.3 и RTIC v0.5.3 нет разниц в коде, это исключительно изменение имен. + +[RFC #33]: https://github.com/rtic-rs/rfcs/pull/33 + +## `Cargo.toml` + +Во-первых, зависимость `cortex-m-rtfm` должна быть изменена на `cortex-m-rtic`. + +``` toml +[dependencies] +# измените это +cortex-m-rtfm = "0.5.3" + +# на это +cortex-m-rtic = "0.5.3" +``` + +## Изменения в коде + +Единственное изменение в коде, которое нужно сделать - поменять все ссылки на `rtfm`, +чтобы они указывали на `rtic`: + +``` rust +// +// Измените это +// + +#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)] +const APP: () = { + // ... + +}; + +// +// На это +// + +#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)] +const APP: () = { + // ... + +}; +``` diff --git a/book/ru/src/migration/migration_v4.md b/book/ru/src/migration/migration_v4.md new file mode 100644 index 0000000..0ff8039 --- /dev/null +++ b/book/ru/src/migration/migration_v4.md @@ -0,0 +1,230 @@ +# Миграция с v0.4.x на v0.5.0 + +Этот раздел описывает как обновить программы, написанные на RTIC v0.4.x +на версию v0.5.0 фреймворка. + +## `Cargo.toml` + +Во-первых, нужно обновить версию зависимости `cortex-m-rtic` до +`"0.5.0"`. Опцию `timer-queue` нужно удалить. + +``` toml +[dependencies.cortex-m-rtic] +# изменить это +version = "0.4.3" + +# на это +version = "0.5.0" + +# и удалить Cargo feature +features = ["timer-queue"] +# ^^^^^^^^^^^^^ +``` + +## Аргумент `Context` + +Все функции внутри элемента `#[rtic::app]` должны принимать первым аргументом +структуру `Context`. Этот тип `Context` будет содержать переменные, которые были магически +инъецированы в область видимости функции версией v0.4.x фреймворка: +`resources`, `spawn`, `schedule` -- эти переменные станут полями структуры `Context`. +Каждая функция элемента `#[rtic::app]` получит отдельный тип `Context`. + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + // change this + #[task(resources = [x], spawn = [a], schedule = [b])] + fn foo() { + resources.x.lock(|x| /* .. */); + spawn.a(message); + schedule.b(baseline); + } + + // into this + #[task(resources = [x], spawn = [a], schedule = [b])] + fn foo(mut cx: foo::Context) { + // ^^^^^^^^^^^^^^^^^^^^ + + cx.resources.x.lock(|x| /* .. */); + // ^^^ + + cx.spawn.a(message); + // ^^^ + + cx.schedule.b(message, baseline); + // ^^^ + } + + // change this + #[init] + fn init() { + // .. + } + + // into this + #[init] + fn init(cx: init::Context) { + // ^^^^^^^^^^^^^^^^^ + // .. + } + + // .. +}; +``` + +## Ресурсы + +Синтаксис, используемый, для определения ресурсов был изменен с переменных `static mut` +на структуру `Resources`. + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + // измените это + static mut X: u32 = 0; + static mut Y: u32 = (); // поздний ресурс + + // на это + struct Resources { + #[init(0)] // <- начальное значение + X: u32, // ПРИМЕЧАНИЕ: мы предлагаем изменить стиль именования на `snake_case` + + Y: u32, // поздний ресурс + } + + // .. +}; +``` + +## Периферия устройства + +Если ваша программа получала доступ к периферии в `#[init]` через +переменну `device`, вам нужно будет добавить `peripherals = true` в атрибут +`#[rtic::app]`, чтобы и дальше получать доступ к периферии через поле `device` структуры `init::Context`. + +Измените это: + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + #[init] + fn init() { + device.SOME_PERIPHERAL.write(something); + } + + // .. +}; +``` + +На это: + +``` rust +#[rtic::app(/* .. */, peripherals = true)] +// ^^^^^^^^^^^^^^^^^^ +const APP: () = { + #[init] + fn init(cx: init::Context) { + // ^^^^^^^^^^^^^^^^^ + cx.device.SOME_PERIPHERAL.write(something); + // ^^^ + } + + // .. +}; +``` + +## `#[interrupt]` и `#[exception]` + +Атрибуты `#[interrupt]` и `#[exception]` были удалены. Чтобы определять аппаратные задачи в v0.5.x +используте атрибут `#[task]` с аргументом `binds`. + +Измените это: + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + // аппаратные задачи + #[exception] + fn SVCall() { /* .. */ } + + #[interrupt] + fn UART0() { /* .. */ } + + // программные задачи + #[task] + fn foo() { /* .. */ } + + // .. +}; +``` + +На это: + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + #[task(binds = SVCall)] + // ^^^^^^^^^^^^^^ + fn svcall(cx: svcall::Context) { /* .. */ } + // ^^^^^^ мы предлагаем использовать `snake_case` имя здесь + + #[task(binds = UART0)] + // ^^^^^^^^^^^^^ + fn uart0(cx: uart0::Context) { /* .. */ } + + #[task] + fn foo(cx: foo::Context) { /* .. */ } + + // .. +}; +``` + +## `schedule` + +Интерфейс `schedule` больше не требует cargo опции `timer-queue`, которая была удалена. +Чтобы использовать интерфес `schedule`, нужно сначала определить +монотонный тамер, который будет использоваьт среды выполнения, с помощью аргумента `monotonic` +атрибута `#[rtic::app]`. Чтобы продолжить использовать счетчик циклов +(CYCCNT) в качестве монотонного таймера, как было в версии v0.4.x, добавьте +аргумент `monotonic = rtic::cyccnt::CYCCNT` в атрибут `#[rtic::app]`. + +Также были добавлены типы `Duration` и `Instant`, а трейт `U32Ext` был перемещен в модуль `rtic::cyccnt`. +Этот модуль доступен только на устройствах ARMv7-M+. +Удаление `timer-queue` также возвращает периферию `DWT` в структуру периферии ядра, +включить ее в работу можно внутри `init`. + +Измените это: + +``` rust +use rtic::{Duration, Instant, U32Ext}; + +#[rtic::app(/* .. */)] +const APP: () = { + #[task(schedule = [b])] + fn a() { + // .. + } +}; +``` + +На это: + +``` rust +use rtic::cyccnt::{Duration, Instant, U32Ext}; +// ^^^^^^^^ + +#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)] +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +const APP: () = { + #[init] + fn init(cx: init::Context) { + cx.core.DWT.enable_cycle_counter(); + // опционально, настройка запуска DWT без подключенного отладчика + cx.core.DCB.enable_trace(); + } + #[task(schedule = [b])] + fn a(cx: a::Context) { + // .. + } +}; +``` diff --git a/book/ru/src/migration/migration_v5.md b/book/ru/src/migration/migration_v5.md new file mode 100644 index 0000000..04aedc5 --- /dev/null +++ b/book/ru/src/migration/migration_v5.md @@ -0,0 +1,208 @@ +# Миграция с v0.5.x на v0.6.0 + +Этот раздел описывает как обновиться с версии v0.5.x на v0.6.0 фреймворка RTIC. + +## `Cargo.toml` - увеличьте версию + +Измените версию `cortex-m-rtic` на `"0.6.0"`. + +## `mod` вместо `const` + +С поддержкой атрибутов над модулями трюк с `const APP` теперь не нужен. + +Измените + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + [код здесь] +}; +``` + +на + +``` rust +#[rtic::app(/* .. */)] +mod app { + [код здесь] +} +``` + +Так как теперь используется обычный модуль Rust, это значит, что можно использовать +обычный пользовательский код в этом модуле. +Также жто значит, что `use`-выражения для ресурсов (и т.п.) могут понадобиться. + +## Перенос диспетчеров из `extern "C"` в аргументы app. + +Измените + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + [код здесь] + + // RTIC требует, чтобы неиспользуемые прерывания были задекларированы в блоке extern, когда + // используются программные задачи; эти свободные прерывания будут использованы для управления + // программными задачами. + extern "C" { + fn SSI0(); + fn QEI0(); + } +}; +``` + +на + +``` rust +#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])] +mod app { + [код здесь] +} +``` + +Это работает и для ОЗУ-функций, см. examples/ramfunc.rs + + +## Init всегда возвращает поздние ресурсы + +С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы. + +С этого: + +``` rust +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) { + rtic::pend(Interrupt::UART0); + } + + // [еще код] +} +``` + +на это: + +``` rust +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + + init::LateResources {} + } + + // [еще код] +} +``` + +## Структура Resources - `#[resources]` + +Ранее ресурсы RTIC должны были располагаться в структуре с именем "Resources": + +``` rust +struct Resources { + // Ресурсы определены здесь +} +``` + +В RTIC v0.6.0 структура ресурсов аннотируется также, как и +`#[task]`, `#[init]`, `#[idle]`: атрибутом `#[resources]` + +``` rust +#[resources] +struct Resources { + // Ресурсы определены здесь +} +``` + +На самом деле, имя структуры предоставлено на усмотрение разработчика: + +``` rust +#[resources] +struct Whateveryouwant { + // Ресурсы определены здесь +} +``` + +будет работать так же хороршо. + +## Вызов/планирование откуда угодно + +С этой новой возвожностью, старый код, такой как: + + +``` rust +#[task(spawn = [bar])] +fn foo(cx: foo::Context) { + cx.spawn.bar().unwrap(); +} + +#[task(schedule = [bar])] +fn bar(cx: bar::Context) { + cx.schedule.foo(/* ... */).unwrap(); +} +``` + +Теперь будет выглядеть так: + +``` rust +#[task] +fn foo(_c: foo::Context) { + bar::spawn().unwrap(); +} + +#[task] +fn bar(_c: bar::Context) { + foo::schedule(/* ... */).unwrap(); +} +``` + +Заметьте, что атрибуты `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, которые убирают ненужные блокировки. + +--- + +## Дополнительно + +### Внешние задачи + +Как программные, так и аппаратные задачи теперь можно определять вне модуля `mod app`. +Ранее это было возможно только путем реализации обертки, вызывающей реализацию задачи. + +Смотреть примеры `examples/extern_binds.rs` и `examples/extern_spawn.rs`. + |
