Миграция с 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 теперь не нужен.

Измените


#![allow(unused)]

fn main() {

#[rtic::app(/* .. */)]

const APP: () = {

[код здесь]

};

}

на


#![allow(unused)]

fn main() {

#[rtic::app(/* .. */)]

mod app {

[код здесь]

}

}

Так как теперь используется обычный модуль Rust, это значит, что можно использовать обычный пользовательский код в этом модуле. Также жто значит, что use-выражения для ресурсов (и т.п.) могут понадобиться.

Перенос диспетчеров из
extern "C"
в аргументы app.

Измените


#![allow(unused)]

fn main() {

#[rtic::app(/* .. */)]

const APP: () = {

[код здесь]


// RTIC требует, чтобы неиспользуемые прерывания были задекларированы в блоке extern, когда

// используются программные задачи; эти свободные прерывания будут использованы для управления

// программными задачами.

extern "C" {

fn SSI0();

fn QEI0();

}

};

}

на


#![allow(unused)]

fn main() {

#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])]

mod app {

[код здесь]

}

}

Это работает и для ОЗУ-функций, см. examples/ramfunc.rs

Init всегда возвращает поздние ресурсы

С целью сделать API более симметричным задача #[init] всегда возвращает поздние ресурсы.

С этого:


#![allow(unused)]

fn main() {

#[rtic::app(device = lm3s6965)]

mod app {

#[init]

fn init(_: init::Context) {

rtic::pend(Interrupt::UART0);

}


// [еще код]

}

}

на это:


#![allow(unused)]

fn main() {

#[rtic::app(device = lm3s6965)]

mod app {

#[init]

fn init(_: init::Context) -> init::LateResources {

rtic::pend(Interrupt::UART0);


init::LateResources {}

}


// [еще код]

}

}

Структура Resources -
#[resources]

Ранее ресурсы RTIC должны были располагаться в структуре с именем "Resources":


#![allow(unused)]

fn main() {

struct Resources {

// Ресурсы определены здесь

}

}

В RTIC v0.6.0 структура ресурсов аннотируется также, как и #[task], #[init], #[idle]: атрибутом #[resources]


#![allow(unused)]

fn main() {

#[resources]

struct Resources {

// Ресурсы определены здесь

}

}

На самом деле, имя структуры предоставлено на усмотрение разработчика:


#![allow(unused)]

fn main() {

#[resources]

struct Whateveryouwant {

// Ресурсы определены здесь

}

}

будет работать так же хороршо.

Вызов/планирование откуда угодно

С этой новой возвожностью, старый код, такой как:


#![allow(unused)]

fn main() {

#[task(spawn = [bar])]

fn foo(cx: foo::Context) {

cx.spawn.bar().unwrap();

}


#[task(schedule = [bar])]

fn bar(cx: bar::Context) {

cx.schedule.foo(/* ... */).unwrap();

}

}

Теперь будет выглядеть так:


#![allow(unused)]

fn main() {

#[task]

fn foo(_c: foo::Context) {

bar::spawn().unwrap();

}


#[task]

fn bar(_c: bar::Context) {

foo::schedule(/* ... */).unwrap();

}

}

Заметьте, что атрибуты spawn и schedule больше не нужны.

Симметричные блокировки

Теперь RTIC использует симметричные блокировки, это значит, что метод lock нужно использовать для всех доступов к ресурсам. Поскольку высокоприоритетные задачи имеют эксклюзивный доступ к ресурсу, в старом коде можно было следующее:


#![allow(unused)]

fn main() {

#[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 для обоих задач:


#![allow(unused)]

fn main() {

#[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.

Загрузка...