Прерывания STM32.

Прерывания STM32.

У STM32 прерываниями управляет контроллер прерываний NVIC — Nested vectored interrupt controller.

Давайте рассмотрим его возможности:
  • обслуживание до 81 прерывания, в зависимости от модели МК
  • программируемый уровень приоритета от 0 до 15 для каждого прерывания, самым приоритетным считается прерывание с уровнем 0
  • динамическое изменение приоритета
  • разделение прерываний на группы, а внутри группы на подгруппы с разным уровнем приоритета

Сразу хотелось бы обратить внимание на то, что в основе любого прерывания лежит событие, принял байт по uart — событие, переполнился таймер— событие. При возникновении события и установленных флагах, разрешающих прерывание, программа прыгнет в обработчик прерывания.

Для настройки NVIC, в CMSIS предназначены массивы, состоящие из 3 элементов.
Прерывания STM32.


Рассмотрим как включить/выключить в NVIC прерывание от usart1, его номер 37, в таблице векторов прерываний RM0008.
Прерывания STM32.


//разрешить прерывание от 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
Прерывания STM32.

Следует отметить, что по завершении передачи и приёму нового кадра по 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] согласно таблице.
Прерывания STM32.

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
  • номер подгруппы определяет какое прерывание выполнится первым, в случае одновременного возникновения двух прерываний из одной группы, также надо сказать, что прерывания из одной группы не могут перебивать друг друга
  • в случае одновременного возникновения двух прерываний из одной группы с одинаковыми подгруппами, первым выполнится прерывание с меньшим номером
комментарии
0