Временно отключить прерывание по таймеру
Я работаю над встроенным проектом в C на stm32f4xx uC.
У меня есть часть кода, которая непрерывно выполняет операцию цикла XYZ, и время от времени прерывание TIM4 изменяет некоторые глобальные параметры и вызывает перезапуск операции XYZ.
код примерно такой:
for (;;) {
//line A
XYZ;
//line B
}
XYZ - сложная операция, включающая передачу данных между буферами и другими.
Обработчик прерываний TIM4 делает это: останавливает XYZ и изменяет некоторые глобальные переменные, которые влияют на операции XYZ.
Поэтому в основном я хочу, чтобы XYZ выполнялся повторно, а прерывание TIM4 останавливало XYZ, изменяло параметры, а затем цикл должен перезапускаться, перезапуская XYZ с новыми глобальными параметрами.
ПРОБЛЕМА IS: Поскольку в XYZ много инструкций, IRQ TIM4 может появиться прямо посередине, и после того, как IRQHandler изменяет глобальные переменные, операции возобновляются с середины XYZ, что разрушает программу.
МОЕ НАЧАЛЬНОЕ РЕШЕНИЕ: Отключите прерывания в строке A с помощью __disable_irq () и восстановите их в строке B с помощью __enable_irq ()
Сбой, потому что сложная операция XYZ должна использовать другие прерывания (кроме TIM4).
СЛЕДУЮЩЕЕ РЕШЕНИЕ Отключите только прерывание TIM4 в строке A с помощью:
TIM_ITConfig(TIM4, TIM_IT_Update , DISABLE)
и включите его обратно в строке B с помощью:
TIM_ITConfig(TIM4, TIM_IT_Update , ENABLE)
Сбой, потому что я теряю прерывание: когда восстанавливается int, прерывание, которое поступило во время XYZ, игнорируется. Это большая проблема (одна из причин заключается в том, что TIM4 IRQHandler изменяет глобальные переменные, а затем снова активирует TIM4, чтобы позже выдать прерывание, я делаю это потому, что период между прерываниями меняется).
Кто-нибудь может дать мне решение этой проблемы? Есть ли лучший способ отключить / восстановить IRQ TIM4 и не терять прерывания?
5 ответов
Есть несколько вариантов, потенциально доступных (я не на 100% по архитектуре ARM):
- Измените регистр приоритета прерываний / маски уровня, чтобы он маскировал только TIM4, оставляя другие прерывания. Будем надеяться, что если TIM4 будет запущен во время маскировки, при восстановлении маски уровня он запомнит и запустит ISR.
- Маскируйте прерывания и вручную проверяйте, установлен ли флаг прерывания TIM4 во время XYZ
- Разбейте XYZ на меньшие секции и замаскируйте TIM4 только тогда, когда это абсолютно необходимо.
- Работайте с копией данных, опционально проверяя флаг прерывания TIM4, чтобы решить, следует ли продолжить / сохранить результат или отменить и перезапустить.
- Проверьте время и избегайте запуска XYZ, если возможно, что TIM4 скоро сработает, или запускайте XYZ N раз после срабатывания TIM4.
Вы можете работать с копией глобальных переменных и менять новое значение из прерывания, как только закончите с XYZ.
Из вопроса не ясно, нужно ли вам немедленно прекратить обработку XYZ, когда глобальные перемены меняются, или вы можете подождать, пока XYZ завершит обработку, чтобы поменять новые копии переменных. Я буду действовать в предположении, что вам нужно прекратить обработку XYZ, но это достаточно просто.
Код будет выглядеть примерно так:
volatile int x;
int x_prime;
int main(void)
{
while(1)
{
//copy in new global parameter value
x_prime = x;
while(1)
{
//do stuff with x_prime
if (x_prime != x)
{
break;
}
//do more stuff with x_prime
if (x_prime != x)
{
break;
}
}
}
}
// interrupt handler
void TIM_IT_Update(void)
{
x++;
}
break
шаблоны предполагают, что вы не меняете x_prime
, Если вам нужно изменить x_prime
Вам понадобится еще одна копия.
Поскольку прерывание никогда не отключается, вам никогда не придется беспокоиться о его потере. И поскольку вы работаете с копией параметров, измененных прерыванием, не имеет значения, изменяет ли прерывание параметры в середине выполнения, потому что вы не смотрите на эти значения, пока не сделаете копии.
Когда я оказываюсь в аналогичной ситуации, когда обработка может занять больше времени, чем период прерывания, я использую FIFO, чтобы отделить обработку от входящих данных. IE: TIM4 заполняет FIFO. XYZ (или менеджер) использует FIFO и обрабатывает данные.
(Я чувствую, что ваш дизайн может быть неправильным, так как вы не должны использовать глобальные переменные для управления данными или потоком процессов. Справочник книги для изучения по данному вопросу: Создание встроенных систем: шаблоны проектирования для отличного программного обеспечения)
Перед XYZ сделайте копию всего из буфера и работайте с копиями. Я считаю, что это лучший способ, который помог во время написания парсера GPS.
Вы рассматривали возможность использования ОСРВ в своей системе? Я понимаю, что это потребует некоторой реструктуризации, но может дать вам гибкость в обработке задач и разрешение, необходимые для вашей системы. Если вы используете CubeIDE STM32, включение, настройка и запуск с RTOS довольно просты.