Перейти к содержанию

NMI (немаскируемое прерывание)

Большинство прерываний Cortex-M можно запретить одной командой. NMI — исключение, которое не выключается ничем и вытесняется только сбросом. Поэтому его оставляют для событий, которые нельзя пропустить, — у STM32 это отказ внешнего кварца.

Обновлено Редакция GAW

NMI (Non-Maskable Interrupt, немаскируемое прерывание) — исключение ядра Cortex-M, которое нельзя запретить. По DUI 0552A его может подать периферия или вызвать программа; это самое приоритетное исключение после сброса с фиксированным приоритетом −2. Ни одно другое исключение не может его замаскировать, а вытесняет обработчик NMI только Reset (разд. 2.3.2). В таблице векторов его адрес — 0x0000 0008, сразу после указателя стека и вектора сброса.

Место среди приоритетов

ИсключениеПриоритетМожно запретить
Reset−3нет
NMI−2нет
HardFault−1только битом FAULTMASK
Остальные0–255, настраиваемыйда

Маски PRIMASK и BASEPRI на NMI не действуют, а FAULTMASK запрещает всё, кроме NMI (DUI 0552A, разд. 2.1.3). Поэтому NMI срабатывает и внутри критической секции, и внутри обработчика HardFault. Подробнее о приоритетах — в статье «NVIC».

NMI в STM32

У STM32 к NMI подключена система контроля тактирования. Если внешний генератор HSE отказал, CSS выключает его, посылает событие на входы аварийного останова таймеров TIM1 и TIM8 и формирует прерывание CSSI, связанное с вектором NMI. Обработчик вызывается бесконечно, пока флаг не сброшен битом CSSC регистра RCC_CIR (RM0090, разд. 6.2.7). Так что NMI_Handler в STM32 обязан сбросить этот флаг, иначе программа в нём застрянет.

Программно NMI вызывают записью 1 в бит NMIPENDSET (бит 31) регистра ICSR по адресу 0xE000ED04 (DUI 0552A, разд. 4.3.3).

Осторожно с отказами в NMI

Обработчик NMI работает на приоритете −2, и отказ внутри него обработать некому: ядро уходит в lockup и перестаёт выполнять команды. Выйти из lockup, случившегося в обработчике NMI, следующий NMI уже не поможет — только сброс или отладчик (DUI 0552A, разд. 2.4.4; DUI 0497A, разд. 2.4.1). Поэтому код в обработчике NMI делают коротким и не трогают в нём сомнительные указатели. Обзор исключений ядра — в статье «Cortex-M3».

Частые вопросы

Чем NMI отличается от обычного прерывания?

Обычное прерывание можно запретить в NVIC, замаскировать битом PRIMASK или порогом BASEPRI, и у него настраиваемый приоритет. NMI всегда разрешён, его не маскирует даже FAULTMASK, а фиксированный приоритет −2 выше любого настраиваемого и выше HardFault. Вытеснить обработчик NMI может только сброс.

Почему STM32 зависает в NMI_Handler?

Чаще всего сработала система контроля тактирования: внешний кварц пропал, CSS переключила ядро на HSI и вызвала NMI. Пока флаг CSSF не сброшен записью бита CSSC в RCC_CIR, NMI вызывается снова и снова, и программа из обработчика не выходит. Обработчик должен сбросить флаг и перенастроить тактирование.

Можно ли вызвать NMI программно?

Да. Запись 1 в бит 31 NMIPENDSET регистра ICSR (адрес 0xE000ED04) переводит NMI в состояние ожидания, и ядро сразу входит в его обработчик. Так иногда проверяют аварийный код, но вызывать NMI из самого обработчика NMI бесполезно: исключение не вытесняет само себя.

Источники

  1. Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — разд. 2.3.2: NMI может подать периферия или вызвать программа; самое приоритетное исключение после сброса, всегда разрешено, фиксированный приоритет −2; его нельзя замаскировать или запретить другим исключением, вытесняет его только Reset; разд. 2.1.3: FAULTMASK запрещает все исключения, кроме NMI; разд. 2.4.4: отказ в обработчике NMI ведёт в lockup, из которого следующий NMI не выводит; разд. 4.3.3, табл. ICSR: бит 31 NMIPENDSET — запись 1 переводит NMI в состояние ожидания
  2. STMicroelectronics. RM0090 Reference manual STM32F405/415, STM32F407/417, STM32F427/437, STM32F429/439 (Rev 21) — разд. 6.2.7: при отказе HSE система CSS выключает генератор, посылает событие на входы аварийного останова TIM1 и TIM8 и формирует прерывание CSSI, связанное с вектором NMI; NMI выполняется бесконечно, пока флаг не сброшен битом CSSC в RCC_CIR; табл. 62: NMI — приоритет −2, адрес вектора 0x0000 0008
  3. Arm. Cortex-M0 Devices Generic User Guide, DUI 0497A, 2009 — разд. 2.4.1: lockup при отказе в обработчике NMI или HardFault; если lockup случился в обработчике NMI, следующий NMI из него не выводит

Нашли ошибку?