Урок 18. Система прерываний STM32. Организация и управление прерываниями.

Уроки STM32

В уроке изучим систему прерываний микроконтроллеров STM32. Разберемся, как управлять ей, как организовывать обработку аппаратных прерываний.

Предыдущий урок     Список уроков     Следующий урок

Не получается рассказывать дальше про таймеры STM32 без знаний о том, как организовывать и использовать прерывания. Поэтому я на один урок прерву представление информации о работе с таймерами и расскажу об организации прерываний в системе STM32.

 

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

 

Аппаратные прерывания и события.

Аппаратное прерывание это сигнал, сообщающий о каком-то событии. По его приходу выполнение программы приостанавливается, и управление переходит на функцию обработки прерывания (обработчик прерывания). После отработки функции управление возвращается в прерванный код программы.

С точки зрения программы прерывание это вызов функции по внешнему, не связанному напрямую с программным кодом, событию.

При определении понятия “прерывание” я употребил слово “событие” в общепринятом значении. Т.е. происшествие, нечто случившееся. Но в системе STM32 наряду с прерыванием (interrupt) существует еще одно строгое понятие – аппаратное событие (event).

Событие – это нечто происшедшее с аппаратным узлом микроконтроллера. Например, переполнился таймер, в порт UART пришло данное, на внешнем входе изменился уровень сигнала и т.п.

Аппаратное событие – это то, что вызывает прерывание. Вернее может вызвать прерывание.

  • Без события прерывание невозможно. Именно аппаратное событие инициирует прерывание.
  • События без прерываний могут происходить.

И дело не только в том, что прерывания можно запретить и игнорировать события. В системе STM32 возможно использование событий для управления периферийными устройствами микроконтроллера. Например, прием байта портом UART вызывает событие, которое в свою очередь запускает контроллер прямого доступа к памяти (DMA) для пересылки этого байта в память. Получается, что происходит обработка события без прерывания программы.

 

Контроллер прерываний STM32.

Обработка и управление прерываниями производятся аппаратным узлом микроконтроллера – контроллером приоритетных векторных прерываний (NVIC). При возникновении разрешенного события контроллер прерывает выполнение программы, сохраняет в стеке необходимые данные и передает управление по адресу функции обработки прерывания. После выхода из функции-обработчика управление возвращается на адрес, по которому была прервана основная программа.

С точки зрения программного управления контроллер прерывания не особо сложное устройство. Я бы выделил следующее.

  • Контроллер приоритетный. Т.е. обработка прерывания может быть прервана другим прерыванием с более высоким приоритетом. Прерывания с таким же или более низким приоритетом будут ожидать окончания обработки активного прерывания. Приоритеты можно разбивать на группы и подгруппы.
  • Как следствие предыдущего пункта для каждого прерывания может быть задан приоритет. Это число от 0 до 15. 0 - самый высокий приоритет. Для установки приоритетов существует специальный блок регистров. На каждое прерывание в нем отведен один байт.
  • Могут быть запрещены сразу все прерывания – глобальный запрет.
  • Могут быть запрещены или разрешены отдельные прерывания. Для этого существует регистр разрешения или маски прерываний. Его отдельные биты определяют разрешение для каждого прерывания.
  • Существует блок регистров ожидания обработки прерываний, каждый бит которых соответствует конкретному прерыванию и показывает, ожидает ли оно обработки. Биты регистров могут быть установлены, для принудительного перевода прерываний в состояние ожидания или сброшены для удаления.
  • Есть регистры действующих прерываний, которые показывают, находятся ли прерывания в стадии обработки.
  • Любое прерывание может быть вызвано программно. Для этого существует регистр программного вызова прерываний. Прерывание вызывается записью в него соответствующего номера.
  • Каждому из прерываний соответствует свой фиксированный адрес-вектор, по которому передается управление для обработки прерывания.

Формально обработкой и управлением прерываниями занимается контроллер прерываний. Но для возникновения прерывания необходимо выполнение нескольких условий связанных как с контроллером прерываний, так и с периферийными устройствами микроконтроллера. Поэтому будем рассматривать задачу в комплексе.

 

Программное управление прерываниями STM32.

Для работы с аппаратными прерываниями необходимо:

  • Разрешить нужное прерывание в контроллере прерываний. Если необходимо, то задать для него приоритет.
  • Разрешить глобальные прерывания микроконтроллера.
  • Настроить устройство, в нашем случае таймер, на формирование запроса прерывания – события.
  • Создать функцию обработки прерывания.

 

Разрешение и запрет прерываний.

Для этого существуют функции библиотеки CMSIS.

