Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2743
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

Обработка прерываний

185

Нам нужно только добавить соответствующую функцию обратного вызова (например, процедуру HAL_GPIO_EXTI_Callback()) в код нашего приложения.

Что к чему принадлежит

Когда вы начинаете иметь дело с HAL от ST, возникает большая путаница изза его связи с пакетом CMSIS от ARM. Модуль stm32XX_hal_cortex.c четко показывает взаимодействие между HAL от ST и пакетом CMSIS, поскольку он полностью зависит от официального пакета ARM для работы с базовыми функциями ядра Cortex-M. Каждая функция HAL_NVIC_xxx() является оболочкой (или, как говорят, «оберткой») соответствующей функции CMSIS NVIC_xxx(). Это означает, что мы можем использовать API-интерфейс CMSIS для программирования контроллера NVIC. Однако, поскольку данная книга о CubeHAL, мы будем использовать API-интерфейс от ST для управления прерываниями.

7.3. Жизненный цикл прерываний

Тому, кто имеет дело с прерываниями, очень важно понимать их жизненный цикл. Хотя ядро Cortex-M автоматически выполняет за нас большую часть работы, мы должны обратить внимание на некоторые аспекты, которые могут стать источником путаницы при управлении прерываниями. Однако в данном параграфе рассматривается жизненный цикл прерываний с «точки зрения HAL». Если вы заинтересованы в более глубоком рассмотрении данного вопроса, серия книг Джозефа Ю7 является опять же лучшим источником.

Прерывание может быть:

1. либо запрещено (поведение по умолчанию) или разрешено;

мы разрешаем/запрещаем его, вызывая функцию HAL_NVIC_EnableIRQ()/

HAL_NVIC_DisableIRQ();

2.либо отложено (запрос ожидает обработки) или не отложено;

3.либо в активном (обслуживаемом) или неактивном состоянии.

Мы уже видели первый случай в предыдущем параграфе. Теперь важно изучить, что происходит при срабатывании прерывания.

Когда срабатывает прерывание, оно помечается как отложенное (pending), пока процессор не сможет его обслужить. Если никакие другие прерывания в настоящее время не обрабатываются, его отложенное состояние автоматически сбрасывается процессором, который почти сразу начинает обслуживать его.

На рисунке 7 показано, как это работает. Прерывание A срабатывает в момент времени t0, и, поскольку ЦПУ не обслуживает другое прерывание, его бит отложенного состояния (pending bit) сбрасывается, после чего немедленно8 начинается его выполнение (прерывание становится активным). В момент времени t1 срабатывает прерывание B, но здесь мы предполагаем, что оно имеет более низкий приоритет, чем у A. Поэтому оно остается

7http://amzn.to/1P5sZwq

8Здесь важно понимать, что под словом «немедленно» мы не подразумеваем, что выполнение прерывания начинается без задержки. Если другие прерывания не выполняются, ядра Cortex-M3/4/7 начинают обслуживать прерывание за 12 тактовых циклов ЦПУ, тогда как Cortex-M0 делает это за 15 тактовых циклов, а Cortex-M0+ – за 16 тактовых циклов.

Обработка прерываний

186

в отложенном состоянии, пока ISR прерывания A не завершит свои операции. Когда это происходит, бит отложенного состояния автоматически сбрасывается и ISR становится

активной.

Рисунок 7: Соотношение между битом отложенного состояния и активным состоянием прерывания

На рисунке 8 показан еще один важный случай. Здесь у нас срабатывает прерывание A, и процессор может немедленно его обслужить. Прерывание B срабатывает, пока обслуживается A, поэтому оно остается в отложенном состоянии до тех пор, пока A не завершит работу. Когда это происходит, бит отложенного состояния для прерывания B сбрасывается, и оно становится активным. Однако через некоторое время прерывание A запускается снова, и, поскольку оно имеет более высокий приоритет, прерывание B приостанавливается (становится неактивным), и немедленно начинается выполнение A. Когда оно заканчивается, прерывание B снова становится активным, и оно завершает свою работу.

Рисунок 8: Соотношение между активным состоянием и приоритетами прерываний

