Выбрать главу

Функцию, помеченную атрибутом idle может опционально добавить в модуль. Эта функция используется как специальная задача ожидания и должна иметь сигнатуру fn(idle::Context) - > !.

Если она присутствует, задача idle будет запущена после init. В отличие от init, idle будет запущена с включенными прерываниями и она не может вернуть результат, а значит должна работать вечно.

Если функция idle не определена, среда вполнения устанавливает бит SLEEPONEXIT, а затем отправляет микроконтроллер в сон после запуска init.

Как и в init, static mut переменные будут трансформированы в &'static mut ссылки, безопасные для доступа. Обратите внимание, данная возможность может быть удалена в следующем релизе, см. task_local ресурсы.

Пример ниже показывает, что idle запускается после init.

Примечание: Цикл loop {} в функци ожидания не может быть пустым, так как это сломает микроконтроллер, из-за того, что LLVM компилирует пустые циклы в инструкцию UDF в release mode. Чтобы избежать неопределенного поведения, цикл должен включать "side-effect" путем вставки ассемблерной инструкции (например, WFI) или ключевого слова continue.

#![allow(unused)]

fn main() {

//! examples/idle.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};

#[shared]

struct Shared {}

#[local]

struct Local {}

#[init]

fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {

hprintln!("init").unwrap();

(Shared {}, Local {}, init::Monotonics())

}

#[idle(local = [x: u32 = 0])]

fn idle(cx: idle::Context) -> ! {

// Locals in idle have lifetime 'static

let _x: &'static mut u32 = cx.local.x;

hprintln!("idle").unwrap();

debug::exit(debug::EXIT_SUCCESS);

loop {

cortex_m::asm::nop();

}

}

}

}

$ cargo run --example idle

init

idle

Чтобы объявить обработчик прерывания, фреймворк предоставляет атрибут #[task], который можно применять к функциям. Этот атрибут берет аргумент binds, чье значение - это имя прерывания, которому будет назначен обработчик; функция, декорированная этим атрибутом становится обработчиком прерывания. В фреймворке такие типы задач именуются аппаратными, потому что они начинают выполняться в ответ на аппаратное событие.

Пример ниже демонстрирует использование атрибута #[task], чтобы объявить обработчик прерывания. Как и в случае с #[init] и #[idle] локальные static mut переменные безопасны для использования с аппаратной задачей.

#![allow(unused)]

fn main() {

//! examples/hardware.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 {}

#[init]

fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {

// Pends the UART0 interrupt but its handler won't run until *after*

// `init` returns because interrupts are disabled

rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend

hprintln!("init").unwrap();

(Shared {}, Local {}, init::Monotonics())

}

#[idle]

fn idle(_: idle::Context) -> ! {

// interrupts are enabled again; the `UART0` handler runs at this point

hprintln!("idle").unwrap();

rtic::pend(Interrupt::UART0);

debug::exit(debug::EXIT_SUCCESS);

loop {

cortex_m::asm::nop();

}

}

#[task(binds = UART0, local = [times: u32 = 0])]

fn uart0(cx: uart0::Context) {

// Safe access to local `static mut` variable

*cx.local.times += 1;

hprintln!(

"UART0 called {} time{}",

*cx.local.times,

if *cx.local.times > 1 { "s" } else { "" }

)

.unwrap();

}

}

}

$ cargo run --example hardware

init

UART0 called 1 time

idle

UART0 called 2 times

До сих пор все программы на RTIC, которые мы видели, не отличались от программ, которые можно написать, используя лишь крейт cortex-m-rt. С этого момента мы начинаем представлять возможности, уникальные для RTIC.