void NVIC_EnableIRQ(IRQn_Type IRQn) – разрешение прерывания с номером IRQn.

void NVIC_DisableIRQ(IRQn_Type IRQn) – запрет прерывания с номером IRQn.

В файле stm32f103xb.h есть символьные имена, соответствующие номерам прерываний. Они описаны в структуре IRQn_Type. Я ее значительно сократил.

typedef enum {
. . . . . . . . . . . . . . . . . . . . . . . .
TIM1_BRK_IRQn               = 24,     /*!< TIM1 Break Interrupt */
TIM1_UP_IRQn                = 25,     /*!< TIM1 Update Interrupt */
TIM1_TRG_COM_IRQn           = 26,     /*!< TIM1 Trigger and Commutation Interrupt */
TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt */
TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt */
TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt */
TIM4_IRQn                   = 30,     /*!< TIM4 global Interrupt */
} IRQn_Type;

Команда разрешения прерывания перезагрузки таймера TIM1 будет выглядеть так.

NVIC_EnableIRQ(TIM1_UP_IRQn);

 

Установка приоритетов прерываний.

По состоянию сброса для всех прерываний устанавливается самый высокий приоритет (0). Для его изменения существует функция библиотеки CMSIS.

void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)

  • IRQn – номер прерывания , можно в символьном виде типа IRQn_Type;
  • priority – приоритет (0 … 15), 0 – наивысший.

Например, если мы хотим для таймера TIM1 установить самый низкий приоритет, то необходимо выполнить команду.

NVIC_SetPriority(TIM1_UP_IRQn, 15);

 

Глобальные разрешение и запрет прерываний.

В программе бывают отрезки, которые недопустимо прерывать по самым разным соображениям. А аппаратные прерывания совершенно непредсказуемы. В этом случае можно запретить все прерывания, используя функцию глобального  запрета.

__disable_irq (); // запретить прерывания

По окончанию непрерываемого блока надо разрешить прерывания специальной функцией.

__enable_irq ();  // разрешить прерывания

 

Настройка устройства на формирование события и прерывания.

Это действие касается настройки конкретного периферийного устройства и индивидуально для каждого из них. Будем рассматривать для каждого устройства отдельно. В следующем уроке настроим таймер.

 

Функции обработки прерываний STM32.

В предыдущих уроках мы уже использовали функцию обработки прерывания таймера. Она была создана конфигуратором STM32CubeMX. Сейчас разберемся, откуда она появилась.

В микроконтроллерах STM32 поддерживается до 68 аппаратных прерываний. Каждому из них соответствует свой адрес – вектор. По этому адресу передается управление программы при возникновении прерывания.

Конкретные адреса для каждого источника можно посмотреть в документации на микроконтроллер. Выглядит это примерно так.

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

Из таблицы видно, что наш таймер TIM1 при перезагрузке формирует прерывания по адресу 00A4.

В файле startup\startup_stm32f103xb.s таблица векторов преобразуется в символьные имена функций обработки прерываний.

.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word TIM4_IRQHandler

Для нашего таймера это TIM1_UP_IRQHandler.

Необходимо создать функцию с таким именем и разместить в ее теле обработчик прерывания.

void TIM1_UP_IRQHandler(void) {

    // код обработки прерывания

    // код или функция завершения прерывания

}

В начале файла c/cpp или h надо объявить функцию, разместить прототип.

void TIM1_UP_IRQHandler(void);

При выходе из функции, еще необходимо выполнить определенные действия для завершения прерывания. Как правило, это сброс флага прерывания.

Иначе может произойти следующее. Устройство сформировало событие. Как следствие стал активным флаг прерывания. Произошло, и было обработано прерывание. Программа вернулась к месту, на котором была прервана. А флаг прерывания остался активным. Произойдет новое прерывание, вызванное ошибкой алгоритма. Перед возвратом надо сбросить флаг. Об этом подробно в следующем уроке.

Думаю, что информации этого урока достаточно, чтобы в полной мере использовать прерывания STM32.

 

В следующем уроке будем настраивать таймеры.

Предыдущий урок     Список уроков     Следующий урок

0

Автор публикации

не в сети 7 дней

Эдуард

56
Комментарии: 1319Публикации: 148Регистрация: 13-12-2015

3 комментария на «Урок 18. Система прерываний STM32. Организация и управление прерываниями.»

  1. Здравствуйте!
    Глобальный запрет прерываний действует на следующие прерывания?
    Non maskable interrupt; Hard fault interrupt; Memory management;
    Prefetch fault, memory access fault; Undefined instruction or illegal state; System service call via SWI instruction; Debug monitor; Pendable request for system service; Time base: System tick timer

    0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *