Контроллер прерываний: различия между версиями
Материал из me-robotics wiki
Sh-sergey (обсуждение | вклад) Метка: визуальный редактор отключён |
Sh-sergey (обсуждение | вклад) |
||
Строка 15: | Строка 15: | ||
Пример обработки прерывания: | Пример обработки прерывания: | ||
− | + | <syntaxhighlight lang="c++"> | |
+ | #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++); //При выполнении из ОЗУ работает быстрее таймера | ||
+ | // } | ||
+ | } | ||
+ | </syntaxhighlight> |
Текущая версия на 15:17, 5 апреля 2022
Данная статья рассматривает настройку контроллера прерываний. Ниже даны основные моменты, на которые следует обратить внимание, далее дан пример с обработкой прерывания от 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++); //При выполнении из ОЗУ работает быстрее таймера
// }
}