Изменить уровень приоритета работающего обработчика прерываний?

Я пытаюсь реализовать следующий псевдокод на контроллере cortex-m3 (в частности, STM32L151)

void SysTick_Handler() {
    do_high_priority_periodic_tasks(); // not to be interrupted
    lower_interrupt_priority();
    do_low_priority_periodic_tasks();  // these may be interrupted
}

Другими словами, запустите первую часть с уровнем приоритета 0, затем каким-то образом понизьте текущий приоритет прерывания до 15, чтобы остальные могли быть прерваны другими аппаратными прерываниями.

Одна идея состоит в том, чтобы двигаться do_low_priority_periodic_tasks(); в отдельный обработчик прерываний, и вызвать этот обработчик через NVIC_SetPendingIRQ() который устанавливает ожидающий бит в NVIC->ISPR[] регистр. Таким образом, другое прерывание будет немедленно следовать SysTick, если нет ничего с приоритетом между 0 и 14 в ожидании.

#define LOWPRIO_IRQn 55
void IRQ55_Handler() {
    do_low_priority_periodic_tasks();  // these may be interrupted
}

void SysTick_Handler() {
    do_high_priority_periodic_tasks(); // not to be interrupted
    NVIC_SetPendingIRQ(LOWPRIO_IRQ);
}

void main() {
    HAL_Init();
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
    HAL_NVIC_SetPriority(LOWPRIO_IRQn, 15, 0);
    HAL_NVIC_EnableIRQ(LOWPRIO_IRQn);
    while(1) {
        /* main loop */
    }
}

Я выбрал IRQ 55, потому что он не занят на моем контроллере, это будет обработчик прерываний AES на STM32L162, но я немного волнуюсь там. Должен ли я выбрать другой IRQ вместо, возможно, неиспользуемого прерывания канала DMA? Безопасно ли использовать прерывания 57-67, которые определены в ядре Cortex-M3, но не в серии STM32L? Есть ли лучший способ сделать это?

1 ответ

Решение

Безопасно ли использовать прерывания 57-67, которые определены в ядре Cortex-M3, но не в серии STM32L?

Нет. Ваша NVIC может на самом деле не реализовывать их.

Но PendSV точно создан для этой задачи:

void SysTick_Handler() {
  do_high_priority_periodic_tasks(); // not to be interrupted
  // Set the PENDSVSET to trigger a PendSV exception
  SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}

void PendSV_Handler() {
    do_low_priority_periodic_tasks();  // these may be interrupted
}

Смотрите также этот ответ о PendSV.

Другие вопросы по тегам