|
|
  |
Перенос кода из под ИАРа на WinAVR, возникают некоторые вопросы... |
|
|
|
Nov 23 2008, 21:54
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(sonycman @ Nov 23 2008, 22:09)  А может кто подскажет, где поискать документацию по AVR GCC в виде PDF? А то не очень удобно пользоваться html версией...  А на родной страничке http://gcc.gnu.org/onlinedocs/ ссылки "also in PDF" - это разве не оно?
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 24 2008, 07:35
|
Профессионал
    
Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886

|
Цитата(ReAl @ Nov 24 2008, 00:43)  Это НЕ аналогичная штука. По ссылке, там где я пример с классом приводил, достаточно полный пример зачем это надо (конструкторы-деструкторы, пусть даже в виде прицепленных атрибутами функций). Может быть выход из середины блока, простой "переносимый" вариант при этом не отработает освобождение ( у вcякой задачи есть два решения - простое и правильное ;-) ) Код #include <avr/interrupt.h> #include <util/atomic.h>
uint8_t get_SREG_and_CLI() { uint8_t s = SREG; cli(); return s; }
#define ATOM() for(uint8_t __temp=get_SREG_and_CLI(),iter=0; iter<1; iter++,SREG=__temp) volatile uint8_t v; Мысль понял. а если так: Код define ATOM() for(uint8_t __temp=get_SREG_and_CLI(),iter=0; iter<1; iter++,SREG=__temp) for(int iter2=0; iter2 < 1; iter2++)
|
|
|
|
|
Nov 24 2008, 11:05
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Портировал я свою программу с IARа на GCC. Оптимизация максимальная по скорости у первого, и Os с ключами -mcall-prologues -fno-threadsafe-statics -ffunction-sections --gc-sections --relax у второго. В результате код IARа - 6 090 bytes of CODE memory + 493 bytes of DATA memory. Код GCC - Program: 7462 bytes + Data: 363 bytes. Код иара компактнее почти на 1,5 килобайта. Правда, некоторые функции "тюнингованы" специальными ключами (типа __z_x и т.д.) для оптимальной генерации. Добавление некоторых аттрибутов для GCC в аналогичных целях, к сожалению, не дало абсолютно никакого результата... На первый взгляд, скомпилированный GCC код весьма красив и аккуратен, за исключением излишней любви к LDS и STS, например: исходный текст: Код case USART_SEND_DATA_EX: length = 4 + 4 + 4 + 20; *pb++ = length + 1; *pb++ = command; *pb++ = temperature.cpu; *pb++ = temperature.gpu; *pb++ = temperature.amb; *pb++ = temperature.hdd; *pb++ = fan_speed[0]; *pb++ = fan_speed[1]; *pb++ = fan_speed[2]; *pb++ = fan_speed[3]; *pb++ = cpuFan.GetCurrentSpeed(); *pb++ = rearFan.GetCurrentSpeed(); *pb++ = sideFan.GetCurrentSpeed(); *pb++ = frontFan.GetCurrentSpeed(); *pb++ = cpuFan.RPMval[RPM_MIN]; *pb++ = cpuFan.RPMval[RPM_MED]; *pb++ = cpuFan.RPMval[RPM_MAX]; *pb++ = cpuFan.minTEMPval; *pb++ = cpuFan.maxTEMPval; *pb++ = rearFan.RPMval[RPM_MIN]; *pb++ = rearFan.RPMval[RPM_MED]; *pb++ = rearFan.RPMval[RPM_MAX]; *pb++ = rearFan.minTEMPval; *pb++ = rearFan.maxTEMPval; *pb++ = sideFan.RPMval[RPM_MIN]; *pb++ = sideFan.RPMval[RPM_MED]; *pb++ = sideFan.RPMval[RPM_MAX]; *pb++ = sideFan.minTEMPval; *pb++ = sideFan.maxTEMPval; *pb++ = frontFan.RPMval[RPM_MIN]; *pb++ = frontFan.RPMval[RPM_MED]; *pb++ = frontFan.RPMval[RPM_MAX]; *pb++ = frontFan.minTEMPval; *pb++ = frontFan.maxTEMPval; break; результат IARа: Код 105 case USART_SEND_DATA_EX: 106 length = 4 + 4 + 4 + 20; \ ??usartSendCommand_4: \ 000000C4 E280 LDI R24, 32 107 *pb++ = length + 1; \ 000000C6 E201 LDI R16, 33 \ 000000C8 930D ST X+, R16 108 *pb++ = command; \ 000000CA 934D ST X+, R20 109 *pb++ = temperature.cpu; \ 000000CC 9100.... LDS R16, temperature \ 000000D0 930D ST X+, R16 110 *pb++ = temperature.gpu; \ 000000D2 9100.... LDS R16, (temperature + 1) \ 000000D6 930D ST X+, R16 111 *pb++ = temperature.amb; \ 000000D8 9100.... LDS R16, (temperature + 2) \ 000000DC 930D ST X+, R16 112 *pb++ = temperature.hdd; \ 000000DE 9100.... LDS R16, (temperature + 3) \ 000000E2 930D ST X+, R16 113 *pb++ = fan_speed[0]; \ 000000E4 9100.... LDS R16, fan_speed \ 000000E8 930D ST X+, R16 114 *pb++ = fan_speed[1]; \ 000000EA 9100.... LDS R16, (fan_speed + 1) \ 000000EE 930D ST X+, R16 115 *pb++ = fan_speed[2]; \ 000000F0 9100.... LDS R16, (fan_speed + 2) \ 000000F4 930D ST X+, R16 116 *pb++ = fan_speed[3]; \ 000000F6 9100.... LDS R16, (fan_speed + 3) \ 000000FA 930D ST X+, R16 117 *pb++ = cpuFan.GetCurrentSpeed(); \ 000000FC .... LDI R16, LOW(cpuFan) \ 000000FE .... LDI R17, (cpuFan) >> 8 \ 00000100 .... RCALL ??GetCurrentSpeed \ 00000102 930D ST X+, R16 118 *pb++ = rearFan.GetCurrentSpeed(); \ 00000104 .... LDI R16, LOW(rearFan) \ 00000106 .... LDI R17, (rearFan) >> 8 \ 00000108 .... RCALL ??GetCurrentSpeed \ 0000010A 930D ST X+, R16 119 *pb++ = sideFan.GetCurrentSpeed(); \ 0000010C .... LDI R16, LOW(sideFan) \ 0000010E .... LDI R17, (sideFan) >> 8 \ 00000110 .... RCALL ??GetCurrentSpeed \ 00000112 930D ST X+, R16 120 *pb++ = frontFan.GetCurrentSpeed(); \ 00000114 .... LDI R16, LOW(frontFan) \ 00000116 .... LDI R17, (frontFan) >> 8 \ 00000118 .... RCALL ??GetCurrentSpeed \ 0000011A 930D ST X+, R16 121 *pb++ = cpuFan.RPMval[RPM_MIN]; \ 0000011C 9100.... LDS R16, (cpuFan + 5) \ 00000120 930D ST X+, R16 122 *pb++ = cpuFan.RPMval[RPM_MED]; \ 00000122 9100.... LDS R16, (cpuFan + 6) \ 00000126 930D ST X+, R16 123 *pb++ = cpuFan.RPMval[RPM_MAX]; \ 00000128 9100.... LDS R16, (cpuFan + 7) \ 0000012C 930D ST X+, R16 124 *pb++ = cpuFan.minTEMPval; \ 0000012E 9100.... LDS R16, (cpuFan + 8) \ 00000132 930D ST X+, R16 125 *pb++ = cpuFan.maxTEMPval; \ 00000134 9100.... LDS R16, (cpuFan + 9) \ 00000138 930D ST X+, R16 126 *pb++ = rearFan.RPMval[RPM_MIN]; \ 0000013A 9100.... LDS R16, (rearFan + 5) \ 0000013E 930D ST X+, R16 127 *pb++ = rearFan.RPMval[RPM_MED]; \ 00000140 9100.... LDS R16, (rearFan + 6) \ 00000144 930D ST X+, R16 128 *pb++ = rearFan.RPMval[RPM_MAX]; \ 00000146 9100.... LDS R16, (rearFan + 7) \ 0000014A 930D ST X+, R16 129 *pb++ = rearFan.minTEMPval; \ 0000014C 9100.... LDS R16, (rearFan + 8) \ 00000150 930D ST X+, R16 130 *pb++ = rearFan.maxTEMPval; \ 00000152 9100.... LDS R16, (rearFan + 9) \ 00000156 930D ST X+, R16 131 *pb++ = sideFan.RPMval[RPM_MIN]; \ 00000158 9100.... LDS R16, (sideFan + 5) \ 0000015C 930D ST X+, R16 132 *pb++ = sideFan.RPMval[RPM_MED]; \ 0000015E 9100.... LDS R16, (sideFan + 6) \ 00000162 930D ST X+, R16 133 *pb++ = sideFan.RPMval[RPM_MAX]; \ 00000164 9100.... LDS R16, (sideFan + 7) \ 00000168 930D ST X+, R16 134 *pb++ = sideFan.minTEMPval; \ 0000016A 9100.... LDS R16, (sideFan + 8) \ 0000016E 930D ST X+, R16 135 *pb++ = sideFan.maxTEMPval; \ 00000170 9100.... LDS R16, (sideFan + 9) \ 00000174 930D ST X+, R16 136 *pb++ = frontFan.RPMval[RPM_MIN]; \ 00000176 9100.... LDS R16, (frontFan + 5) \ 0000017A 930D ST X+, R16 137 *pb++ = frontFan.RPMval[RPM_MED]; \ 0000017C 9100.... LDS R16, (frontFan + 6) \ 00000180 930D ST X+, R16 138 *pb++ = frontFan.RPMval[RPM_MAX]; \ 00000182 9100.... LDS R16, (frontFan + 7) \ 00000186 930D ST X+, R16 139 *pb++ = frontFan.minTEMPval; \ 00000188 9100.... LDS R16, (frontFan + 8) \ 0000018C 930D ST X+, R16 140 *pb++ = frontFan.maxTEMPval; \ 0000018E 9100.... LDS R16, (frontFan + 9) \ 00000192 CF96 RJMP ??usartSendCommand_12 141 break; вполне прилично. А вот у GCC: Код case USART_SEND_DATA_EX: length = 4 + 4 + 4 + 20; *pb++ = length + 1; 153c: 81 e2 ldi r24, 0x21; 33 153e: 80 93 ed 01 sts 0x01ED, r24 *pb++ = command; 1542: 90 93 ee 01 sts 0x01EE, r25 *pb++ = temperature.cpu; 1546: 80 91 34 01 lds r24, 0x0134 154a: 80 93 ef 01 sts 0x01EF, r24 *pb++ = temperature.gpu; 154e: 80 91 35 01 lds r24, 0x0135 1552: 80 93 f0 01 sts 0x01F0, r24 *pb++ = temperature.amb; 1556: 80 91 36 01 lds r24, 0x0136 155a: 80 93 f1 01 sts 0x01F1, r24 *pb++ = temperature.hdd; 155e: 80 91 37 01 lds r24, 0x0137 1562: 80 93 f2 01 sts 0x01F2, r24 *pb++ = fan_speed[0]; 1566: 80 91 6f 01 lds r24, 0x016F 156a: 80 93 f3 01 sts 0x01F3, r24 *pb++ = fan_speed[1]; 156e: 80 91 70 01 lds r24, 0x0170 1572: 80 93 f4 01 sts 0x01F4, r24 *pb++ = fan_speed[2]; 1576: 80 91 71 01 lds r24, 0x0171 157a: 80 93 f5 01 sts 0x01F5, r24 *pb++ = fan_speed[3]; 157e: 80 91 72 01 lds r24, 0x0172 1582: 80 93 f6 01 sts 0x01F6, r24 *pb++ = cpuFan.GetCurrentSpeed(); 1586: 87 e3 ldi r24, 0x37; 55 1588: 92 e0 ldi r25, 0x02; 2 158a: 4c d7 rcall .+3736 ; 0x2424 <__data_load_end+0x6fe> 158c: 80 93 f7 01 sts 0x01F7, r24 *pb++ = rearFan.GetCurrentSpeed(); 1590: 81 e4 ldi r24, 0x41; 65 1592: 92 e0 ldi r25, 0x02; 2 1594: 47 d7 rcall .+3726 ; 0x2424 <__data_load_end+0x6fe> 1596: 80 93 f8 01 sts 0x01F8, r24 *pb++ = sideFan.GetCurrentSpeed(); 159a: 8b e4 ldi r24, 0x4B; 75 159c: 92 e0 ldi r25, 0x02; 2 159e: 42 d7 rcall .+3716 ; 0x2424 <__data_load_end+0x6fe> 15a0: 80 93 f9 01 sts 0x01F9, r24 *pb++ = frontFan.GetCurrentSpeed(); 15a4: 85 e5 ldi r24, 0x55; 85 15a6: 92 e0 ldi r25, 0x02; 2 15a8: 3d d7 rcall .+3706 ; 0x2424 <__data_load_end+0x6fe> 15aa: 80 93 fa 01 sts 0x01FA, r24 *pb++ = cpuFan.RPMval[RPM_MIN]; 15ae: 80 91 3c 02 lds r24, 0x023C 15b2: 80 93 fb 01 sts 0x01FB, r24 *pb++ = cpuFan.RPMval[RPM_MED]; 15b6: 80 91 3d 02 lds r24, 0x023D 15ba: 80 93 fc 01 sts 0x01FC, r24 *pb++ = cpuFan.RPMval[RPM_MAX]; 15be: 80 91 3e 02 lds r24, 0x023E 15c2: 80 93 fd 01 sts 0x01FD, r24 *pb++ = cpuFan.minTEMPval; 15c6: 80 91 3f 02 lds r24, 0x023F 15ca: 80 93 fe 01 sts 0x01FE, r24 *pb++ = cpuFan.maxTEMPval; 15ce: 80 91 40 02 lds r24, 0x0240 15d2: 80 93 ff 01 sts 0x01FF, r24 *pb++ = rearFan.RPMval[RPM_MIN]; 15d6: 80 91 46 02 lds r24, 0x0246 15da: 80 93 00 02 sts 0x0200, r24 *pb++ = rearFan.RPMval[RPM_MED]; 15de: 80 91 47 02 lds r24, 0x0247 15e2: 80 93 01 02 sts 0x0201, r24 *pb++ = rearFan.RPMval[RPM_MAX]; 15e6: 80 91 48 02 lds r24, 0x0248 15ea: 80 93 02 02 sts 0x0202, r24 *pb++ = rearFan.minTEMPval; 15ee: 80 91 49 02 lds r24, 0x0249 15f2: 80 93 03 02 sts 0x0203, r24 *pb++ = rearFan.maxTEMPval; 15f6: 80 91 4a 02 lds r24, 0x024A 15fa: 80 93 04 02 sts 0x0204, r24 *pb++ = sideFan.RPMval[RPM_MIN]; 15fe: 80 91 50 02 lds r24, 0x0250 1602: 80 93 05 02 sts 0x0205, r24 *pb++ = sideFan.RPMval[RPM_MED]; 1606: 80 91 51 02 lds r24, 0x0251 160a: 80 93 06 02 sts 0x0206, r24 *pb++ = sideFan.RPMval[RPM_MAX]; 160e: 80 91 52 02 lds r24, 0x0252 1612: 80 93 07 02 sts 0x0207, r24 *pb++ = sideFan.minTEMPval; 1616: 80 91 53 02 lds r24, 0x0253 161a: 80 93 08 02 sts 0x0208, r24 *pb++ = sideFan.maxTEMPval; 161e: 80 91 54 02 lds r24, 0x0254 1622: 80 93 09 02 sts 0x0209, r24 *pb++ = frontFan.RPMval[RPM_MIN]; 1626: 80 91 5a 02 lds r24, 0x025A 162a: 80 93 0a 02 sts 0x020A, r24 *pb++ = frontFan.RPMval[RPM_MED]; 162e: 80 91 5b 02 lds r24, 0x025B 1632: 80 93 0b 02 sts 0x020B, r24 *pb++ = frontFan.RPMval[RPM_MAX]; 1636: 80 91 5c 02 lds r24, 0x025C 163a: 80 93 0c 02 sts 0x020C, r24 *pb++ = frontFan.minTEMPval; 163e: 80 91 5d 02 lds r24, 0x025D 1642: 80 93 0d 02 sts 0x020D, r24 *pb++ = frontFan.maxTEMPval; 1646: 80 91 5e 02 lds r24, 0x025E 164a: 80 93 0e 02 sts 0x020E, r24 164e: 10 e2 ldi r17, 0x20; 32 1650: cf e0 ldi r28, 0x0F; 15 1652: d2 e0 ldi r29, 0x02; 2 1654: 08 c0 rjmp .+16 ; 0x1666 <_Z16usartSendCommandhPKvh+0x24e> break; жаль, не догадался компилер использовать указатель А зря. Итог - внушительный, в два раза больший, размер функции. Также в коде есть одна немаленькая inline функция, которая используется всего один раз (и то, понятно, инлайнится в тело вызывающей функции), но непонятно, почему остаётся её вторая копия? За короткое время знакомства с GCC понравилось: удобная реализация атомарности через макросы ATOMIC_BLOCK(), удобная обёртка для обработчиков прерываний вида ISR(vector_name){}. Что не понравилось: гиморрой с обработкой данных, расположенных во флеш - для их чтения необходимо использовать специальный макрос pgm_read_...(). В ИАРе достаточно объявить указатель типа __flash и можно работать с ним совершенно обычным образом Также не очень удобно каждый раз пользоваться PSTR() для обозначения in-line строк вида: printText(PSTR("some")). ИАР тут опять на высоте со своим __flash, так как подобная функция в нём декларируется как printText(char const __flash __flash * pointer), и вызов делается просто: printText("that`s cool")
|
|
|
|
|
Nov 24 2008, 11:35
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(sonycman @ Nov 24 2008, 14:05)  Также в коде есть одна немаленькая inline функция, которая используется всего один раз (и то, понятно, инлайнится в тело вызывающей функции), но непонятно, почему остаётся её вторая копия? Добавте при обьявлении этой функции static. Анатолий.
|
|
|
|
|
Nov 24 2008, 11:56
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(sonycman @ Nov 24 2008, 14:05)  и вызов делается просто: printText("that`s cool")  Я уже описал как добиться того же результата и в GCC (правда через макрос)... Повторяю: Код void lcd_print_str (unsigned char x, unsigned char y, char* p); // print RAM str void lcd_print_cstr (unsigned char x, unsigned char y, const char* p); // print FLASH str
#define lcd_print_PSTR(X,Y,LCDPSTR) lcd_print_cstr(X,Y,PSTR(LCDPSTR)) // put str in to FLASH and then print
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Nov 24 2008, 11:57
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(aesok @ Nov 24 2008, 15:35)  Добавте при обьявлении этой функции static.
Анатолий. У меня она так и объявлена: Код static inline void ReadButtons(void) __attribute__ ((always_inline));
static inline void ReadButtons(void) {} Результата нет - всё равно две копии
|
|
|
|
|
Nov 24 2008, 14:15
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Интересно, почему при делении на два не всегда используются оптимизации? Например: Код else if (percent == MED_AVAIL) percent = (RPMval[RPM_MAX] - RPMval[RPM_MIN]) / 2; 68c: 61 38 cpi r22, 0x81; 129 68e: 49 f4 brne .+18 ; 0x6a2 <_ZN13CFanRegulator8SetSpeedEhh+0x44> 690: 87 81 ldd r24, Z+7; 0x07 692: 90 e0 ldi r25, 0x00; 0 694: 25 81 ldd r18, Z+5; 0x05 696: 82 1b sub r24, r18 698: 91 09 sbc r25, r1 69a: 62 e0 ldi r22, 0x02; 2 69c: 70 e0 ldi r23, 0x00; 0 69e: 52 da rcall .-2908 ; 0xfffffb44 <__eeprom_end+0xff7efb1c> Видно, что для деления вызывается подпрограмма библиотеки. Почему не используется простой сдвиг?
|
|
|
|
|
Nov 24 2008, 14:22
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(sonycman @ Nov 24 2008, 17:15)  Интересно, почему при делении на два не всегда используются оптимизации? Видно, что для деления вызывается подпрограмма библиотеки. Почему не используется простой сдвиг?  Я обычно ручками пишу <<1 (2,3,etc) или >>1, не надеясь на компилятор. А вообще от флагов оптимизации зависит.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Nov 24 2008, 14:46
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(MrYuran @ Nov 24 2008, 18:22)  Я обычно ручками пишу <<1 (2,3,etc) или >>1, не надеясь на компилятор. А вообще от флагов оптимизации зависит. Точно, надо попробовать. С другой стороны, приятнее читать программу с обычными символами /, чем сдвигами. А где можно почитать про флаги для оптимизации? Я уже кучу флагов надобавлял (в сети понаходил). Вот они: -ffunction-sections -fno-inline-small-functions -fno-tree-scev-cprop -mcall-prologues и ключ -fno-inline-small-functions помог уменьшить размер кода на 400 байт (итого получилось 7110 байт). Ещё непонятно, почему компилер выдаёт предупреждения типа: only initialized variables can be placed into program memory area на все строки, подобные: Код static prog_char fntable[] PROGMEM = "!%`()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^";
|
|
|
|
|
Nov 24 2008, 15:58
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(sonycman @ Nov 24 2008, 17:46)  Ещё непонятно, почему компилер выдаёт предупреждения типа: only initialized variables can be placed into program memory area на все строки, подобные: Код static prog_char fntable[] PROGMEM = "!%`()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^"; prog_char ведь это уже: Код typedef char PROGMEM prog_char; для prog_char уже PROGMEM не требуется. Тут c С++ и prog_char какие-то нюансы всплывали... Попробуйте так: Код const char PROGMEM Vasja[] = "Vasja";
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Nov 24 2008, 16:05
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(demiurg_spb @ Nov 24 2008, 19:58)  prog_char ведь это уже: Код typedef char PROGMEM prog_char; второй раз после prog_char PROGMEM уже не требуется. Тут c С++ и prog_char какие-то нюансы всплывали... Попробуйте так: Код const char PROGMEM Vasja[] = "Vasja"; Спасибо, попробовал. Но всё осталось по прежнему...
|
|
|
|
|
Nov 24 2008, 19:07
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(sonycman @ Nov 24 2008, 14:57)  У меня она так и объявлена: Код static inline void ReadButtons(void) __attribute__ ((always_inline));
static inline void ReadButtons(void) {} Результата нет - всё равно две копии  Почитайте про static inline функции здесь: http://www.greenend.org.uk/rjk/2003/03/inline.htmlС ними есть какието тонкости, у меня сейчас нет времени вникать. Анатолий.
|
|
|
|
|
Nov 24 2008, 19:26
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(ARV @ Nov 24 2008, 20:40)  смутил ключик --gc-sections я всегда использую -Wl,-gc-sections возможно, это одно и то же, но на всякий случай обращу ваше внимание... Попробовал и с -gc-sections. Вроде без разницы. Полный текст командной строки линкера: Код Invoking: AVR C++ Linker avr-g++ -Wl,-Map,FanController.map,--cref --gc-sections --relax -mmcu=atmega88 Цитата(aesok @ Nov 24 2008, 23:07)  Почитайте про static inline функции здесь: http://www.greenend.org.uk/rjk/2003/03/inline.htmlС ними есть какието тонкости, у меня сейчас нет времени вникать. Анатолий. Спасибо, ознакомлюсь.  ЗЫ: Хм, написано, что инлайн функция не должна иметь статических переменных или обращаться к таковым... а у меня внутри есть статическая переменная. Может, дело в этом?
|
|
|
|
|
Nov 24 2008, 20:00
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(sonycman @ Nov 24 2008, 22:26)  Попробовал и с -gc-sections. Вроде без разницы. Полный текст командной строки линкера: Код Invoking: AVR C++ Linker avr-g++ -Wl,-Map,FanController.map,--cref --gc-sections --relax -mmcu=atmega88 если уж вы передаете разные параметры компоновщику, то указывайте тогда их все через запятую Код avr-g++ -Wl,-Map,FanController.map,--cref,-gc-sections --relax -mmcu=atmega88 и снова: почему у вас 2 минуса перед gc-sections? разве 2 или 1 - это все равно? и, при всем при том, где -ffunction-sections? они же в паре должны быть. я так понимаю: Код avr-g++ -ffunction-sections -Wl,-gc-sections,-Map,FanController.map,--cref --relax -mmcu=atmega88
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|