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

Материал из MIK32 микроконтроллер

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

Важный момент

Контроллер прерываний не является векторным, при возникновении прерывания из любого источника он всегда вызовет один обработчик.

Обратите внимание

Для работы контроллера прерываний требуется следующее:

  • Включить тактирование EPIC на шине APB_M (в блоке Power Manager);
  • Разрешить прерывания по необходимым линиям в блоке EPIC (контроллер прерываний);
  • Разрешить аппаратные прерывания (установить соответствующие регистры состояния в ядре).

В периферийных блоках также требуется разрешить прерывания по определенным событиям.

Пример обработки прерывания:

#include <mcu32_memory_map.h>
#include <pad_config.h>
#include <gpio.h>
#include <power_manager.h>
#include <timer32.h>
#include <epic.h>
#include <csr.h>
#include <scr1_csr_encoding.h>


void trap_handler() {
  if (EPIC->STATUS & (1 << EPIC_TIMER32_0_INDEX)) { //Проверка источника прерывания
    GPIO_1->OUTPUT ^= 1 << 13; //Установка значения выходного регистра
    // TIMER32_0->Enable = TIMER32_RESET_VALUE_M | TIMER32_ENABLE_M;
    TIMER32_0->IntClear = TIMER32_INT_OVERFLOW_M; //Сброс флага прерывания таймера
    EPIC->CLEAR = 1 << EPIC_TIMER32_0_INDEX; //Сброс флага прерывания линии таймера
  }
}

void EnableInterrupts() {   
    set_csr(mstatus, MSTATUS_MIE);
    set_csr(mie, MIE_MEIE);
}

void DisableInterrupts() {    
    clear_csr(mie, MIE_MEIE);
}

int main() {
  DisableInterrupts();

  //Включаем тактирование необходимых блоков
	PM->CLK_APB_P_SET = PM_CLOCK_GPIO_1_M;
	PM->CLK_APB_M_SET = PM_CLOCK_PAD_CONFIG_M | PM_CLOCK_WU_M | PM_CLOCK_PM_M | 
                      PM_CLOCK_TIMER32_0_M | PM_CLOCK_EPIC_M;

	for (volatile int i = 0; i < 10; i++);

  //Настройка вывода (светодиода)
	PAD_CONFIG->PORT_1_CFG = 1 << (13 << 1); //Установка режима 01 (GPIO) вывода 13
	GPIO_1->DIRECTION_OUT = 1 << 13;
  GPIO_1->OUTPUT = 0; //Установка значения выходного регистра

  //Остановка таймера и сброс настроек до стандартных
  TIMER32_0->Enable = TIMER32_RESET_VALUE_M;
  TIMER32_0->IntMask = 0;
  TIMER32_0->IntClear = 0x3FF;
  TIMER32_0->Control = 0;

  //Настройка максимального значения счетчика
  //и включение прерывания на переполнение
  TIMER32_0->Top = 32000000u;
  TIMER32_0->IntMask = TIMER32_INT_OVERFLOW_M;

  //Сброс настроек контроллера прерываний 
  //и включение линии прерываний таймера
  EPIC->MASK_CLEAR = 0xFFFF;
  EPIC->CLEAR = 0xFFFF; //Сброс флагов прерываний
  EPIC->MASK_SET = 1 << EPIC_TIMER32_0_INDEX;

  //Разрешение прерываний и запуск таймера
  EnableInterrupts();
  TIMER32_0->Enable = TIMER32_ENABLE_M;

  for (;;);

	// while (1) {
    //  GPIO_1->OUTPUT = (1 << 13) & ~GPIO_1->OUTPUT; //Цикл зависит от скорости выполнения программы
	// 	for (volatile int i = 0; i < 500000; i++); //При выполнении из ОЗУ работает быстрее таймера
	// }
}