Avr-gcc почему не работает обращение к полям структуры по индексу в цикле?

Имеем компилятор AVR-GCC в AVR-студии, оптимизация отключена, от слова совсем. Для обращения к группам устройств, разбросанных на разных пинах разных портов, сделал такую структуру.

typedef struct {
	uint16_t port;
	uint16_t ddr;
	uint8_t mask;
} power_control;

Пример, инициализации такой структуры:

#define V5_SIZE		5
const power_control PROGMEM power_5v [V5_SIZE] = {
	{(uint16_t) &PORTA, (uint16_t) &DDRA, _BV(7)}, //POWER_5B_1
	{(uint16_t) &PORTA, (uint16_t) &DDRA, _BV(6)}, //POWER_5B_2
	{(uint16_t) &PORTC, (uint16_t) &DDRC, _BV(6)}, //POWER_5B_3
	{(uint16_t) &PORTH, (uint16_t) &DDRH, _BV(6)}, //POWER_5B_4
	{(uint16_t) &PORTC, (uint16_t) &DDRC, _BV(4)}, //POWER_5B_5
};


При этом, если попробовать сделать все пины в единицу в цикле, а потом в ноль в цикле - это не работает:

//set to 1
	for(int i = 0; i < V5_SIZE; i ++) {
		* (uint8_t *) power_5v[i].port |= power_5v[i].mask;
	}
	_delay_ms(1000);

//set to 0
	for(int i = 0; i < V5_SIZE; i ++) {
		* (uint8_t *) power_5v[i].port &=~ power_5v[i].mask;
	}


Артефакты какие-то есть на пинах, но всё не поднимается. При этом, если просто вручную написать обращение по индексу, то всё работает корректно:

//set to 1
	* (uint8_t *) power_5v[0].port |= power_5v[0].mask;
	* (uint8_t *) power_5v[1].port |= power_5v[1].mask;
	* (uint8_t *) power_5v[2].port |= power_5v[2].mask;
	* (uint8_t *) power_5v[3].port |= power_5v[3].mask;
	* (uint8_t *) power_5v[4].port |= power_5v[4].mask;
	_delay_ms(1000);
//set to 0
	* (uint8_t *) power_5v[0].port &=~ power_5v[0].mask;
	* (uint8_t *) power_5v[1].port &=~ power_5v[1].mask;
	* (uint8_t *) power_5v[2].port &=~ power_5v[2].mask;
	* (uint8_t *) power_5v[3].port &=~ power_5v[3].mask;
	* (uint8_t *) power_5v[4].port &=~ power_5v[4].mask;


Почему такое может быть, а главное: как это исправить?

З.Ы. Не в первый раз сталкиваюсь, как avr-gcc чудит со структурами, и пока не знаю внятного решения как это победить.
  • Вопрос задан
  • 163 просмотра
Решения вопроса 1
dlinyj
@dlinyj Автор вопроса
Решение оказалось банальным.

* (volatile uint8_t *) power_5v[i].port |= power_5v[i].mask;


Добавил ключевое слово volatile и всё стало работать как надо!
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
если просто вручную написать обращение по индексу, то всё работает корректно
Почему такое может быть

Если посмотреть в сгенерированный код (я компилировал командой
avr-gcc -mmcu=atmega2560 -DF_CPU=8000000 -fverbose-asm -S test.c
), то можно увидеть, что он не обращается к массиву power_5v, а все константы просто подставлены как непосредственные значения в инструкции. Я думаю, что по этой причине.

как это исправить

Нужны детали: версия компилятора, опции компиляции.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы