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

Примечание: Между RTFM v0.5.3 и RTIC v0.5.3 нет разниц в коде, это исключительно изменение имен.

Во-первых, зависимость cortex-m-rtfm должна быть изменена на cortex-m-rtic.

[dependencies]

# измените это

cortex-m-rtfm = "0.5.3"

# на это

cortex-m-rtic = "0.5.3"

Единственное изменение в коде, которое нужно сделать - поменять все ссылки на rtfm, чтобы они указывали на rtic:

#![allow(unused)]

fn main() {

//

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

//

#[rtfm::app(/* .. */, monotonic = rtfm::cyccnt::CYCCNT)]

const APP: () = {

// ...

};

//

// На это

//

#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]

const APP: () = {

// ...

};

}

Этот раздел в настоящий момент находится в разработке, он появится снова, когда будет завершен

Этот раздел описывает внутренности фреймворка RTIC на высоком уровне. Низкоуровневые детали, такие как парсинг и генерация кода, выполняемые процедурным макросом (#[app]) объясняться не будут. Внимание будет сосредоточено на анализе спецификации пользователя и структурах данных, используемых на этапе выполнения.

Мы настоятельно рекомендуем вам прочитать раздел о конкуренции в embedonomicon перед тем, как погружаться в материал.

Прерывания - это основа работы программ на RTIC. Правильно настроить приоритеты прерываний и убедиться, что они не изменяются во время выполнения обязательно для безопасной работы программы.

Фреймворк RTIC представляет приоритеты прерываний, как нечто, что должно быть определено на этапе компиляции. Однако, статическая настройка должна быть зашита в соответствующие регистры в процессе инициализации программы. Настройка прерываний происходит до запуска функции init.

Этот пример дает представление о коде, запускаемом фреймворком RTIC:

#![allow(unused)]

fn main() {

#[rtic::app(device = lm3s6965)]

mod app {

#[init]

fn init(c: init::Context) {

// .. пользовательский код ..

}

#[idle]

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

// .. пользовательский код ..

}

#[interrupt(binds = UART0, priority = 2)]

fn foo(c: foo::Context) {

// .. пользовательский код ..

}

}

}

Фреймворк генерирует точку входа в программу, которая выглядит примерно так:

// настоящая точку входа в программу

#[no_mangle]

unsafe fn main() -> ! {

// преобразует логические приоритеты в аппаратные / NVIC приоритеты

fn logical2hw(priority: u8) -> u8 {

use lm3s6965::NVIC_PRIO_BITS;

// NVIC кодирует приоритеты верхними битами

// большие значения обозначают меньший приоритет

((1 << NVIC_PRIORITY_BITS) - priority) << (8 - NVIC_PRIO_BITS)

}

cortex_m::interrupt::disable();

let mut core = cortex_m::Peripheraclass="underline" :steal();

core.NVIC.enable(Interrupt::UART0);

// значение, определенное пользователем

let uart0_prio = 2;

// проверка на этапе компиляции, что определенный приоритет входит в поддерживаемый диапазон

let _ = [(); (1 << NVIC_PRIORITY_BITS) - (uart0_prio as usize)];

core.NVIC.set_priority(Interrupt::UART0, logical2hw(uart0_prio));

// вызов пользовательского кода

init(/* .. */);

// ..

cortex_m::interrupt::enable();

// вызов пользовательского кода

idle(/* .. */)

}

В RTIC задачи-обработчики не могут использоваться повторно. Переиспользование задачи-обработчика может сломать правила заимствования Rust и привести к неопределенному поведению. Задача-обработчик теоретически может быть переиспользована одним из двух способов: программно или аппаратно.