|
WINAVR: ламерский вопрос |
|
|
|
Feb 11 2008, 11:59
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Господа, помогите тормозящему. Надо получить библиотеку для RS-485 (это я так упражняюсь). Все бы ничего, но есть ножка, переключающая прием/передачу, и расположение ее не определено. Ясно, что #define здесь не годится. Объявление Код extern uint8_t Flow_Port, Flow_Pin_Mask; Тоже неприемлемо, потому что мы пытаемся получить инструкции sbi/cbi Значит, надо объявить extern inline функцию. Как правильно это сделать - не могу найти. Помогите,пожалуйста.
|
|
|
|
|
Feb 11 2008, 12:42
|

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

|
Цитата(_Pasha @ Feb 11 2008, 13:59)  Все бы ничего, но есть ножка, переключающая прием/передачу, и расположение ее не определено. Очень полезные макросы. Чуть-чуть поправить #ifdef и будут работать с avr-gcc. А вот тут они же, но уже под avr-gcc, спасибо сказать ReAlу
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 11 2008, 13:10
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Сергей Борщ @ Feb 11 2008, 15:42)  Очень полезные макросы... Спасибо, но я имел ввиду чуть другое. Хотел отвязаться от порядка компиляции модулей, из-за чего не хочется пользоваться макросом. Так, чтобы линкер подставил то ,что надо, а именно Flow_Port |=(1<<Flow_Pin); . Например: Код extern void Flow_Rx(void); // как ее правильно inline описать в главном модуле? ISR (UART_TX_vect) { Flow_Rx(); /*чтобы здесь оказалось Flow_Port &= ~(1<<Flow_Pin); без пролога/эпилога и вообще вызова подпрограммы*/ } Может, это вообще невозможно? А макросы великолепные.
Сообщение отредактировал _Pasha - Feb 11 2008, 13:14
|
|
|
|
|
Feb 12 2008, 10:46
|

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

|
Цитата(_Pasha @ Feb 11 2008, 15:10)  Спасибо, но я имел ввиду чуть другое. Хотел отвязаться от порядка компиляции модулей, из-за чего не хочется пользоваться макросом. Так, чтобы линкер подставил то ,что надо, а именно Flow_Port |=(1<<Flow_Pin); . Так вам не нужно это выносить в функцию. Вместо описания отдельных Flow_Port и Flow_Pin сделайте Код #define FLOW_PIN D,4,H // PORTD.4 переключает направление
ISR (UART_TX_vect) { off(FLOW_PIN); /*здесь как раз и окажется PORTD &= ~(1<<4); без пролога/эпилога и вообще вызова подпрограммы*/ ......... on(FLOW_PIN); /*а здесь PORTD |= (1<<4); без пролога/эпилога и вообще вызова подпрограммы*/ } А чтобы сделать что-то "без пролога/эпилога и вообще вызова подпрограммы", функцию можно определить как static inline __attribute__((__always_inline__)).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 12 2008, 16:48
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Сергей Борщ @ Feb 12 2008, 15:46)  сделайте Код #define FLOW_PIN D,4,H // PORTD.4 переключает направление Так ведь для библиотеки это не пойдёт?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Feb 12 2008, 17:38
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Сергей Борщ @ Feb 12 2008, 22:14)  С библиотекой скорее всего и не получится, ибо компилятор не может гарантировать, что при вызове такой функции в качестве параметров будут переданы константы. Неужели нет какого-нибудь механизма? Было бы очень соблазнительно иметь возможность передавать порты в качестве параметров при инициализации библиотечных модулей... Вот из faq: Код void set_bits_func_correct (volatile uint8_t *port, uint8_t mask) { *port |= mask; } То есть, если в библиотеке держать ссылку на порт (на два порта) и маску, то всё получится? Типа: Код static volatile uint8_t *led_port; // порт на вывод static volatile uint8_t *led_dport; // порт направления static uint8_t led_mask;
void init_led(volatile uint8_t *p, volatile uint8_t *dport, uint8_t mask) { led_port = port; led_dport = dport; led_mask = mask; *dport |= mask; *port |= mask; }
void led_on(void) { *led_port |= led_mask; }
void led_off(void) { *led_port &= ~led_mask; } Немного накладно конечно...
Сообщение отредактировал AHTOXA - Feb 12 2008, 17:39
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Feb 12 2008, 18:03
|

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

