|
Порт как параметр функции С/С++ IAR |
|
|
|
Sep 6 2012, 10:17
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Собственно вопрос по теме сабжа: как передать имя порта (или любой другой регистр) как параметр в функцию/класс С++ ? Пишу программный драйвер интерфейса, создал под это дело класс обертку и хочу конфигурировать интерфейс (назначать ноги МК), чтобы можно было поднять несколько интерфейсов параллельно на разных ногах, создав несколько объектов. Пробовал вот так: Код void foo (unsigned char PORTx) { *(unsigned char*)PORTx=0xFF; }
void main(void) { foo(PORTA); } такой вариант не работает.... и компилятор ругается на строку вызова функции: Код Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 24)
|
Sep 6 2012, 10:30
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Как обычный указатель. Код void foo (volatile unsigned char * PORTx) { *PORTx=0xFF; }
void main(void) { foo( & PORTA); } В этом случае компилятор при работе с портом будет использовать команды LD/ST - которые занимают два такта. И не сможет использовать команды in,out, которые один такт и sbi,cbi, которые за один такт модифицируют значение одного бита в порту. Плюс еще надо будет передавать указатель на регистры DDRx и PINx. Для начала хватит, но есть и более интересный способ...
|
|
|
|
|
Sep 6 2012, 10:37
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
char * __io или char *__ext_io
В чем разница?
|
|
|
|
|
Sep 6 2012, 10:45
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
я так понимаю что вы предлагает сделать вот так: Код void foo (char* __io Portx) { Portx=0xFF; }
foo(PORTA); если так - не работает Error[Be009]: memory attributes not allowed on auto variables or parameters Цитата Как обычный указатель. Работает, но меня смущает, что компилятор не использует in/out инструкции
|
|
|
|
|
Sep 6 2012, 10:47
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Цитата(Непомнящий Евгений @ Sep 6 2012, 14:34)  neiver, а разве там все регистры мапятся в общее адресное пространство? Вроде бы __io не мапились... Мапятся. Даже регистры общего назначения r0-r31 мапятся начиная с адреса 0. Начиная с адреса 0x20 мапятся обычные IO регистры, следом расширенные.
|
|
|
|
|
Sep 6 2012, 10:58
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Код void classname::init(volatile unsigned char * PORTx) ??init: CFI Block cfiBlock0 Using cfiCommon0 CFI Function ??init // 6 { // 7 *PORTx=0xFF; LDI R16, 255 MOV R30, R17 ST Z, R16 // 8 } RET CFI EndBlock cfiBlock0
RSEG CODE:CODE:NOROOT(1) не ссорьтесь, мапится и работает. но все-таки хочется, чтобы через "out" заработало. neiver, а можно поподробнее : Цитата но есть и более интересный способ...
|
|
|
|
|
Sep 6 2012, 11:05
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Если хочется чтоб через in,out,sbi,cbi работало - у меня есть библиотечка "для работы с портами". С её помощью порты, отдельные пины и произвольные группы пинов можно передавать как шаблонные параметры функций и классов: Код template<class Port> void Foo() { Port::SetConfiguration(Port::Out); Port::Write(0xff); }
template<class Pin> void Bar() { Pin::Set(); ... Pin::Clear(); }
template<class PinGroup> void Buzz() { PinGroup::SetConfiguration(Port::Out); PinGroup::Write(0xff); }
int main() { Foo<IO::Porta>(); Bar<IO::Pa1>();
typedef IO::PinList<IO::Pa1, IO::Pa2, IO::Pb3, IO::Pb2> MyPinGroup; Buzz<MyPinGroup>(); } Тут тестовый пример для IAR AVR
|
|
|
|
|
Sep 6 2012, 12:07
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Цитата А как вы себе представляете это хотя бы на ассемблере? Адрес регистра находится в коде команды out, как функция сможет его заменить? Имелся ввиду другой вариант реализации. Насколько я понял из представленных сдесь вариантов, простого и прозрачного способа реализации этой задачи нет, кроме как использовать указатель (с вытекающими накладными расходами).
|
|
|
|
|
Sep 6 2012, 12:12
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(Errorkpi @ Sep 6 2012, 14:45)  я так понимаю что вы предлагает сделать вот так: У ИАРа кривоватая реализация. void foo (unsigned char volatile __io * adr) - работает
|
|
|
|
|
Sep 6 2012, 12:22
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Цитата(Непомнящий Евгений @ Sep 6 2012, 15:12)  У ИАРа кривоватая реализация.
void foo (unsigned char volatile __io * adr) - работает Неа Error[Ta034]: __io pointer/reference is not allowed. И даже попытка объявить эту переменную как член класса тоже не получится.
|
|
|
|
|
Sep 6 2012, 12:33
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Цитата(Непомнящий Евгений @ Sep 6 2012, 15:25)  Странно, у меня работает. IAR 5.12c. Atmega 128, 1280, 2560 5.50.0 - не работает, причем он одинаково относится к любым спецификаторам места хранения (__io, __flash, __eeprom) Попытка обмана, через ассемблер не прошла  void foo (unsigned char adr) { asm("CLR r17"); asm("OUT r16, r17"); // первый параметр функции типа char хранится в r16 } исходя из того, что я знаю про ассемблер, подменить этот параметр никак не получится.... Прийдется смирится с накладными рассходами. Всетаки интересно на счет спецификатора __io, мне так и не удалось его применить. Даже для глобальной переменной ругается вот так: Error[Ta007]: An __io declared variable must be located.
Сообщение отредактировал Errorkpi - Sep 6 2012, 12:34
|
|
|
|
|
Sep 6 2012, 13:04
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Цитата(_Артём_ @ Sep 6 2012, 15:59)  Новую команду ввели? У АВР нет такой команды. Да все я понимаю, думал может оптимизатор или линкер додумается подменить параметр PORTB на $18 в асм операторе. Не вышло, но надежда умирает последней. Все-таки странно, почему нет такой возможности на уровне спецификаторов, или директив препроцессора, все-таки часто используемая вещь (передача регистра I/O в функцию), судя по комментариям.
Сообщение отредактировал Errorkpi - Sep 6 2012, 13:07
|
|
|
|
|
Sep 6 2012, 13:16
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Цитата(demiurg_spb @ Sep 6 2012, 16:10)  Уже предлагали этот вариант и он действительно работает.... вот только появляются накладные расходы при таком подходе.... вынесу сюда, чтобы таких ответов больше не было: Код void set_bits_func (volatile uint8_t *port, uint8_t mask) { *port |= mask; }
транслируется в:
void set_bits_func (volatile uint8_t *port, uint8_t mask) { f8: fc 01 movw r30, r24 *port |= mask; fa: 80 81 ld r24, Z fc: 86 2b or r24, r22 fe: 80 83 st Z, r24 }
Сообщение отредактировал Errorkpi - Sep 6 2012, 13:19
|
|
|
|
|
Sep 6 2012, 13:24
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (Errorkpi @ Sep 6 2012, 16:04)  Да все я понимаю, думал может оптимизатор или линкер додумается подменить параметр PORTB на $18 в асм операторе. Не вышло, но надежда умирает последней. Ах вот оно что! Вам нужна встраиваемая функция... QUOTE (Errorkpi @ Sep 6 2012, 16:04)  или директив препроцессора Если на препроцессоре - ищите здесь на форуме "макросы имени Аскольда Волкова".
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 6 2012, 14:06
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 14-04-09
Пользователь №: 47 659

|
Цитата(Сергей Борщ @ Sep 6 2012, 16:24)  Ах вот оно что! Вам нужна встраиваемая функция...
Если на препроцессоре - ищите здесь на форуме "макросы имени Аскольда Волкова". inline как-бы не помогает...
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|