|
|
  |
WinAVR - как оно?, Эффективность компилятора |
|
|
|
May 27 2006, 15:14
|

Дух погибшего транзистора
   
Группа: Свой
Сообщений: 877
Регистрация: 6-09-05
Из: Москва
Пользователь №: 8 288

|
А собственнно в чем вопрос у автора, если альтернативы gcc как многгоплатформенному компилятору особой нет? Знаю что компилятор реально хороший, под AVR проигрывает только IAR. Но есть некоторые мелкие особенности использования gcc в целом: 1 некоторые версии могут быть глючными даже при том что получили стабильный номер. 2 старшие версии могут в некоторых моментах быть не совместимыми с предыдущими, причем это как правило не документируется, так как создатели такие моменты просто могут упустить из вида. 3 существует обилие документации но вся она бестолковая, создается впечатление вороха бумажек вместо прошитых и разложенных по папкам документов 4 своеобразный синтаксис асм, берущий начало от AT&T, хотя многим нравится, я лично тоже не против.
--------------------
Yes, there are two paths you can go by But in the long run Theres still time to change the road youre on.
|
|
|
|
|
May 28 2006, 22:18
|
Частый гость
 
Группа: Свой
Сообщений: 126
Регистрация: 1-01-06
Из: Украина, Киев
Пользователь №: 12 759

|
Цитата([banned] @ May 27 2006, 09:21)  Цитата(msn @ May 27 2006, 03:10)  Пользуюсь больше 4-х лет.
до сих пор нет нормально реализованной printf
ну если ОНА так нужна то можно было уж свою написать и поделится с общественностью ! В большинстве случаев так и есть использую, свои функции из разряда print_num, print_hex, print _str, print _pstr и т.д. Но когда переносишь часть кодов, например, с какого ни будь 8051 для которого обычно пишу в Keil (там printf на мой взгляд очень хорошо сделано) то довольно таки накладно менять. Еще printf очень удобно пользоваться софте содержащим очень много разнородных сообщений для работы с пользователем, у меня это промышленные контролеры, где по объему эти сообщения / меню / разнообразная информация и т.д. занимают, чуть ли не половину места программы. Свою не писал, не вижу смысла, использую уже написанные до меня (в инете их превеликое множество), допустим из Procyon AVRlib. Цитата(aesok @ May 27 2006, 21:33)  Цитата(msn @ May 27 2006, 02:10)  .... до сих пор нет нормально реализованной printf, ...
Что вам не хватает в 'printf', можно подробнее? Во первых первое что попадается на глаза при прочтении мануала Standard IO facilities: Warning: This implementation of the standard IO facilities is new to avr-libc. It is not yet expected to remain stable, so some aspects of the API might change in a future release. Уже настораживает. Когда то писал софт на 8515 (простенький диспетчерский контролер, задачей которого было прослушивание линии вывод разных сообщений и в нагрузку управлении нескольким дискретными входами / выходами), так вот из 8 КБ код и вызовы printf сожрали почти 6,5 КБ, т.е. больше 80 %. Частично посмотрел в дебугере реализацию самой функции и ее вызовом особенно где было несколько параметров (в основном целы числа, строки и символы) сложилось такое впечатление что ни кто ни чего не оптимизировал.
|
|
|
|
|
May 29 2006, 13:51
|
Частый гость
 
Группа: Свой
Сообщений: 126
Регистрация: 1-01-06
Из: Украина, Киев
Пользователь №: 12 759