|
Цитата(AHTOXA @ Feb 12 2008, 19:38)  То есть, если в библиотеке держать ссылку на порт (на два порта) и маску, то всё получится? C ссылкой может и получится, но ссылка - это C++, а не С. В вашем примере в ОЗУ выделяется место, в котором хранится указатель на порт и компилятор при всей своей способности к оптимизации обязан считать из него адрес собственно порта. К тому же объявив указатель статическим, вы исключили возможность присвоить ему что-либо за пределами этого (библиотечного) файла. К сожалению, в С нет типа данных "константный адрес", который тут бы подошел (правда это можно обойти через приведения типа). Но главное - компилятор не имееет (насколько я знаю) механизма подстановки аргументов команд sbi, cbi на этапе линковки, только на этапе компиляции. Поэтому любая попытка передать адрес порта "извне" приведет к генерации команд lds/in, andi(ori), sts/out вместо sbi, cbi. Может быть можно как-то через инлайн-ассемблер это сделать, но я пока не представляю как и не имею (пока) необходимости разбираться. Я предпочитаю библиотеки в виде исходных текстов - так их легче хранить в репозитории
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 12 2008, 18:53
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Сергей Борщ @ Feb 12 2008, 23:03)  В вашем примере в ОЗУ выделяется место, в котором хранится указатель на порт и компилятор при всей своей способности к оптимизации обязан считать из него адрес собственно порта. К тому же объявив указатель статическим, вы исключили возможность присвоить ему что-либо за пределами этого (библиотечного) файла. Так это-то как раз хорошо:-) Чтобы я (или не я) не мог лазать в этот порт иначе как через функции библиотеки. Цитата - компилятор не имееет (насколько я знаю) механизма подстановки аргументов команд sbi, cbi на этапе линковки, только на этапе компиляции. Поэтому любая попытка передать адрес порта "извне" приведет к генерации команд lds/in, andi(ori), sts/out вместо sbi, cbi. Да, получается накладнее. Зачастую это приемлемо. Зато — библиотека! Откомпилил, протестил и забыл:-) Цитата Я предпочитаю библиотеки в виде исходных текстов - так их легче хранить в репозитории  Да я тоже в исходных текстах храню. Но эта куча дефайнов... Да и код лишний линкуется. (Я читал топик про способ этого избежать, но пока не пробовал.)
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Feb 12 2008, 20:48
|

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

|
Цитата(AHTOXA @ Feb 12 2008, 20:53)  Так это-то как раз хорошо:-) Чтобы я (или не я) не мог лазать в этот порт иначе как через функции библиотеки. А как вы им начальные значения присвоите кроме как из этого же исходника, т.е. на этапе компиляции библиотеки? Цитата(AHTOXA @ Feb 12 2008, 20:53)  Да я тоже в исходных текстах храню. Но эта куча дефайнов... Да и код лишний линкуется. (Я читал топик про способ этого избежать, но пока не пробовал.) Ну, куча-не куча, ровно столько же сколько и для библиотеки, если только она не привязана намертво к каким-то ногам. А если привязана - то они точно также переносятся в исходник библиотеки. Лишний код не линкуется - один раз настройте правильно компилятор и линкер и все. Из библиотеки лишний код линкуется точно также
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 12 2008, 21:11
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Сергей Борщ @ Feb 13 2008, 01:48)  А как вы им начальные значения присвоите кроме как из этого же исходника, т.е. на этапе компиляции библиотеки? Дык, я же написал: Код led_init(PORTB, DDRB, 1); Это будет в main(), библиотеку перекомпилировать не надо:-)
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Feb 13 2008, 08:33
|

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

|
Цитата(AHTOXA @ Feb 12 2008, 23:11)  Дык, я же написал: Все, теперь понял. Я изначально зациклился на получении в библиотеке команд sbi, cbi, ну в крайнем случае lds/sts, но никак не на указателях в явном виде. Как-то это расточительно - всю свою сознательную жизнь кристалл будет вынимать из одной и той же ячейки одно и то же значение указателя только из-за того, что у программиста не сложилось вшить этот адрес непосредственно в команду. И ведь понимаю, что это из серии asm vs C, но ничего с собой поделать не могу
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 13 2008, 08:57
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Сергей Борщ @ Feb 12 2008, 13:46)  А чтобы сделать что-то "без пролога/эпилога и вообще вызова подпрограммы", функцию можно определить как static inline __attribute__((__always_inline__)). Дык с этим аттрибутом Winavr все равно умудряется иногда сформировать подпрограмму. Когда подключал работу с eeprom, заметил это, хотя чтение вызывалось всего один раз. Поэтому не стал разбираться, а задал вопрос. Повторюсь, что вопрос вызван ошибкой в проектировании и явился следствием долгого писания на асме. ИМХО, правильная портируемая библиотека должна на своем нижнем уровне, работающем с железом, как раз и иметь все варианты через #ifdef..#endif, следовательно, подлежать самой частой перекомпиляции. На примере с RS-485 на данном уровне достаточно экспортировать функции настройки / работы с буферами, на котором сидят прерывания / единую кодировку ошибок. И все это с выбором номера порта. А протоколы - это уже другая песнь, но если не хватает ресурсов, проще, например, работу с 9-ти битной адресацией МК, мультимастеры и прочие дебри решать на данном "полужелезном" уровне. В данном случае "нисходящее проектирования" - отличный способ водить себя за нос, как сказал бы Эйнштейн.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|