QUOTE (sigmaN @ Mar 9 2013, 04:18)

Верно ли утверждение, что все глобальные переменные, доступ к которым осуществляется как в прерывании, так и в основном цикле нужно обязательно объявлять с volatile?
Да, верно.
QUOTE (xemul @ Mar 9 2013, 10:20)

volatile должны быть объявлены глобальные переменные, которые и _изменяются_ в прерывании, и используются вне прерывания.
channels[i].enabled, channels[i].top и channels[i].compare_val в прерывании не изменяются, и им volatile'ность не требуется.
А вот это неверно. Если оставить их без volatile, то компилятор может в основном цикле просто закешировать их значение в регистрах и никогда не складывать в память. А может вообще выкинуть все операции с этими переменными, ибо в основном цикле есть только запись в эти переменные, но нет чтения. Следовательно, результат этой записи никому не нужен и считать его тоже не нужно.
QUOTE (sigmaN @ Mar 9 2013, 04:18)

но вот тут вдруг всё работает даже с -O3
Если хотите после обновления компилятора или изменения какой-нибудь галочки в его настройках или изменения исходника долго и с удовольствием искать, почему же все вдруг перестало работать - оставьте так. Если же будете добавлять volatile, то в местах, где есть несколько доступов к одной переменной вроде вот этого:
CODE
channels[i].counter++;
if ( channels[i].counter == channels[i].compare_val )
используйте временную не-volatile переменную:
CODE
uint8_t counter_cache = channels[i].counter++;
if ( counter_cache == channels[i].compare_val )