STM32F4, странное поведение между обработчиком IRQ и функцией с общими переменными

Я столкнулся со странным поведением в моей программе. Для контекста я программирую микроконтроллер STM32F469. Используемая IDE — SW4STM32 (с версией Eclipse Neon (4.6.3)).

Чтобы сразу перейти к делу, вот что у меня есть:

void foo(void){
    while(1){
        if(var.x == 1){
            var.x = 0;
            var.y = 1;

            // Some irrelevant calculus

            var.y = 0;
        }
    }

Функция foo() не имеет ничего конкретного. Он работает, помимо всего прочего, здесь не относящегося к делу, с глобальной переменной (структурой) var.

void interruption(void){
    if(var.x == 0 && var.y == 0){
        // Some irrelevant calculus
        var.x = 1;
    }
}

Как следует из названия, функция interruption() представляет собой ISR (процедура обслуживания прерываний). Прерывание, связанное с этим ISR, возникает примерно каждые 16 мс. Он работает с той же глобальной переменной (структурой) var.

Наконец, вот мой main:

int main(void)
{
    myStruct var;
    var.x = 0;
    var.y = 0;

    // Some initialization (the ISR for example)

    foo();
}

Итак, чего я не понимаю, так это того, что весь процесс работает только в том случае, если между циклом while и условием if есть «что-то», например: задержка или переключение состояния вывода в функции foo():

 void foo(void){
    **Place something here to make the process work, a 1ms delay for example**
    while(1){
        if(var.x == 1){
            var.x = 0;
            var.y = 1;

            // Some irrelevant calculus

            var.y = 0;
        }
    }

Просто чтобы быть конкретным: когда это не работает, это означает, что моя программа не проходит ни условие if в ISR, ни условие if в функции foo(). Когда это сработает, программа пройдет их оба (условие if).

Тот факт, что оба условия if ложны, означает, что:

  1. var.x == 0
  2. var.y == 1
  3. Оба эти значения истинны вне условия if. Дело в том, что здесь что-то не так, обычно эти значения встречаются только в условии if функции foo(). И если я нахожусь в этом состоянии, var.y должно быть равно 0в конце этого состояния.

var в настоящее время больше нигде не используется.

Итак, мой вопрос: есть ли у вас какое-либо объяснение этому феномену?

Спасибо !


person vionyst    schedule 06.10.2017    source источник


Ответы (1)


Вероятно, вы видите кэширование регистров в действии. Убедитесь, что ваши глобальные переменные объявлены как volatile (см. https://barrgroup.com/Embedded-Systems/How-To/C-Volatile-Keyword). По сути, сгенерированный код не думает, что var.x может измениться за пределами текущей функции. Ключевое слово volatile сообщает генератору кода, что он должен предположить, что значение изменено асинхронным действием (ISR, обработчик сигнала, другой поток и т. д.).

О, и я предполагаю, что целевой язык — C или C++, так как язык определяет ключевое слово volatile.

person D.Shawley    schedule 06.10.2017
comment
Я никогда полностью не понимал, как, почему и когда следует использовать ключевое слово volatile (как говорится в вашей статье, кстати). Теперь я знаю. Это решило проблему. Спасибо ! - person vionyst; 06.10.2017
comment
@D.Shawley, в вашем случае этого недостаточно !!! Он тоже должен быть атомным. volatile не делает ничего другого, только обеспечивает загрузку и сохранение объекта, но не атомарность. Он проверяет значение и предпринимает действия для значения, которое тем временем может быть изменено (между загрузкой/модификацией/сохранением). - person 0___________; 06.10.2017