Контроллер NVIC обеспечивает высокую степень гибкости для программистов. Прерывание может быть вызвано снова во время его выполнения, просто снова устанавливая свой бит отложенного состояния, как показано на рисунке 99. Таким же образом выполнение прерывания можно отменить, сбросив его бит отложенного состояния, пока он находится в отложенном состоянии, как показано на рисунке 10.

Рисунок 9: Как прерывание может быть принудительно сработать снова, установив его бит отложенного состояния

9 Для полноты картины важно указать, что архитектура Cortex-M разработана таким образом, что, если прерывание срабатывает, когда процессор уже обслуживает другое прерывание, оно будет обслуживаться без восстановления предыдущего приложения, выполняющего извлечение из стека (см. Примечание 5 в этой главе по определениям загрузки в стек/извлечения из стека). Данная технология называется «цепочечной» обработкой прерываний (tail chaining), и она позволяет ускорить управление прерываниями и снизить энергопотребление.

Обработка прерываний

187

Рисунок 10: Обслуживание IRQ можно отменить, сбросив его бит отложенного состояния перед его выполнением

Здесь нужно уточнить важный аспект, связанный с тем, как периферийные устройства предупреждают контроллер NVIC о запросе прерывания. Когда происходит прерывание, большинство периферийных устройств STM32 выдают определенный сигнал, подключенный к NVIC, который отображается в периферийной памяти через специальный бит. Этот бит запроса прерывания периферии будет удерживаться на высоком уровне, пока он не будет сброшен вручную кодом приложения. Например, в Примере 1 мы должны были явно сбросить бит отложенного состояния IRQ линии EXTI, используя макрос __HAL_GPIO_EXTI_CLEAR_IT(). Если мы не сбросим этот бит, то будет срабатывать новое прерывание, пока он не будет сброшен.

На рисунке 11 четко показана взаимосвязь между отложенным состоянием IRQ периферии и отложенным состоянием ISR. Сигнальным I/O является внешнее периферийное устройство, управляющее I/O (например, тактильный переключатель, подключенный к выводу). Когда уровень сигнала изменяется, линия прерывания EXTI, подключенная к этому I/O, генерирует IRQ и устанавливается соответствующий бит отложенного состояния. Как следствие, NVIC генерирует прерывание. Когда процессор начинает обслуживать ISR, бит отложенного состояния ISR сбрасывается автоматически, но бит отложенного состояния IRQ периферии будет удерживаться на высоком уровне, пока он не будет сброшен кодом приложения.

Рисунок 11: Соотношение между IRQ периферии и соответствующим прерыванием

Обработка прерываний

188

На рисунке 12 показан другой случай. Здесь мы форсируем выполнение ISR, устанавливая ее бит отложенного состояния. Поскольку на этот раз внешнее периферийное устройство не задействовано, нет необходимости сбрасывать соответствующий бит отложенного состояния IRQ.

Рисунок 12: Когда прерывание принудительно устанавливает его бит отложенного состояния, соответствующий бит отложенного состояния IRQ периферии остается неустановленным

Поскольку наличие бита отложенного состояния IRQ зависит от периферии, всегда целесообразно использовать функции HAL от ST для управления прерываниями, оставляя все базовые подробности для реализации HAL (если мы не хотим иметь полный контроль, но это не цель данной книги). Однако имейте в виду, что во избежание потери важных прерываний хорошей практикой при разработке является сброс бита отложенного состояния IRQ от периферийных устройств сразу после начала обслуживания ISR. Ядро процессора не отслеживает множественные прерывания (оно не ставит в очередь прерывания), поэтому, если мы сбросим бит отложенного состояния периферийного устройства в конце ISR, мы можем потерять важные IRQ, которые срабатывают в середине обслуживания ISR.

Чтобы увидеть, отложено ли прерывание (то есть сработано, но не запущено), мы можем использовать функцию HAL:

uint32_t HAL_NVIC_GetPendingIRQ(IRQn_Type IRQn);

которая возвращает 0, если IRQ не отложено, и 1 в противном случае.

Чтобы программно установить бит отложенного состояния IRQ, мы можем использовать функцию HAL:

void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);

Это приведет к срабатыванию прерывания, так как оно будет сгенерировано аппаратно. Отличительная особенность процессоров Cortex-M в том, что можно программно запускать прерывание внутри процедуры ISR другого прерывания.