Как читать из периферийного регистра ввода-вывода с помощью C/gcc?

У меня есть маршрутизация службы прерываний на AVR32. Мне нужно прочитать из регистра состояния прерывания, чтобы отменить прерывание. Однако я не использую результат чтения. Я бы предпочел не использовать инструкцию asm, но я обеспокоен тем, что gcc оптимизирует чтение в фиктивную переменную. Каков правильный путь?

В настоящее время у меня есть:

uint32_t tmp = *(volatile uint32_t *)INTERRUPT_STATUS_REG_ADDRESS;

Должен ли tmp также быть изменчивым? Я беспокоюсь, что gcc просто пропустит чтение, если tmp не используется.


person Robotbugs    schedule 20.10.2014    source источник
comment
Я не знаком с AVR32, но вы уверены, что вам нужно читать регистр статуса прерывания? По моему опыту, вам нужно просто сбросить один флаг прерывания в соответствующем регистре (часто это достигается путем записи 1 в соответствующий бит). Кроме того, каков ваш вариант использования для этого?   -  person Rev    schedule 21.10.2014
comment
Да, это просто чтение регистра состояния сравнения ШИМ для очистки IRQ. uint32_t temp = AVR32_PWM.isr2;   -  person Robotbugs    schedule 22.10.2014


Ответы (1)


Чтение регистра состояния прерывания через указатель, приведенный к (volatile uint32_t*), сообщает компилятору, что чтение этого выражения (переменной по указанному адресу) приводит к побочным эффектам, поэтому ему всегда нужно вычислять это выражение.

Поскольку ваша переменная tmp не является изменчивой, компилятор может оптимизировать сохранение значения вашего регистра в переменной.

Я думаю, глава 5.1.2.3 стандарта C (см. здесь) достаточно актуален.

Кроме того, в главе 6.7.3 поясняется:

Объект с типом, определяемым как volatile, может быть изменен способом, неизвестным реализации, или иметь другие неизвестные побочные эффекты. Поэтому любое выражение, относящееся к такому объекту, должно оцениваться строго в соответствии с правилами абстрактной машины, как описано в 5.1.2.3. Кроме того, в каждой точке последовательности значение, сохраненное последним в объекте, должно совпадать со значением, предписанным абстрактной машиной, за исключением случаев, когда оно изменяется под действием неизвестных факторов, упомянутых ранее. 116) То, что представляет собой доступ к объекту, который имеет тип с уточнением volatile, определяется реализацией.

На самом деле вы можете опустить tmp и просто написать:

*(volatile uint32_t *)INTERRUPT_STATUS_REG_ADDRESS;

Это просто прочитает регистр uint32_t, расположенный по адресу INTERRUPT_STATUS_REG_ADDRESS;

person dbrank0    schedule 21.10.2014
comment
Спасибо, странно видеть кусок кода, который, кажется, ничего подобного не делает. Я действительно не был уверен, что такая вещь может работать. - person Robotbugs; 22.10.2014
comment
Да, это выглядит странно, так что, наверное, хорошо хотя бы написать макрос или функцию с поясняющим названием для чтения периферийных регистров. - person dbrank0; 22.10.2014