📌 IRQ

IRQ (Interrupt Request, запрос прерывания) — аппаратный или программный механизм, с помощью которого периферийные устройства, компоненты системы или само ядро могут временно приостанавливать основное выполнение программы (CPU) для немедленной обработки критического события. IRQ — фундаментальная основа реакции в реальном времени: обмен данными, таймеры, I/O, обработка ошибок, синхронизация.


🧠 Как работает

Основная логика

  • Аппаратный сигнал: периферийное устройство (например, UART, Timer, GPIO, Network, DMA) формирует сигнал на одной из линий IRQ.
  • Контроллер прерываний (PIC, APIC, GIC): определяет, какое устройство требует внимания, приоритет IRQ, маскирование и маршрутизацию сигнала к CPU.
  • CPU: при поступлении IRQ приостанавливает основную программу (генерируется Trap), сохраняет контекст, переходит на обработчик (ISR, Interrupt Service Routine), выполняет обслуживание, возвращается к основной задаче.

Классификация IRQ

  • Маскируемые (Maskable): могут быть временно отключены (маскированы), основной поток не реагирует.
  • Немаскируемые (NMI): имеют высший приоритет, не могут быть отключены (обычно — ошибки питания, критические сбои).
  • Программные IRQ (Software Interrupt): генерируются программно (инструкции int, svc, ecall).
  • Векторные IRQ: адрес ISR определяется номером/вектором IRQ.

Типовой поток обработки

  1. Событие на периферии → генерируется IRQ (например, приход байта на UART).
  2. Контроллер IRQ формирует запрос, присваивает приоритет, посылает сигнал на CPU.
  3. CPU прерывает текущий код, сохраняет регистры/PC, переходит на адрес ISR.
  4. ISR обслуживает событие (считывает данные, сбрасывает флаг, очищает IRQ).
  5. Возврат из ISR — восстановление контекста, продолжение основной задачи.

Иллюстрация:

flowchart TB
    Device["Периферия (UART, Timer, ... )"]
    IRQLine["IRQ Line"]
    PIC["Interrupt Controller"]
    CPU["CPU"]
    ISR["Interrupt Service Routine"]
    App["Main Program"]

    Device --> IRQLine
    IRQLine --> PIC
    PIC --> CPU
    CPU --> ISR
    ISR --> CPU
    CPU --> App

⚙️ Где применяется

  • Микроконтроллеры, SoC, CPU: обслуживание периферии (UART, SPI, ADC, Timer, Ethernet, GPIO).

  • ОС и RTOS: планирование, сервис таймеров, контекстное переключение, сетевые стеки, прерывания от устройств.

  • Системы реального времени: жёсткие требования к латентности обработки событий.

  • Встроенные системы, автоматизация, промышленность, IoT: обработка сигналов, аварий, датчиков.

  • Компьютеры и серверы: управление устройствами ввода/вывода, обработка ошибок, watchdog.


✅ Преимущества

  • Мгновенная реакция: минимальное время между событием и обработкой.

  • Освобождение CPU: выполнение основной программы не блокируется ожиданием (polling).

  • Масштабируемость: поддержка сотен/тысяч IRQ с разными приоритетами.

  • Гибкость: программное и аппаратное управление, маскирование, вложенность.

  • Энергосбережение: CPU может находиться в режиме сна до прихода IRQ.


❌ Недостатки

  • Сложность отладки: ошибки в ISR, гонки, неочищенные IRQ приводят к “зависаниям”.

  • Jitter и латентность: возможны задержки при высоких нагрузках, блокировках.

  • Проблемы приоритетов: низкоприоритетные IRQ могут “голодать” (starvation).

  • Оверхед: каждый вход/выход из ISR — сохранение/восстановление контекста, сброс кешей.

  • Зависимость от контроллера: особенности работы PIC, APIC, GIC различаются, влияет на портируемость.


🔗 Связанные технологии

CPU, PIC, APIC, GIC, ISR, Trap, NMI, DMA, Timer, GPIO, UART, SPI, RTOS, MCU, SoC


Резюме

IRQ — ключевой механизм для обслуживания событий и асинхронного обмена в цифровых системах. Он обеспечивает минимальное время реакции, повышает эффективность, критичен для управления периферией, realtime-задач и энергосберегающих сценариев. Однако требует продуманной архитектуры и аккуратной реализации ISR для избежания зависаний и ошибок.


Примеры кода

C (baremetal): обработка IRQ на Cortex-M

volatile int irq_counter = 0;
 
void UART0_IRQHandler(void) {
    // Считываем байт из UART, очищаем флаг прерывания
    char c = UART0->DR;
    irq_counter++;
}
 
int main() {
    NVIC_EnableIRQ(UART0_IRQn);
    while (1) {
        // основной цикл
    }
}

Ассемблер x86: программный вызов и возврат из прерывания

int_handler:
    pusha           ; Сохраняем все регистры
    ; ... обработка прерывания ...
    popa            ; Восстановление регистров
    iret            ; Возврат из IRQ
 
; ... где-то в коде ...
    int 0x21        ; Генерируем программное прерывание

Linux: регистрация обработчика IRQ

#include <linux/interrupt.h>
 
irqreturn_t my_irq_handler(int irq, void *dev_id) {
    // обработка события
    return IRQ_HANDLED;
}
 
static int __init my_driver_init(void) {
    request_irq(IRQ_NUM, my_irq_handler, 0, "my_irq", NULL);
    return 0;
}

Источники: Intel® SDM, ARM Cortex-M TRM, osdev.org, habr.com, Linux kernel docs, FreeRTOS docs, микроконтроллеры STM32/NXP/TI, Wikipedia.