:::: MENU ::::

volatile и зависания

Ключевое слово volatile – это спецификатор, применяемый при объявлении переменной. Он сообщает компилятору, что значение переменной может изменяться в любой момент – без какого-либо действия со стороны кода, который компилятор обнаруживает поблизости.

Переменная должна быть объявлена с ключевым словом volatile  всякий раз, когда ее значение может измениться неожиданно. На практике так ведут себя только три типа переменных:

1.    Отображаемые в памяти периферийные регистры
2.    Глобальные переменные, изменяемые в обработчике прерывания
3.    Глобальные переменные, используемые в многопотоковом приложении

Встраиваемые системы содержат оборудование со сложной периферией. В составе  периферии есть регистры, чьи значения могут изменяться асинхронно алгоритму программы. В качестве простого примера рассмотрим 8-битный регистр состояния, отображаемый в памяти по адресу 0х1234. Допустим, нам нужно опрашивать регистр состояния до тех пор, пока он не станет ненулевым. Простая и неправильная реализация может быть такой:

uint8_t * pReg = (uint8_t *) 0x1234;

// Wait for register to become non-zero
while (*pReg == 0) { } // Do something else

В этом случае, почти наверняка будет сбой, как только вы включите оптимизацию.  Компилятор сгенерирует ассемблерный код подобный этому:

  mov ptr, #0x1234
  mov a, @ptr
loop:
  bz loop

Логическое обоснование оптимизатора довольно простое: уже считав значение переменной в аккумулятор (вторую строка кода), нет необходимости считывать его заново, поскольку  значение всегда будет тем же. Таким образом, в третьей строке мы окажемся в бесконечном цикле. Чтобы заставить компилятор сделать то, что нам нужно, мы изменим описание на:

uint8_t volatile * pReg = (uint8_t volatile *) 0x1234;

Ассемблерный код теперь выглядит следующим образом:

  mov ptr, #0x1234
loop:
  mov a, @ptr
  bz loop