Чтобы временно заблокировать реакцию на внешние сигналы в Cortex-M, используйте макрос __disable_irq(). Это отключает все аппаратные исключения, кроме NMI и HardFault. Для восстановления работы вызовите __enable_irq(). Эти функции встроены в компилятор GCC и IAR, работают без дополнительных библиотек.
Для избирательной блокировки конкретных линий применяйте регистр NVIC_ICER. Например, отключение таймера TIM2 выполняется так: NVIC_DisableIRQ(TIM2_IRQn). Проверьте номер канала в даташите – для STM32F4xx TIM2 использует позицию 28. Счет начинается с 0.
При работе с DMA и критичными участками кода сначала сохраняйте текущее состояние флага прерываний: uint32_t primask = __get_PRIMASK(). Затем активируйте маску через __set_PRIMASK(1). После завершения операций восстановите контекст: __set_PRIMASK(primask). Это предотвратит конфликты при одновременном доступе к памяти.
Отключение обработки внешних событий в микроконтроллерах STM
Для временной блокировки реакции на внешние сигналы используйте встроенные функции CMSIS: __disable_irq()
и __enable_irq()
. Эти макросы изменяют регистр PRIMASK, полностью останавливая обработку всех асинхронных вызовов, кроме аппаратных исключений.
Если требуется защитить только критический участок кода, примените пару __set_BASEPRI(priority)
и __set_BASEPRI(0)
. Укажите приоритет, выше которого обработчики продолжат работу. Например, __set_BASEPRI(0x40)
отключает все вызовы с уровнем 0x40 и ниже.
В HAL-библиотеке доступны аналогичные инструменты: HAL_NVIC_DisableIRQ(IRQn_Type IRQn)
для выборочной деактивации конкретного вектора. После выполнения защищаемого кода восстановите его через HAL_NVIC_EnableIRQ()
.
Пример для Cortex-M4:
// Отключение всех обработчиков
uint32_t primask = __get_PRIMASK();
__disable_irq();
// Критическая секция
GPIOA->ODR ^= (1 << 5);
// Восстановление состояния
if (!(primask & 1)) {
__enable_irq();
}
Для работы с FreeRTOS применяйте taskENTER_CRITICAL()
и taskEXIT_CRITICAL()
. Эти макросы учитывают состояние системы и глубину вложенности критических секций.
Избегайте длительной блокировки: в режиме с отключенными асинхронными вызовами не вызывайте функции, зависящие от системного таймера (HAL_Delay(), osDelay()).
Временное отключение обработки внешних событий через __disable_irq()
Функция __disable_irq()
блокирует выполнение всех обработчиков, кроме системных исключений (например, NMI и HardFault). Вызов этого макроса изменяет регистр PRIMASK, устанавливая бит 0, что предотвращает запуск кода, связанного с внешними сигналами.
Для восстановления работы обработчиков используйте парный макрос __enable_irq()
. Он сбрасывает PRIMASK, разрешая выполнение отложенных запросов. Не вызывайте __enable_irq()
без предварительного вызова __disable_irq()
– это может привести к неожиданному поведению.
Пример:
__disable_irq();
// Критический участок кода
__enable_irq();
Не оставляйте обработку сигналов отключенной надолго – это увеличивает задержки реакции на высокоприоритетные события. Оптимально ограничить область действия парой вызовов несколькими строками кода.
Для вложенного отключения применяйте __get_PRIMASK()
и ручное управление регистром:
uint32_t primask = __get_PRIMASK();
__disable_irq();
// Операции, требующие изоляции
if (!primask) __enable_irq();
Применение PRIMASK для изоляции критических операций
Для защиты участков кода от внешнего вмешательства активируйте бит PRIMASK перед началом выполнения критической операции. В Cortex-M это делается через встроенные функции:
__asm volatile ("cpsid i"); // Блокировка внешних событий
// Критический участок
__asm volatile ("cpsie i"); // Восстановление обработки
Важные детали:
- Минимизируйте время удержания PRIMASK – не более 20-30 тактов процессора
- Не вызывайте функции внутри защищенного блока, если они могут зависеть от фоновых процессов
- Для вложенной защиты используйте BASEPRI вместо PRIMASK
Конкретный случай – синхронизация доступа к разделяемому ресурсу:
void UpdateSharedData() {
__disable_irq(); // Аналог cpsid i через CMSIS
shared_buffer.index = (shared_buffer.index + 1) % BUFFER_SIZE;
__enable_irq(); // cpsie i
}
При работе с DMA или аппаратными модулями проверяйте флаги готовности до включения PRIMASK, чтобы избежать зависания.