1. Тема дня
Разбираем:
interrupt latency
приоритеты NVIC на STM32
configMAX_SYSCALL_INTERRUPT_PRIORITY
ESP32 interrupt levels
IRAM-safe ISR
ISR-safe FreeRTOS API
deferred interrupt processing
DMA half/full callbacks
измерение времени ISRГлавная мысль: ISR должна быстро зафиксировать аппаратное событие, очистить источник прерывания, передать минимальную информацию задаче и завершиться. Парсинг, фильтрация, recovery, логирование и работа с сетью выполняются не в ISR.
2. Зачем это нужно
EC25 UART
UART/DMA interrupt не должен разбирать +QMTRECV, выполнять strstr(), отправлять MQTT или перезапускать EC25. Правильный поток:
UART/DMA interrupt
→ зафиксировать позицию DMA/ring buffer
→ уведомить modem_task
→ modem_task забирает байты
→ AT parser
→ modem state machineGPIO фаз
GPIO edge:
GPIO edge
→ timestamp + raw level
→ input_task
→ debounce / AC-window / confidence
→ phase_detector
→ phase_eventDMA callbacks
DMA half/full callbacks говорят, что половина буфера готова. Фильтрация ADC, CRC, UART parsing должны быть в task.
3. Теория
Верхняя и нижняя половина
ISR:
read status
clear flag
save minimal data
notify task
exitTask:
parse UART
debounce
filter ADC
CRC
state machine
recovery
logsNVIC priority
На Cortex-M меньшее число означает более высокий приоритет. Priority 0 - самый высокий. configMAX_SYSCALL_INTERRUPT_PRIORITY разделяет ISR:
0..4:
FreeRTOS API нельзя
5..15:
можно ...FromISR()Пример при 4 priority bits:
UART DMA: priority 6 → можно RTOS API
ADC DMA: priority 7 → можно RTOS API
FDCAN: priority 8 → можно RTOS API
точный capture: priority 3 → RTOS API нельзяТолько ...FromISR()
Из ISR нельзя вызывать обычные:
xQueueSend();
xSemaphoreGive();
xTaskNotify();
vTaskDelay();Нужно:
xQueueSendFromISR();
xSemaphoreGiveFromISR();
xTaskNotifyFromISR();
vTaskNotifyGiveFromISR();Если разблокирована более приоритетная задача, нужен portYIELD_FROM_ISR().
ESP32 interrupts
ESP32 имеет interrupt levels и core affinity. Внешнее прерывание выделяется на том core, где вызвана allocation-функция. Выделять interrupt лучше из pinned task. ESP_INTR_FLAG_IRAM требует, чтобы вся цепочка ISR-кода и используемые данные были во внутренней памяти, а не только первая функция с IRAM_ATTR.
4. Типичные ошибки
- Все IRQ имеют priority 0.
- Обычный RTOS API вызывается из ISR.
- Не вызывается portYIELD_FROM_ISR().
- Парсинг EC25 выполняется в UART callback.
- printf или ESP_LOGI в ISR.
- ESP_INTR_FLAG_IRAM поставлен без полной IRAM-safe цепочки.
- Interrupt выделен из migratable ESP32 task.
- Shared ISR не проверяет status.
- Event bit используется как счётчик.
- DMA callback обрабатывает весь буфер.
5. Практическое задание
Создай INTERRUPT_POLICY.md.
# Interrupt policy
## Main rule
ISR acknowledges hardware, records minimal data,
notifies the owner task and exits.
## Forbidden in ISR
- blocking calls
- delays
- printf/full logging
- MQTT/TCP operations
- NVS/Flash writes
- modem recovery
- large CRC/parsing
- mutex waits
- malloc/free unless explicitly proven ISR-safeДобавь таблицу IRQ:
UART EC25 RX/DMA: priority 6, calls RTOS, owner modem_task
GPIO phase: priority 9, owner input_task
ADC DMA: priority 7, owner adc_task
FDCAN RX: priority 8, owner can_task
Timer capture: priority 3, no RTOS API6. Что попробовать дальше
- Измерить latency через debug GPIO.
- Добавить irq stats CLI.
- Проверить STM32 configPRIO_BITS == __NVIC_PRIO_BITS.
- Проверить, что все IRQ с RTOS API имеют priority ниже/равно разрешённой границе.
Задание
Объясните условия примера 0..4 forbidden и 5..15 allowed. Как проверить соответствие для другой конфигурации Cortex-M?
Критерии самопроверки: Отделить logical library priority numbers от shifted register encoding; меньший numerical priority означает большую urgency. Это условный пример, не универсальная IRQ map.
Показать ответ автора
Пример предполагает 4 реализованных priority bits и настроенный library syscall threshold 5. Проверить implemented priority bits, priority grouping, FreeRTOS port и encoded configMAX_SYSCALL_INTERRUPT_PRIORITY; применять фактическую границу платформы, а не копировать пример универсально.
Задание
UART callback разбирает большой response и пишет log. Перепроектируйте путь для ограниченной ISR latency без незаметной потери bytes.
Критерии самопроверки: Ограничить ISR work; выбрать ...FromISR() там, где разрешено, и объяснить yield decision и buffer-lifetime contract.
Показать ответ автора
ISR фиксирует готовую область или position, очищает source и уведомляет owning task через ISR-safe primitive. Task владеет parsing и logging; задать buffer ownership и overflow detection, чтобы задержка обработки наблюдалась.