Waso 1 4 ноября, 2009 Опубликовано 4 ноября, 2009 · Жалоба Всем доброго времени суток! Понадобилось перенести проект с IAR (EWAVR 530) на WinAVR (20090313) для юридической чистоты... Вылезла такая бяка: Иар успешно работает с такой конструкцией: template <unsigned char volatile * port, const char bit> class mypin { public: inline mypin() {*(port-1)|=(1<<bit);} // смещение -1 - регистр DDR - настраиваем на выход. static inline void set() {*port|=(1<<bit);} }; int main() { mypin<&PORTA,4> mypinname; // тут мы обьявляем место подключения и инициализируем одновременно //... mypinname.set(); //... } А WinAVR глючит на конструкции &PORTA в объявлении класса и заявляет что не хватает параметров: - wrong number of template arguments (1, should be 2) provided for 'template<volatile uint8_t* port, char bit> class mypin' хотя в другом месте адрес порта успешно изымается: volatile uint8_t* portC = &PORTC; *portC &= ~(1<<7); Это глюк компилятора? Как это можно обойти? Подскажите пожалуйста! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 4 ноября, 2009 Опубликовано 4 ноября, 2009 (изменено) · Жалоба Попробуйте в шаблоне не делать предположения о том, что uint8_t это unsigned char, а оставить этот тип. За справками в файл stdint.h, строка 121. И поделитесь результатами. зы: а попробуйте как улучшение сделать параметром ссылку вместо указателя. Изменено 4 ноября, 2009 пользователем Genadi Zawidowski Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Waso 1 4 ноября, 2009 Опубликовано 4 ноября, 2009 · Жалоба template <uint8_t volatile & port, const char bit> class mypin { public: __inline mypin(){*(&port-1)|=(1<<bit);} static __inline void set() {port|=(1<<bit);} }; mypin<PORTA,4> mypinname; mypinname.set(); такой вариант работает в иаре, но ухудшается оптимизация. ВинАВР же опять не доволен строчкой "mypin<PORTA,4> mypinname;": - template argument 1 is invalid - `*' cannot appear in a constant-expression - a cast to a type other than an integral or enumeration type cannot appear in a constant-expression звезда там берется из разложения макроса PORTA => (*(volatile uint8_t *)((0x1B) + 0x20)) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 4 ноября, 2009 Опубликовано 4 ноября, 2009 · Жалоба А не надо делать предположения об адресе регистра управления направлением. Заведите явный параметр для регистра управления направлением и настанет благодать... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 4 ноября, 2009 Опубликовано 4 ноября, 2009 · Жалоба А не надо делать предположения об адресе регистра управления направлением. Заведите явный параметр для регистра управления направлением и настанет благодать... Шоб это было так просто... Если объявить volatile-переменную и передавать её адрес mypin< &vv >, то и с этим констурктором работает и ожидаемый код генерит, а если даже его убрать а на место &PORTA вручную вписать mypin< (volatile uint8_t *)0x1B > mypinname; то всё равно ругается p.cpp:13: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression p.cpp:13: error: template argument 1 is invalid Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 4 ноября, 2009 Опубликовано 4 ноября, 2009 (изменено) · Жалоба Что не так в версии: template <uint8_t volatile & ctl, uint8_t volatile & port, const char bit> class mypin { public: __inline mypin(){ctl|=(1<<bit);} static __inline void set() {port|=(1<<bit);} }; mypin<DDRA,PORTA, PA4> mypinname; mypinname.set(); Изменено 4 ноября, 2009 пользователем Genadi Zawidowski Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 4 ноября, 2009 Опубликовано 4 ноября, 2009 · Жалоба Что не так в версии:А я почём знаю, что ему не так. ================= E:\>c:\WinAVR/bin/avr-g++ -Wall -Wextra --version 2>&1 avr-g++ (GCC) 4.4.0 20090323 (experimental) Copyright (C) 2009 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. E:\>c:\WinAVR/bin/avr-gcc -Wall -Wextra -Os -S -mmcu=atmega64 p.cpp 2>&1 p.cpp: In function 'void foo()': p.cpp:14: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression p.cpp:14: error: '*' cannot appear in a constant-expression p.cpp:14: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression p.cpp:14: error: '*' cannot appear in a constant-expression p.cpp:14: error: template argument 1 is invalid p.cpp:14: error: template argument 2 is invalid p.cpp:14: error: invalid type in declaration before ';' token p.cpp:15: error: request for member 'set' in 'mypinname', which is of non-class type 'int' =================== avr-gcc.exe (WinAVR 20090313) 4.3.2 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. p.cpp: In function 'void foo()': p.cpp:14: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression p.cpp:14: error: `*' cannot appear in a constant-expression p.cpp:14: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression p.cpp:14: error: `*' cannot appear in a constant-expression p.cpp:14: error: template argument 1 is invalid p.cpp:14: error: template argument 2 is invalid p.cpp:14: error: invalid type in declaration before ';' token p.cpp:15: error: request for member 'set' in 'mypinname', which is of non-class type 'int' =================== avr-gcc.exe (GCC) 4.2.2 (WinAVR 20071221) Copyright (C) 2007 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. p.cpp: In function 'void foo()': p.cpp:14: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression p.cpp:14: error: `*' cannot appear in a constant-expression p.cpp:14: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression p.cpp:14: error: `*' cannot appear in a constant-expression p.cpp:14: error: template argument 1 is invalid p.cpp:14: error: template argument 2 is invalid p.cpp:14: error: invalid type in declaration before ';' token p.cpp:15: error: request for member 'set' in 'mypinname', which is of non-class type 'int' Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 5 ноября, 2009 Опубликовано 5 ноября, 2009 (изменено) · Жалоба Посмотрел на результат препроцессирования (-E)... Только не понятно с такими ошибками, как же тогда offsetof в константных инициалзиаторах работает? Или тогда дефайлы для SFR надо было бы сделать так же... Кто объяснит это автору? ps: а для случая со смещениями в структурах придумано __builtin_offsetof - интересно, что-то делающее l-value из числа встроенное есть? Изменено 5 ноября, 2009 пользователем Genadi Zawidowski Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Waso 1 5 ноября, 2009 Опубликовано 5 ноября, 2009 · Жалоба Genadi, даже если уйти от смещений и явно указывать регистры, то проблема остается. Ведь компилятор ругается не на это. Он не хочет принимать указатель как константу. В теме с исходниками нашел такой файлик "avrio.hpp" от Аlex312. Там эта задача реализована через enum-ы: enum __bits {__bit_0=0, __bit_1=1, __bit_2=2, __bit_3=3, __bit_4=4, __bit_5=5, __bit_6=6, __bit_7=7}; enum __ports{__port_A,__port_B,__port_C,__port_D,__port_E,__port_F,__port_G}; enum __ports_reg {__reg_PORT, __reg_DDR, __reg_PIN}; // Шаблон функции, определяющей требуемые адреса в пространстве В/В template <__ports port, __ports_reg reg> volatile uint8_t& __ports_ref(); #define AVRLIB_SPECIALIZE_PORT_REF(_port_) \ template <> inline volatile uint8_t& __ports_ref<__port_##_port_, __reg_PORT>() { return PORT##_port_; } \ template <> inline volatile uint8_t& __ports_ref<__port_##_port_, __reg_DDR >() { return DDR##_port_; } \ template <> inline volatile uint8_t& __ports_ref<__port_##_port_, __reg_PIN >() { return PIN##_port_; } #if defined (PORTA) AVRLIB_SPECIALIZE_PORT_REF(A) #endif #if defined (PORTB) AVRLIB_SPECIALIZE_PORT_REF(B) #endif ..... template <__ports port, __bits bit> class __pin { public: static inline void set(void) { __ports_ref<port, __reg_PORT>()|=bit_mask(bit); } }; __pin<__port_C,__bit_4> out4; out4.set(); Довольно муторно, но работает. Правда на этот раз несварение возникает у Иара. Даже на максимальной оптимизации он упорно отказывается сводить "out4.set();" к ассемблерному "sbi". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 5 ноября, 2009 Опубликовано 5 ноября, 2009 · Жалоба .. Гляньте ещё вот здесь, может пригодится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 5 ноября, 2009 Опубликовано 5 ноября, 2009 · Жалоба А не получится описать порты как переменные и задать их адрес через скрипт линкера? // In .h file extern volatile uint8_t PORTA; // In .ld file _PORTA = 0x3B Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Waso 1 6 ноября, 2009 Опубликовано 6 ноября, 2009 · Жалоба AHTOXA, посмотрел я на ваши труды и попробовал написать подобное для АВР. Сначала было так: template<GPIO_mode_t mode, char port, int bit, char activestate> class Pin{ inline volatile uint8_t & PORTx() { #if defined (PORTA) if (port == 'A') return PORTA; #endif #if defined (PORTB) if (port == 'B') return PORTB; #endif //..................такая конструкция для буков С..F и все вместе для DDRх и PINх} inline void On() { if ( mode==BIDIR || mode==OUTPUT ) {activestate == 'L' ? PORTx()&=~mask : PORTx()|=mask;} if ( mode==OUTPUT_OK ) {activestate == 'L' ? DDRx()|=mask : DDRx()&=~mask;} } // и тп } Потом пытался уменьшить количество писанины в части ссылок на регистры: template<char port> class Base_Pin; template<> // такой шаблон для всех буков - можно сделать макрос class Base_Pin<'A'> { public: inline volatile uint8_t & PORTx(){return PORTA;} inline volatile uint8_t & DDRx(){return DDRA;} inline volatile uint8_t & PINx(){return PINA;} }; template<GPIO_mode_t mode, char port, int bit, char activestate> class Pin2 : public Base_Pin<port> { inline void On(){Base_Pin<port>::PORTx()|=(1<<bit);} }; И если дальше "упрощать" создав макрос для объявления базовых классов всех портов, то приходим к необходимости отказаться от символьных констант и воспользоваться enum-ом. В итоге получаем код Alex312. Но я оставил себе первый вариант. Он хоть и громоздкий, но зато легко читаемый\понимаемый. И да кстати. Я так и не понял в чем вкусность переопределения операторов в примере Антона. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 6 ноября, 2009 Опубликовано 6 ноября, 2009 · Жалоба Сначала было так:template<GPIO_mode_t mode, char port, int bit, char activestate> ... Ну и нормально:) Только #if defined (PORTA) - лишнее, ибо не будет вызываться, пока вы не определите Pin<'A'...>. В этом прелесть шаблонов:) Потом пытался уменьшить количество писанины в части ссылок на регистры: template<char port> class Base_Pin; ... template<GPIO_mode_t mode, char port, int bit, char activestate> class Pin2 : public Base_Pin<port> ... От наследования тут мало толку, всё равно приходится указывать имя базового класса. Здесь удобнее определить включаемый класс, типа // объявление шаблона регистров порта: template<char port>struct port_regs_t; // специализация для каждого порта: template <> struct port_regs_t<'A'> { inline volatile uint8_t & PORTx(){return PORTA;} ... }; ... // и наконец, собственно шаблон ноги: template<GPIO_mode_t mode, char port, int bit, char activestate> class Pin2 { private: typedef port_regs_t<port> regs_t; public: typename regs_t::PORTx PORTx; typename pins_t::DDRx DDRx; typename pins_t::PINx PINx; ... }; В варианте для MSP430 (а именно на него я давал ссылку:) ) у меня примерно так и сделано. А вы, похоже, смотрели вариант для stm32? И да кстати. Я так и не понял в чем вкусность переопределения операторов в примере Антона. Дык, просто что-то не сложилось со ссылками (или просто не догадался). Потому пришлось определять все операции. Если работает со ссылками, то так конечно лучше. Надо будет попробовать... И, кстати, одно замечание по параметрам. Имхо, включать режим работы ножки (GPIO_mode_t) в перечень параметров шаблона - идеологически неверно. Потому что иногда случается, что режим работы ноги надо переключать на ходу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 6 ноября, 2009 Опубликовано 6 ноября, 2009 · Жалоба Потому что иногда случается, что режим работы ноги надо переключать на ходу."я даже больше скажу" - для тех ног, для которых оно в начале программы один раз ставится и всё - для них не жалко и в начале программы несколько строк DDRx = 0xXX написать, а вот если уж начинаешь переключать.... offtopic: Я пока в эти все темы с интересом заглядываю, но использую всё те же "Волковские" макросы, нет времени на эти эксперименты. Зато, похоже, мне нравится placement new :rolleyes: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 6 ноября, 2009 Опубликовано 6 ноября, 2009 · Жалоба Зато, похоже, мне нравится placement new :rolleyes: А что это? А то может мне тоже это нравится, а я и не знаю ;) ---- Почитал. Пока не понял, нравится ли... Но скорее да, чем нет:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться