#![allow(unused)]
fn main() {
//! examples/resource.rs
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
use cortex_m_semihosting::{debug, hprintln};
use lm3s6965::Interrupt;
#[shared]
struct Shared {}
#[local]
struct Local {
local_to_uart0: i64,
local_to_uart1: i64,
}
#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
(
Shared {},
// initial values for the `#[local]` resources
Local {
local_to_uart0: 0,
local_to_uart1: 0,
},
init::Monotonics(),
)
}
// `#[local]` resources cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
debug::exit(debug::EXIT_SUCCESS);
// error: no `local` field in `idle::Context`
// _cx.local.local_to_uart0 += 1;
// error: no `local` field in `idle::Context`
// _cx.local.local_to_uart1 += 1;
loop {
cortex_m::asm::nop();
}
}
// `local_to_uart0` can only be accessed from this context
// defaults to priority 1
#[task(binds = UART0, local = [local_to_uart0])]
fn uart0(cx: uart0::Context) {
*cx.local.local_to_uart0 += 1;
let local_to_uart0 = cx.local.local_to_uart0;
// error: no `local_to_uart1` field in `uart0::LocalResources`
// cx.local.local_to_uart1 += 1;
hprintln!("UART0: local_to_uart0 = {}", local_to_uart0).unwrap();
}
// `shared` can only be accessed from this context
// explicitly set to priority 2
#[task(binds = UART1, local = [local_to_uart1], priority = 2)]
fn uart1(cx: uart1::Context) {
*cx.local.local_to_uart1 += 1;
let local_to_uart1 = cx.local.local_to_uart1;
// error: no `local_to_uart0` field in `uart1::LocalResources`
// cx.local.local_to_uart0 += 1;
hprintln!("UART1: local_to_uart1 = {}", local_to_uart1).unwrap();
}
}
}
$ cargo run --example resource
UART1: local_to_uart1 = 1
UART0: local_to_uart0 = 1
Заметьте, что к ресурсу shared нельзя получить доступ из idle. Попытка сделать это приведет к ошибке компиляции.
Критические секции необходимы для разделения изменяемых данных таким образом, чтобы избежать гонок данных.
Поле resources, передаваемого Context реализует трейт Mutex для каждого разделяемого ресурса, доступного задаче.
Единственный метод этого трейта, lock, запускает свой аргумент-замыкание в критической секции.
Критическая секция, создаваемая интерфейсом lock основана на динамических приоритетах: она временно повышает динамический приоритет контекста до максимального приоритета, что не дает другим задачам возможности вытеснить критическую секцию. Этот протокол синхронизации известен как Протокол немедленного максимального приоритета (ICPP), и компилируется диспетчером RTIC с Политикой ресурсов стека(SRP).
В примере ниже у нас есть три обработчика прерываний с приоритетами от одного до трех. Два из обработчиков с более низким приоритетом соревнуются за ресурс shared, поэтому должны блокировать доступа к данным ресурса. Обработчик с наивысшим приоритетом, который не имеет доступа к ресурсу shared, может свободно вытеснять критическую секцию, созданную обработчиком с низким приоритетом.
#![allow(unused)]
fn main() {
//! examples/lock.rs
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
use cortex_m_semihosting::{debug, hprintln};
use lm3s6965::Interrupt;
#[shared]
struct Shared {
shared: u32,
}
#[local]
struct Local {}
#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
rtic::pend(Interrupt::GPIOA);
(Shared { shared: 0 }, Local {}, init::Monotonics())
}
// when omitted priority is assumed to be `1`
#[task(binds = GPIOA, shared = [shared])]
fn gpioa(mut c: gpioa::Context) {