Real-Time Interrupt-driven Concurrency — страница 12 из 23

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

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


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

Миграция с v0.4.x на v0.5.0

Этот раздел описывает как обновить программы, написанные на RTIC v0.4.x на версию v0.5.0 фреймворка.

Cargo.toml

Во-первых, нужно обновить версию зависимости cortex-m-rtic до "0.5.0". Опцию timer-queue нужно удалить.

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


#![allow(unused)]

fn main() {

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


#![allow(unused)]

fn main() {

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

Измените это:


#![allow(unused)]

fn main() {

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

const APP: () = {

#[init]

fn init() {