Описывается он подробно в Cortex-M4 Programming Manual.
читать дальшеОн управляет прерываниями от всей периферии и может их сортировать в порядке важности, если сработало сразу несколько. То есть, система прерываний тут многоуровневая. Каждому прерыванию можно назначить свой приоритет. И, кроме того, прерывания могут быть вложенными. Прерывания с более высоким приоритетом могут вытеснить менее приоритетные прерывания.
Есть ряд групп регистров:
NVIC_ISER0-NVIC_ISER7 — маска для разрешения прерываний;
NVIC_ICER0-NVIC_ICER7 — маска для запрещения прерываний;
NVIC_ISPR0-NVIC_ISPR7 — маска для активации
NVIC_ICPR0-NVIC_ICPR7 — маска сброса активного прерывания;
NVIC_IABR0-NVIC_IABR7 — флаги активных прерываний;
Плюс отдельно целая пачка регистров, где настраиваются приоритеты: NVIC_IPR0-NVIC_IPR59
И один регистр для программной активации любого прерывания по его номеру: NVIC_STIR.
Маски все устроены одинаково: каждая содержит по 32 флага, к каждому приписано какое-то прерывание. Конкретное распределение по периферии всегда на совести производителя контроллера и даётся в соответствующей литературе по нему.
В нулевом регистре содержатся флаги прерываний под номерами 0-31, в первом 32-63, и т.д.
То есть младшая часть номера определяется положением бита, старшая — номером регистра.
Рассчитать положение флага в регистре и номер регистра можно по следующим формулам:
Таблица прерываний заранее определена в файле startup_stm32f4xx.s. Там все прерывания по умолчанию указывают на бесконечный цикл.
Если создать в своём модуле экспортируемую функцию с таким же названием, то именно на неё будет указывать адрес в этой таблице прерываний.
У нас же есть таймер и единственное его прерывание (совмещённое с прерыванием от ЦАП) TIM6_DAC_IRQHandler.
В прерывании можно делать всё, что захотим. Это привелегированный режим. Главное, не забыть снять флаг, который вызвал это прерывание (у нас это UIF из регистра TIM6->SR), иначе в нём можно застрять навсегда.
Как и во всех прерываниях, контроллер предусмотрительно сохранил в стеке перед входом в прерывание регистры R0-R3, R12, LR, PC и xPSR. Потому, если это возможно, лучше использовать только их. Остальные регистры надо сохранять уже самостоятельно.
Для прерываний можно иметь отдельный стек, если основной код выполняется в пользовательском режиме.
Возвращение из прерывания происходит так же, как и из функции, то есть записью содержимого LR в PC. Правда, там лежит не адрес, а специальный код возврата, лучше который не трогать и не менять.
Чтобы в прерывание, после того, как мы его создали, попасть, надо его разрешить и в периферии (чтобы она посылала запрос в NVIC), и в самом NVIC, чтобы он это дело разруливал.
Собственно, для этого достаточно записать единичку в нужный регистр ISER. Я не стал рассчитывать вручную, а написал функцию NVIC_EnableIRQ (описана в Programming Manual, пример см. в nvic.s), которая это делает сама.
Номер прерывания я вытащил из файла stm32f4xx.h: 54. Хотя, конечно, он есть и в документации.
Итоговый вид обработчика прерывания:
Здесь он просто увеличивает значение переменной. Примерно так же обрабатываются и остальные прерывания.
И да, если не хотите, чтоб прерывание кем-то ещё прерывалось, запрещайте прерывания на время нахождения в нём с помощью CPSIE/CPSID (какое-то масло масляное).
проект
main.s
nvic.s
<< Предыдущее Следующее >>