|
Цитата(_4afc_ @ May 29 2006, 15:54)  Я тоже пользуюсь только им, но раньше ( а скорее всего и сейчас) у него была одна особенность - он хранил все данные в RAM перенося их туда из FLASH в начальном коде. Раньше можно было только строки (char) хранить во FLASH. Причём в принципе заставить хранить там данные можно, а вот заставить взять средствами си - не получалось, он не использовал код LPM и брал соответственно значение из RAM. Сейчас вроде все нормально: Код prog_char ansi_rus[64]={0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4, // Таблица перекодировки таблицы ЖКИ в соответствии с таблицей ANSI ... 0xc1,0xe6,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7};
...
void print_char(u8_t ch) { if (lcd_x>(LCD_COLUMN-1) || lcd_y>(LCD_ROW-1)) {return;} // Если за пределами ЖКИ if (ch>=0xc0 && !fl_no_use_ansi_rus) {ch=pgm_read_byte(&ansi_rus[ch-0xc0]);} lcd_wr_data(ch); // Вывести символ по текущим координатам lcd_x++; // Передвигаемся на следующие знакоместо } Или Код const char txtErrorMaster__0[] PROGMEM = " Исход. состояние ";// 0 Текстовое представлениие произошедшей аврии / предупреждения const char txtErrorMaster__1[] PROGMEM = " Отказ модуля 1 ";// 1 const char txtErrorMaster__2[] PROGMEM = " Отказ модуля 2 ";// 2 ....
PGM_P txtErorrMaster[] = {txtErrorMaster__0, // Буфер для поиндексного доступа txtErrorMaster__1, txtErrorMaster__2, .... };
....
void print_str(PGM_P addr) { u8_t ch; while ((ch=pgm_read_byte(addr++))) {print_char(ch);} }
|
|
|
|
|
May 29 2006, 13:52
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата Причём в принципе заставить хранить там данные можно, а вот заставить взять средствами си - не получалось, он не использовал код LPM и брал соответственно значение из RAM. Да, к сожалению, невозможность легко манипулировать данными из флэш было и остается самым серьезным недостатком avr-gcc. Здесь ИАР рулит однозначно.
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
May 29 2006, 13:54
|

МедвеД Инженер I
   
Группа: Свой
Сообщений: 816
Регистрация: 21-10-04
Пользователь №: 951

|
Цитата(msn @ May 29 2006, 02:18)  В большинстве случаев так и есть использую, свои функции из разряда print_num, print_hex, print _str, print _pstr и т.д. Но когда переносишь часть кодов, например, с какого ни будь 8051 для которого обычно пишу в Keil (там printf на мой взгляд очень хорошо сделано) то довольно таки накладно менять. Еще printf очень удобно пользоваться софте содержащим очень много разнородных сообщений для работы с пользователем, у меня это промышленные контролеры, где по объему эти сообщения / меню / разнообразная информация и т.д. занимают, чуть ли не половину места программы. Свою не писал, не вижу смысла, использую уже написанные до меня (в инете их превеликое множество), допустим из Procyon AVRlib. тоесть вы хотите сказать что в WInAvr не реализованы аналоги ваших - print_hex,print_num,print _str,print _pstr посредством родного (winavr) PRINTF? или то что они жрут много?
--------------------
Cogito ergo sum
|
|
|
|
|
May 29 2006, 14:10
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(_4afc_ @ May 29 2006, 15:54)  Ну и вообще прерывания лучше на ассемблере писать, а то слишком много ресурсов съедает. (Пример - обработка внешнего последовательного АЦП на си потребовала бы поставить Atmega48 на 80МГц, периписав код на асм с разделением регистров - уложился в 10  Не убедительно ;> В таком случае лучше вообще все писать на асм.. Не вижу смысла писать на Си под чипы у которых меньше 16k Flash.. Не исключено, что программа которая у Вас выполняется на m48, будучи полностью переписана на asm (и с условием наличия требуемых пинов) с успехом разместилась бы в t13. ps: Пример - IP стек на ассемблере, чудно влез в m48 вместе с программой решающей прикладную задачу и пакетным драйвером PHY/MAC контроллера, еще 2kb флеша осталось (при этом на 20Mhz помимо выполнения основной задачи и общения с сервером по TCP обеспечивается еще и стабильный отклик 1ms на несколько десятков потоков ping'a с пакетами (ICMP) по 256 байт). Для решения этой же задачи на Си потребовался бы ARM ;>
|
|
|
|
|
May 29 2006, 14:27
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(msn @ May 29 2006, 01:18)  Во первых первое что попадается на глаза при прочтении мануала Standard IO facilities: Warning: This implementation of the standard IO facilities is new to avr-libc. It is not yet expected to remain stable, so some aspects of the API might change in a future release. Уже настораживает. printf - Это стандартная функция и она не будет изменяться. Что касается функций открытия/закрытия потоков, то эти изменения уже произошли в avr-libc версии 1.4. В версии 1.2 была функция 'fdevopen' которая использовала динамическое выделение памяти (malloc()), в версии 1.4 этой функции нет. Цитата(msn @ May 29 2006, 01:18)  Когда то писал софт на 8515 (простенький диспетчерский контролер, задачей которого было прослушивание линии вывод разных сообщений и в нагрузку управлении нескольким дискретными входами / выходами), так вот из 8 КБ код и вызовы printf сожрали почти 6,5 КБ, т.е. больше 80 %. Скорее всего это произошло из за того, что вы использовали полную версию 'printf' с поддержкой чисел с плавающей точкой. О разных вариантах функции 'printf', а точнее 'vfprintf', посмотрите описание 'vfprintf'. Если вам не нужны числа с плавающей точкой используйте стандартную версию функции 'vfprintf'. Код #include <stdio.h>
int uart_putchar(char c, FILE *stream) { return 0; }
FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
int main() { stdout = &uart_str; printf("test"); return 0;
} Размер кода для этой программы при использовании стандартной версии 'vfprintf' равен примерно 1.8KB, при использовании полной версии (с плавающей точкой) примерно 4,5KB. Конечно не бесплатно ..... Цитата(msn @ May 29 2006, 01:18)  Частично посмотрел в дебугере реализацию самой функции и ее вызовом особенно где было несколько параметров (в основном целы числа, строки и символы) сложилось такое впечатление что ни кто ни чего не оптимизировал. 'vfprintf' написанна на С, пока не нашлось героя переписать ее на асме.  Анатолий.
Сообщение отредактировал aesok - May 29 2006, 14:33
|
|
|
|
|
May 29 2006, 14:42
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата Скорее всего это произошло из за того, что вы использовали полную версию 'printf' с поддержкой чисел с плавающей точкой. BTW в makefile который генерирует mfile присутствуют специальные опциии линкера для printf и scanf *_LIB_MIN и *_LIB_FLOAT. Цитата 'vfprintf' написанна на С, пока не нашлось героя переписать ее на асме. smile.gif А никто не пробовал играться с С++ и его перегружаемыми cin/cout?
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
May 29 2006, 15:22
|
Частый гость
 
Группа: Свой
Сообщений: 172
Регистрация: 23-04-06
Пользователь №: 16 404

|
Я WinAVR использую года 2 и за это время сложилось достаточно положительное впечатление, но не без причуд. Похоже на уровне оптимизации WinAVR "не знает" что регистры 8 разрядные (разработчики портировали с другой архитектуры без существенной переработки, это моё личное мнение) Например возьмём убогий пример, и откоипилируем с опцией -O2, компилятор последний офиц WinAVR (а по сути здесь и не важно) Код uint8_t get_small_val() { return 0x8; } uint32_t test(uint32_t val) { uint8_t tmp = get_small_val(); val += (uint16_t)tmp << 8; return val; } то получим Код 00000284 <get_small_val>: 284: 88 e0 ldi r24, 0x08; 8 286: 90 e0 ldi r25, 0x00; 0 288: 08 95 ret
0000028a <test>: 28a: ef 92 push r14 28c: ff 92 push r15 28e: 0f 93 push r16 290: 1f 93 push r17 292: 7b 01 movw r14, r22 294: 8c 01 movw r16, r24 296: f6 df rcall .-20 ; 0x284 <get_small_val> 298: 99 27 eor r25, r25 29a: 98 2f mov r25, r24 29c: 88 27 eor r24, r24 29e: aa 27 eor r26, r26 2a0: bb 27 eor r27, r27 2a2: 8e 0d add r24, r14 2a4: 9f 1d adc r25, r15 2a6: a0 1f adc r26, r16 2a8: b1 1f adc r27, r17 2aa: bc 01 movw r22, r24 2ac: cd 01 movw r24, r26 2ae: 1f 91 pop r17 2b0: 0f 91 pop r16 2b2: ff 90 pop r15 2b4: ef 90 pop r14 2b6: 08 95 ret Во-первых функции которые возвращают uint8_t расширяются до int (строчка 286), причём как я смотрел совершенно не зависит от опций оптимизаций, конечно есть волшеьная опция -mint8 которая заставляет int принимать 8 бит, но при этом разработчики не гарантируют что все проекты откомпилируются с данной опцией. Во-вторых по согласованию распределения регистров с переменными, есть 3 типа, в стандартном, бедет всегда такая картина при передаче и возврашение 32 битного числа (292-294, 2aa-2ac). Причем если активно использовать 32 битные типы (да понимаю AVR не затачивался под 32) то таких констукций будет много. Причем нам явно младший байт после сдвига tmp прибавлять не надо, это очевидно. Но GCC этого "не прнимает". Причем если не написать (uint16_t) перед опеорацией сдвига, то компилятор расширит uint8_t до int, а int знаковое, и после сдвига явно сбросит 7 бит, чтобы расширение произошло "корректно". Есть ещё моного тонкостей на которые я наткнулся... Но вот если в проекте на так много 32битных вычисление то GCC может очень изащренно оптимизировать код, бывало когда я смотрел дамп аж сам биву давался как он налавкачел.. =) Ещё один огромнейший и неоспоримый плюс GCC это ассемблерные вставки. В них можно написать что-то типа макроса и компилятор будет сам выбирать какие регистры ему в конкретном случае лучше использовать (применительно к inline конструкциям) Код __asm__ __volatile__ ( "ldd %0, Z+14" "\r\n" "andi %0, 0x8C" "\r\n" "lsr %0" "\r\n" "mov __tmp_reg__, %0" "\r\n" "lsr %0" "\r\n" "swap __tmp_reg__" "\r\n" "or %0, __tmp_reg__" "\r\n" : "=r" (resp) : "z" (data) ); Вместо %0, в котором размещается resp, компилятор сам подставит необхолимые регистр, далее указываем компилятору чтобы в Z было data. Если бы в констукции использовался явно какой-то регистр (например после mul) то его нужно было бы включить в список экранируемых регистров ( : "r1" , после : "z" (data) ). При это генерируемы код, если правильно составить макрос булет 100% безопасным. Тема написания вставок вообще очень интересная, думаю общий обзор дал.. Я использую WinAVR на всех проектах с AVR, а где код сильно тормозил, использовую вставочку =)
|
|
|
|
|
May 29 2006, 17:05
|
Частый гость
 
Группа: Свой
Сообщений: 126
Регистрация: 1-01-06
Из: Украина, Киев
Пользователь №: 12 759

|
Цитата(Postoroniy_V @ May 29 2006, 16:54)  тоесть вы хотите сказать что в WInAvr не реализованы аналоги ваших - print_hex,print_num,print _str,print _pstr посредством родного (winavr) PRINTF? или то что они жрут много? Много жрут. Цитата(aesok @ May 29 2006, 17:27)  Скорее всего это произошло из за того, что вы использовали полную версию 'printf' с поддержкой чисел с плавающей точкой. О разных вариантах функции 'printf', а точнее 'vfprintf', посмотрите описание 'vfprintf'. Если вам не нужны числа с плавающей точкой используйте стандартную версию функции 'vfprintf'. Так и есть мне нужно было просчитывать несколько значений вытянутых из линии, результатом были числа с плавающей точкой (нужно было квадратный корень вычислять и выводить результат с точностью до 3 знаков после запятой). Все написал в лоб, без оптимизации.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|