STM32 µC: задержка SysTick не работает внутри обработчика прерываний
Поэтому я написал программу для STM32F103C8T6
микроконтроллер на С, использующий RTC (часы реального времени) и дисплейный модуль.
RTC и дисплей работают нормально, но когда я пытаюсь обновить дисплей из обработчика прерываний RTC, он не работает.
Когда я пишу что-то на дисплей изнутри main()
, это работает просто отлично.
Обработчик прерываний также работает, поэтому я решил, что проблема заключается в функции записи на дисплей.
Эта функция использует небольшие задержки для передачи бит-связи с контроллером дисплея.
Я ранее использовал SysTick
чтобы сгенерировать такие задержки:
void delay(uint32_t n){
uint32_t start = systick_count;
while (systick_count - start < n);
return;
}
Но почему-то внутри обработчика прерываний RTC это не работает. Поэтому я заменил свою функцию задержки на эту, не используя SysTick:
for (; i>0; i--) {
for (int j = 0; j < 72; ++j) {
__asm__ __volatile__("nop\n\t":::"memory");
}
}
и теперь все работает просто отлично.
Я пытаюсь понять, почему SysTick
очевидно, не работает внутри обработчика прерываний RTC.
Я подумал, что, возможно, это вызвано приоритетами прерываний, но в соответствии с таблицей, по умолчанию SysTick Interrupt
приоритет выше, чем RTC прерывает приоритет.
Может быть, кто-то может объяснить, почему это происходит?
EDIT1: Итак, я прочитал немного больше о приоритетах прерывания, и мне кажется, что мне нужно правильно настроить NVIC_IRQChannelPreemptionPriority. Я попробую это, как только смогу...
Что касается задержки внутри прерывания, я знаю, что это неправильный способ сделать это, но я все же хотел понять поведение программы
РЕДАКТИРОВАТЬ 2: Я просто попытался изменить приоритеты прерываний следующим образом:
// set RTC interrupt priority to 15 (lowest)
NVIC_SetPriority(RTC_IRQn, 15);
// set interrupt priority of SysTick to 0 (highest)
NVIC_SetPriority(SysTick_IRQn, 0);
и теперь задержка SysTick работает в обработчике прерывания RTC.
1 ответ
Ваш способ реализации задержки с помощью SysTick такой же, как HAL_Delay
в библиотеке HAL из ST. Это работает так, что SysTick постоянно увеличивает (обычно с интервалом в 1 мс) переменную - systick_count
в вашем случае - это сравнивается с локальной переменной внутри функции задержки - start
в твоем случае.
Здесь нужно отметить две вещи:
systick_count
необходимо сделать изменчивым, чтобы заставить перечитывать его значение перед каждым сравнением. Это модифицируется прерыванием, а не внутри этой функции. Ваш компилятор может решить оптимизировать эту часть кода.Прерывание SysTick должно быть "запущено" при вызове функции задержки. Если это не так, например, потому что вы находитесь в прерывании с более высоким приоритетом (численно более низким), то вы находитесь в тупике, и функция задержки никогда не завершится, потому что SysTick никогда не будет увеличивать счетчик, что никогда не происходит. Что касается этого пункта - не принимайте вещи и полагайтесь только на таблицу. Идите и на самом деле убедитесь, что он работает во время задержки. Либо проверяйте значения регистра NVIC в момент вызова функции задержки, либо просто устанавливайте точку останова в SysTick, когда вы находитесь в прерывании RTC - он должен достичь этой точки останова, пока вы находитесь в функции задержки. Если это не так - вам, вероятно, нужно настроить приоритеты прерываний.
Что касается самой идеи задержки ваших прерываний - это обычно считается плохой практикой. Предполагается, что прерывания используются для выполнения очень небольших частей работы очень быстро, например, для установки флага, что что-то должно быть сделано в основном программном коде, или для помещения полученного байта в очередь для последующей обработки. Хотя это может показаться неочевидным в простой программе, в которой у вас есть только одно прерывание (два, если вы учитываете Systick), оно очень быстро станет проблематичным, когда вы добавите больше прерываний, и столкнется с такими проблемами, как потеря информации, поскольку каждое прерывание блокирует каждое другие, и они не звонят достаточно быстро.