Прерывания
Прерывания отличаются от исключений по многим признакам, но их работа и использование во многом похожи, и обрабатываются они одним и тем же контроллером прерываний. Исключения определяются архитектурой Cortex-M, а прерывания всегда реализуются производителем (и часто даже конкретным чипом) и различаются как по именам, так и по функциональности.
Прерывания дают большую гибкость, которую нужно учитывать при попытке использовать их продвинутым образом. В этой книге мы не будем рассматривать такие случаи, однако полезно помнить следующее:
- У прерываний есть программируемые приоритеты, которые определяют порядок выполнения их обработчиков.
- Прерывания могут вкладываться друг в друга и вытеснять друг друга: выполнение обработчика прерывания может быть прервано другим, более приоритетным прерыванием.
- Обычно причину, вызвавшую прерывание, нужно сбросить, чтобы не допустить бесконечного повторного входа в обработчик прерывания.
Общие шаги инициализации во время выполнения всегда одинаковы:
- Настроить периферию так, чтобы она генерировала запросы прерываний в нужные моменты;
- Задать нужный приоритет обработчика прерывания в контроллере прерываний;
- Разрешить обработчик прерывания в контроллере прерываний.
Подобно исключениям, крейт cortex-m-rt предоставляет атрибут interrupt для объявления обработчиков прерываний. Однако этот атрибут доступен только при включённом feature device. Кроме того, атрибут не предназначен для прямого использования: попытка сделать это приведёт к ошибке компиляции.
Вместо этого используйте повторно экспортированную версию атрибута interrupt, которую предоставляет крейт устройства (обычно сгенерированный с помощью svd2rust). Это гарантирует, что компилятор может проверить, существует ли прерывание на целевом устройстве. Список доступных прерываний и их позиций в таблице векторов прерываний обычно автоматически генерируется из файла SVD с помощью svd2rust.
use lm3s6965::interrupt; // Повторно экспортированный атрибут из крейта устройства
// Обработчик прерывания для прерывания Timer2
#[interrupt]
fn TIMER2A() {
// ..
// Сбросить причину, по которой сгенерирован запрос прерывания
}
Обработчики прерываний выглядят как обычные функции (только без аргументов), аналогично обработчикам исключений. Однако из-за особых соглашений о вызовах другие части прошивки не могут вызывать их напрямую. Тем не менее можно сгенерировать запрос прерывания программно, чтобы передать управление обработчику прерывания.
Как и в случае с обработчиками исключений, внутри обработчиков прерываний можно объявлять static mut-переменные для безопасного хранения состояния.
#[interrupt]
fn TIMER2A() {
static mut COUNT: u32 = 0;
// `COUNT` имеет тип `&mut u32`, и её безопасно использовать
*COUNT += 1;
}
Более подробное описание механизмов, показанных здесь, см. в разделе исключения.