#[task(binds = UART0, shared = [&key])]
fn uart0(cx: uart0::Context) {
let key: &u32 = cx.shared.key;
hprintln!("UART0(key = {:#x})", key).unwrap();
debug::exit(debug::EXIT_SUCCESS);
}
#[task(binds = UART1, priority = 2, shared = [&key])]
fn uart1(cx: uart1::Context) {
hprintln!("UART1(key = {:#x})", cx.shared.key).unwrap();
}
}
}
$ cargo run --example only-shared-access
UART1(key = 0xdeadbeef)
UART0(key = 0xdeadbeef)
Есть две других возможности доступа к ресурсам
• #[lock_free]: могут быть несколько задач с одинаковым приоритетом, получающие доступ к ресурсу без критических секций. Так как задачи с одинаковым приоритетом никогда не могут вытеснить друг друга, это безопасно.
• #[task_local]: в этом случае должна быть только одна задача, использующая этот ресурс, так же как локальный static mut ресурс задачи, но (опционально) устанавливаемая с в init.
В дополнение к аппаратным задачам, вызываемым в ответ на аппаратные события, RTIC также поддерживает
Программным задачам можно также назначать приоритет и, под капотом, они диспетчеризуются обработчиками прерываний. RTIC требует, чтобы свободные прерывания, были указаны в аргументе dispatchers модуля app, если используются программные задачи; часть из этих свободных прерываний будут использованы для управления программными задачами. Преимущество программных задач над аппаратными в том, что множество задач можно назначить на один обработчик прерывания.
Программные задачи также определяются атрибутом task, но аргумент binds опускается.
Пример ниже демонстрирует три программные задачи, запускаемых 2-х разных приоритетах. Три программные задачи привязаны к 2-м обработчикам прерываний.
#![allow(unused)]
fn main() {
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use panic_semihosting as _;
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
mod app {
use cortex_m_semihosting::{debug, hprintln};
#[shared]
struct Shared {}
#[local]
struct Local {}
#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
foo::spawn().unwrap();
(Shared {}, Local {}, init::Monotonics())
}
#[task]
fn foo(_: foo::Context) {
hprintln!("foo - start").unwrap();
bar::spawn().unwrap();
hprintln!("foo - middle").unwrap();
baz::spawn().unwrap();
hprintln!("foo - end").unwrap();
}
#[task]
fn bar(_: bar::Context) {
hprintln!("bar").unwrap();
debug::exit(debug::EXIT_SUCCESS);
}
#[task(priority = 2)]
fn baz(_: baz::Context) {
hprintln!("baz").unwrap();
}
}
}
$ cargo run --example task
foo - start
foo - middle
baz
foo - end
bar
Другое преимущество программной задачи в том, что задачам можно передать сообщения в момент их запуска. Тип передаваемого сообщения должен быть определен в сигнатуре задачи-обработчика.
Пример ниже демонстрирует три задачи, две из которых ожидают сообщение.
#![allow(unused)]
fn main() {
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use panic_semihosting as _;