Прерывания STM32.
У STM32 прерываниями управляет контроллер прерываний NVIC — Nested vectored interrupt controller.
Давайте рассмотрим его возможности:
Сразу хотелось бы обратить внимание на то, что в основе любого прерывания лежит событие, принял байт по uart — событие, переполнился таймер— событие. При возникновении события и установленных флагах, разрешающих прерывание, программа прыгнет в обработчик прерывания.
Для настройки NVIC, в CMSIS предназначены массивы, состоящие из 3 элементов.
Рассмотрим как включить/выключить в NVIC прерывание от usart1, его номер 37, в таблице векторов прерываний RM0008.
Откуда взялась цифра 5? Шестое прерывание из-за того, что счёт начинается с нуля будет иметь номер 5. Так как в нулевом элементе массива расположены прерывания с номерами от 0 до 31, шестое прерывание из первого элемента массива будет иметь номер 37, 6 + 31 = 37.
Но для того, чтобы программа перешла в обработчик прерывания этого недостаточно, у STM32 надо разрешить его в 3-х местах:
Глобальное управление прерываниями , производится с помощью следующих команд:
Разрешить прерывание по завершению передачи и приему кадра по usart1, можно следующим образом:
Название обработчиков прерываний можно найти в файле startup_stm32f10x_hd.s
Следует отметить, что по завершении передачи и приёму нового кадра по uart1 возникает одно и то же прерывание и для того, чтобы определить какое событие вызвало это прерывание, нужно воспользоваться флагами. Если прерывание произошло по приёму выставиться флаг USART_SR_RXNE, по завершении передачи — USART_SR_TC, кстати, флаги надо сбрасывать вручную.
Каждому прерыванию, при сброшенных битах AIRCR[10:8], может быть назначен приоритет от 0 до 15, после сброса все прерывания имеют высший приоритет — 0.
Обслуживаются они по следующим правилам:
Для задания приоритетов выделены старшие 4 бита в регистрах IPRx[7:4], в CMSIS они представлены массивом IP[x].
Для создания групп приоритетов необходимо установить биты в регистре AIRCR[10:8] согласно таблице.
x - определяет количество групп приоритетов, y - количество подгрупп приоритетов.
То есть если мы хотим задать 16 групп приоритетов надо записать в AIRCR[10:8] число 3, а записанное число в регистр IPRx[7:4] будет определять группу, если хотим 8 групп и 2 подгруппы надо записать в AIRCR[10:8] число 4, тогда старшие 3 бита регистра IPRx[7:4] будут определять группу, а младший бит старшей тетрады — подгруппу и так далее.
Но если разрешать/запрешать прерывания, выставлять приоритет, удобно, выставляя соответствующие биты, то для создания групп приоритетов удобнее пользоваться функциями CMSIS, хотя кому-то может быть удобно всегда использовать функции CMSIS.
Давайте рассмотрим его возможности:
- обслуживание до 81 прерывания, в зависимости от модели МК
- программируемый уровень приоритета от 0 до 15 для каждого прерывания, самым приоритетным считается прерывание с уровнем 0
- динамическое изменение приоритета
- разделение прерываний на группы, а внутри группы на подгруппы с разным уровнем приоритета
Сразу хотелось бы обратить внимание на то, что в основе любого прерывания лежит событие, принял байт по uart — событие, переполнился таймер— событие. При возникновении события и установленных флагах, разрешающих прерывание, программа прыгнет в обработчик прерывания.
Для настройки NVIC, в CMSIS предназначены массивы, состоящие из 3 элементов.
Рассмотрим как включить/выключить в NVIC прерывание от usart1, его номер 37, в таблице векторов прерываний RM0008.
//разрешить прерывание от usart1
NVIC->ISER[1] = NVIC_ISER_SETENA_5;
//запретить прерывания от uart1
NVIC->ICER[1] = NVIC_ICER_CLRENA_5;
Откуда взялась цифра 5? Шестое прерывание из-за того, что счёт начинается с нуля будет иметь номер 5. Так как в нулевом элементе массива расположены прерывания с номерами от 0 до 31, шестое прерывание из первого элемента массива будет иметь номер 37, 6 + 31 = 37.
Но для того, чтобы программа перешла в обработчик прерывания этого недостаточно, у STM32 надо разрешить его в 3-х местах:
- разрешить прерывания глобально
- разрешить прерывание в NVIC
- разрешить прерывание непосредственно в самой периферии
Глобальное управление прерываниями , производится с помощью следующих команд:
// Запретить прерывания IRQ
__disable_irq ();
// Разрешить прерывания IRQ
__enable_irq ();
Разрешить прерывание по завершению передачи и приему кадра по usart1, можно следующим образом:
USART1->CR1 |=USART_CR1_TCIE | USART_CR1_RXNEIE;
Название обработчиков прерываний можно найти в файле startup_stm32f10x_hd.s
Следует отметить, что по завершении передачи и приёму нового кадра по uart1 возникает одно и то же прерывание и для того, чтобы определить какое событие вызвало это прерывание, нужно воспользоваться флагами. Если прерывание произошло по приёму выставиться флаг USART_SR_RXNE, по завершении передачи — USART_SR_TC, кстати, флаги надо сбрасывать вручную.
void USART1_IRQHandler(void)
{
//прерывание произошло по приёму
if (USART1->SR & USART_SR_RXNE)
{
Код....
// Сбрасываем флаг прерывания
USART1->SR &= ~USART_SR_RXNE;
}
//прерывание произошло по завершении передачи
if (USART1->SR & USART_SR_TC)
{
Код....
// Сбрасываем флаг прерывания
USART1->SR &= ~USART_SR_TC;
}
}
Каждому прерыванию, при сброшенных битах AIRCR[10:8], может быть назначен приоритет от 0 до 15, после сброса все прерывания имеют высший приоритет — 0.
Обслуживаются они по следующим правилам:
- текущее прерывание может быть прервано более приоритетным
- в случае одновременного возникновения 2-х прерываний выполнится, то чей номер в таблице меньше.
Для задания приоритетов выделены старшие 4 бита в регистрах IPRx[7:4], в CMSIS они представлены массивом IP[x].
//мы хотим установить usart1 приоритет равный 5, но в Keil он будет равен 80
//так как он учитывает значения четырёх младших битов
NVIC->IP[37] = 0x50;
Для создания групп приоритетов необходимо установить биты в регистре AIRCR[10:8] согласно таблице.
x - определяет количество групп приоритетов, y - количество подгрупп приоритетов.
То есть если мы хотим задать 16 групп приоритетов надо записать в AIRCR[10:8] число 3, а записанное число в регистр IPRx[7:4] будет определять группу, если хотим 8 групп и 2 подгруппы надо записать в AIRCR[10:8] число 4, тогда старшие 3 бита регистра IPRx[7:4] будут определять группу, а младший бит старшей тетрады — подгруппу и так далее.
Но если разрешать/запрешать прерывания, выставлять приоритет, удобно, выставляя соответствующие биты, то для создания групп приоритетов удобнее пользоваться функциями CMSIS, хотя кому-то может быть удобно всегда использовать функции CMSIS.
void NVIC_SetPriorityGrouping(uint32_t priority_grouping) // Задать группы/подгруппы приоритетов
void NVIC_EnableIRQ(IRQn_t IRQn) // Включить IRQn
void NVIC_DisableIRQ(IRQn_t IRQn) // Выключить IRQn
uint32_t NVIC_GetPendingIRQ (IRQn_t IRQn) // Вернуть номер IRQn если оно в ожидании
void NVIC_SetPendingIRQ (IRQn_t IRQn) // Поставить IRQn в ожидание
void NVIC_ClearPendingIRQ (IRQn_tIRQn) // Убрать IRQn из очереди ожидания
uint32_t NVIC_GetActive (IRQn_t IRQn) // Возвращает номер текущего активного прерывания
void NVIC_SetPriority (IRQn_t IRQn, uint32_t priority) // Задать приоритет IRQn
uint32_t NVIC_GetPriority (IRQn_t IRQn) // Считать приоритет IRQn
void NVIC_SystemReset (void) //Сброс
- приоритет группы определяет может ли одно прерывание перебивать другое, то есть группа с приоритетом 1 легко перебьет любое прерывание из группы с приоритетом 5
- номер подгруппы определяет какое прерывание выполнится первым, в случае одновременного возникновения двух прерываний из одной группы, также надо сказать, что прерывания из одной группы не могут перебивать друг друга
- в случае одновременного возникновения двух прерываний из одной группы с одинаковыми подгруппами, первым выполнится прерывание с меньшим номером
Похожие статьи