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 в твоем случае.

Здесь нужно отметить две вещи:

  1. systick_count необходимо сделать изменчивым, чтобы заставить перечитывать его значение перед каждым сравнением. Это модифицируется прерыванием, а не внутри этой функции. Ваш компилятор может решить оптимизировать эту часть кода.

  2. Прерывание SysTick должно быть "запущено" при вызове функции задержки. Если это не так, например, потому что вы находитесь в прерывании с более высоким приоритетом (численно более низким), то вы находитесь в тупике, и функция задержки никогда не завершится, потому что SysTick никогда не будет увеличивать счетчик, что никогда не происходит. Что касается этого пункта - не принимайте вещи и полагайтесь только на таблицу. Идите и на самом деле убедитесь, что он работает во время задержки. Либо проверяйте значения регистра NVIC в момент вызова функции задержки, либо просто устанавливайте точку останова в SysTick, когда вы находитесь в прерывании RTC - он должен достичь этой точки останова, пока вы находитесь в функции задержки. Если это не так - вам, вероятно, нужно настроить приоритеты прерываний.

Что касается самой идеи задержки ваших прерываний - это обычно считается плохой практикой. Предполагается, что прерывания используются для выполнения очень небольших частей работы очень быстро, например, для установки флага, что что-то должно быть сделано в основном программном коде, или для помещения полученного байта в очередь для последующей обработки. Хотя это может показаться неочевидным в простой программе, в которой у вас есть только одно прерывание (два, если вы учитываете Systick), оно очень быстро станет проблематичным, когда вы добавите больше прерываний, и столкнется с такими проблемами, как потеря информации, поскольку каждое прерывание блокирует каждое другие, и они не звонят достаточно быстро.

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