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 бесполезно: исключение не вытесняет само себя.
Источники
- 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 в состояние ожидания
- 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
- Arm. Cortex-M0 Devices Generic User Guide, DUI 0497A, 2009 — разд. 2.4.1: lockup при отказе в обработчике NMI или HardFault; если lockup случился в обработчике NMI, следующий NMI из него не выводит
Нашли ошибку?
Смотрите также
- Система контроля тактирования (CSS)Обнаружение отказа кварца HSE и переход на HSI
- HardFaultИсключение Cortex-M при необработанной ошибке
- NVIC — контроллер прерыванийКонтроллер прерываний Cortex-M: приоритеты и вытеснение
- Lockup (блокировка ядра Cortex-M)Остановка ядра Cortex-M при отказе на приоритете HardFault или NMI
- Cortex-M3Регистры, карта памяти, bit-banding, NVIC, SysTick, MPU, старт, пример