The app attribute

Это наименьшая возможная программа на RTFM:


# #![allow(unused_variables)]
#fn main() {
//! examples/smallest.rs

#![no_main]
#![no_std]

use panic_semihosting as _; // panic handler
use rtfm::app;

#[app(device = lm3s6965)]
const APP: () = {};

#}

Все программы на RTFM используют атрибут app (#[app(..)]). Этот атрибут нужно применять к const-элементам, содержащим элементы. Атрибут app имеет обязательный аргумент device, в качестве значения которому передается путь. Этот путь должен указывать на библиотеку устройства, сгенерированную с помощью svd2rust v0.14.x. Атрибут app развернется в удобную точку входа, поэтому нет необходимости использовать атрибут cortex_m_rt::entry.

ОТСТУПЛЕНИЕ: Некоторые из вас удивятся, почему мы используем ключевое слово const как модуль, а не правильное mod. Причина в том, что использование атрибутов на модулях требует feature gate, который требует ночную сборку. Чтобы заставить RTFM работать на стабильной сборке, мы используем вместо него слово const. Когда большая часть макросов 1.2 стабилизируются, мы прейдем от const к mod и в конце концов в атрибуту уровне приложения (#![app]).

init

Внутри псевдо-модуля атрибут app ожидает найти функцию инициализации, обозначенную атрибутом init. Эта функция должна иметь сигнатуру [unsafe] fn().

Эта функция инициализации будет первой частью запускаемого приложения. Функция init запустится с отключенными прерываниями и будет иметь эксклюзивный доступ к периферии Cortex-M и специфичной для устройства периферии через переменные core and device, которые внедряются в область видимости init атрибутом app. Не вся периферия Cortex-M доступна в core, потому что рантайм RTFM принимает владение частью из неё -- более подробно см. структуру rtfm::Peripherals.

Переменные static mut, определённые в начале init будут преобразованы в ссылки &'static mut с безопасным доступом.

Пример ниже показывает типы переменных core и device и демонстрирует безопасный доступ к переменной static mut.


# #![allow(unused_variables)]
#fn main() {
//! examples/init.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _;

#[rtfm::app(device = lm3s6965, peripherals = true)]
const APP: () = {
    #[init]
    fn init(cx: init::Context) {
        static mut X: u32 = 0;

        // Cortex-M peripherals
        let _core: cortex_m::Peripherals = cx.core;

        // Device specific peripherals
        let _device: lm3s6965::Peripherals = cx.device;

        // Safe access to local `static mut` variable
        let _x: &'static mut u32 = X;

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

        debug::exit(debug::EXIT_SUCCESS);
    }
};

#}

Запуск примера напечатает init в консоли и завершит процесс QEMU.

$ cargo run --example init
init

idle

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

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

Когда функция idle не определена, рантайм устанавливает бит SLEEPONEXIT, после чего отправляет микроконтроллер в состояние сна после выполнения init.

Как и в init, переменные static mutбудут преобразованы в ссылки &'static mut с безопасным доступом.

В примере ниже показан запуск idle после init.


# #![allow(unused_variables)]
#fn main() {
//! examples/idle.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _;

#[rtfm::app(device = lm3s6965)]
const APP: () = {
    #[init]
    fn init(_: init::Context) {
        hprintln!("init").unwrap();
    }

    #[idle]
    fn idle(_: idle::Context) -> ! {
        static mut X: u32 = 0;

        // Safe access to local `static mut` variable
        let _x: &'static mut u32 = X;

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

        debug::exit(debug::EXIT_SUCCESS);

        loop {}
    }
};

#}
$ cargo run --example idle
init
idle

interrupt / exception

Как Вы бы сделали с помощью библиотеки cortex-m-rt, Вы можете использовать атрибуты interrupt и exception внутри псевдо-модуля app, чтобы определить обработчики прерываний и исключений. В RTFM, мы называем обработчики прерываний и исключений аппаратными задачами.


# #![allow(unused_variables)]
#fn main() {
{{#include ../../../../examples/interrupt.rs}}
#}
$ cargo run --example interrupt
{{#include ../../../../ci/expected/interrupt.run}}```

До сих пор программы RTFM, которые мы видели не отличались от программ, которые
можно написать, используя только библиотеку `cortex-m-rt`. В следующем разделе
мы начнем знакомиться с функционалом, присущим только RTFM.