Имеем компилятор AVR-GCC в AVR-студии, оптимизация отключена, от слова совсем. Для обращения к группам устройств, разбросанных на разных пинах разных портов, сделал такую структуру.
typedef struct {
uint16_t port;
uint16_t ddr;
uint8_t mask;
} power_control;
Пример, инициализации такой структуры:
#define V5_SIZE 5
(
Read more... )
А в целом, раз уж задаете такие вопросы то неплохо бы вывод промежуточного ассемблера... Глядишь если туда заглянуть, то и спрашивать не придется.
Reply
Reply
Поясните, чем поможет volatile? У вас явно нет понимания ключевого слово volatile и где его применять. Поэтому, часто его пихают туда, где оно совсем не нужно. Обратите внимание на структуру:
const power_control PROGMEM power_5v [V5_SIZE]
А тут мы просто получаем адрес порта. И я буду узнать вашу версию, для чего там слово volatile и на что оно повлияет?
Reply
код без побочных эффектов компилятор имеет право выкинуть. ну и про насильную перетипизацию уже сказали - лучше оставить как есть, то есть, PORT и DDR в структуре иметь тех же типов что и в родном заголовке ио_что-то-там.аш
Reply
void digitalWrite(uint8_t pin, uint8_t val){
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
out = portOutputRegister(port);
uint8_t oldSREG = SREG; cli();
if (val == LOW) {
*out &= ~bit;
} else {
*out |= bit;
}
SREG = oldSREG;}
спасибо, попробую с volatile
Reply
>>во-первых неплохо бы добавить volatile в структуру, ко всем полям которые по сути адрес.
Зачем? У меня однопоточная программа, в прерывании переменная не изменяется, никто кроме меня не обращается к этому полю.
>>Во вторых а зачем такие пляски с приведением типов: * (uint8_t *) power_5v[i]? что мешает прямо в структуре обьявить его указателем на io?
Если вы дадите годный пример, то возьму за основу. Я взял то как реализован digitalWrite() в Ардуино, и переписал под свою задачу. Других адекватных способов я не встречал.
>> Глядишь если туда заглянуть, то и спрашивать не придется.
Меня не пугает заглянуть в ассемблер. Но как это поможет в том, что при компиляции код не соответствует стандартам?
Reply
Может быть для того, чтобы посмотреть, как именно он работает с mask? Попробуйте объявить mask тоже как uin16_t.
Reply
Ох, заставляете меня вспомнить молодость... Попробую сврганить что-нить но увы, не обещаю что будет быстро. Пока скажу лишь вот что
sfr_defs.h содержит
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
...
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
А уж далее в каком-нить iom1281.h
#define PINA _SFR_IO8(0X00)
т.е. для себя они совершенно правильно не забывают volatile, что категорически не дает оптимизатору разгуляться. Увы, шибко умные компиляторы - бич современности.
>> Меня не пугает заглянуть в ассемблер.
Напрасно... И потом, ну ладно второкурсник из института, но вы-то... И бояться ассемблера...
>> Но как это поможет в том, что при компиляции код не соответствует стандартам?
Кстати хорошее замечание. А включите в настройках C89 и проверим...
Reply
Я где-то сказал что боюсь ассемблера? (Несколько раз перечитал, не увидел). Просто чтобы туда заглядывать надо понять, что я хочу увидеть и как это мне поможет модифицировать код. Я много лет писал на ассемблере для AVR, дизассемблировал программы. Но надо понимать какую цель преследуешь туда заглядывая.
Reply
А заглянуть - так ровно за этим. Что творит компилятор, что получается дичь. У меня есть привычка туда регулярно заглядывать. Просто на всякий случай. А уж при возникновении подобных проблем - мне кажется сам бог велел.
Reply
volatile uint8_t* port;
volatile uint8_t* ddr;
uint8_t mask;
} power_control;
#define V5_SIZE 5
const power_control power_5v [V5_SIZE] = {
{ &PORTA, &DDRA, _BV(7)}, //POWER_5B_1
{ &PORTA, &DDRA, _BV(6)}, //POWER_5B_2
{ &PORTC, &DDRC, _BV(6)}, //POWER_5B_3
{ &PORTD, &DDRD, _BV(6)}, //POWER_5B_4
{ &PORTC, &DDRC, _BV(4)}, //POWER_5B_5
};
//...
for(int i = 0; i < V5_SIZE; i ++) {
*power_5v[i].port |= power_5v[i].mask;
}
//....
Для начала как-то так... С PROGMEM как-нить сами. И да - увы, проверить нечем.
Reply
Спасибо, проверю, отпишусь. PROGMEM это не обязательный атрибут, памяти у меня много-много
Reply
решение оказалось банальным. Код не менял свой от слова совсем, просто в приведение типов добавил слово volatile и всё стало работать, вот так:
* (volatile uint8_t *) power_5v[i].port |= power_5v[i].mask;
Reply
Reply
Leave a comment