avr-gcc деструктивная оптимизация. Avr gcc оптимизация кода
c - avr-gcc деструктивная оптимизация
Я знаю, что мой ответ наступает через ~ 2 года после того, как этот вопрос был задан, но я верю, что до сих пор нет правильного, углубленного ответа.
Начнем с немного теории:
Когда вы вызываете GCC, он обычно выполняет предварительную обработку, компиляцию, сборку и компоновку. "Общие параметры" позволяют остановить этот процесс на промежуточной стадии. Например, опция -c говорит, что нельзя запускать компоновщик. Затем вывод состоит из объектных файлов, выводимых ассемблером.
Другие варианты передаются на один этап обработки. Некоторые параметры управляют препроцессором, а другие - самим компилятором. Однако другие опции управляют ассемблером и компоновщиком; большинство из них не описаны здесь, поскольку вам редко приходится использовать любой из них.
источник: GCC Online Docs
LDFLAGS
Дополнительные флаги для компиляторов, когда они должны ссылаться на компоновщик, ld, например -L. Библиотеки (-L foo) должны быть добавлены к переменной LDLIBS.
источник: GNU make Manual
Как вы можете видеть, это зависит от GCC (я буду называть это таким образом, чтобы отличать от реального компилятора, вы можете найти его как называемый C-компилятор или просто компилятор), какие параметры будут переданы каким инструментам, и кажется, что -On не передается компоновщику (вы можете проверить его, предоставив параметр -v для GCC). Таким образом, вызывать GCC без этой опции, когда предполагается только соединение, в порядке.
Реальная проблема заключается в том, что вы не предоставляете -mmcu=dev для GCC при связывании. Поэтому он не может найти правильный файл crt*.o (C RunTime) и сообщить компоновщику ссылку на него; ваше приложение заканчивается без кода инициализации.
Поэтому учтите, что вы должны включить -mmcu=dev в LDFLAGS или передать его в GCC независимо от того, что он предназначен (предварительная обработка/компиляция/сборка/привязка). Я уже видел пару make файлов без этой опции в LDFLAGS в Интернете, так что будьте осторожны.
Теперь пришло время для некоторой практики - предположив, что ваш источник находится в файле test.c, выполните следующие команды (в linux):
Я оставил только необходимые опции + -Wall, для ATtiny13a вам нужно -mmcu=attiny13a вместо -mmcu=attiny13.
Давайте взглянем на testOs_nodev.log и testOs_correct.log. Выполните следующую команду:
diff testOs_nodev.log testOs_correct.logи вы увидите что-то вроде:
2c2 < Reading specs from /usr/lib/gcc/avr/5.2.0/device-specs/specs-avr2 --- > Reading specs from /usr/lib/gcc/avr/5.2.0/device-specs/specs-attiny13a 10,12c10,12 < LIBRARY_PATH=/usr/lib/gcc/avr/5.2.0/:/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/ < COLLECT_GCC_OPTIONS='-v' '-o' 'testOs_nodev.elf' '-specs=device-specs/specs-avr2' < /usr/lib/gcc/avr/5.2.0/collect2 -plugin /usr/lib/gcc/avr/5.2.0/liblto_plugin.so \ -plugin-opt=/usr/lib/gcc/avr/5.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccqBjM6T.res \ -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lc \ -o testOs_nodev.elf -L/usr/lib/gcc/avr/5.2.0 -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib \ testOs.o --start-group -lgcc -lm -lc --end-group --- > LIBRARY_PATH=/usr/lib/gcc/avr/5.2.0/avr25/tiny-stack/:\ /usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack/:\ /usr/lib/gcc/avr/5.2.0/:/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/ > COLLECT_GCC_OPTIONS='-v' '-o' 'testOs_correct.elf' '-specs=device-specs/specs-attiny13a' \ '-mmcu=avr25' '-msp8' > /usr/lib/gcc/avr/5.2.0/collect2 -plugin /usr/lib/gcc/avr/5.2.0/liblto_plugin.so \ -plugin-opt=/usr/lib/gcc/avr/5.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccV919rY.res \ -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lc \ -plugin-opt=-pass-through=-lattiny13a -mavr25 -o testOs_correct.elf \ /usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack/crtattiny13a.o \ -L/usr/lib/gcc/avr/5.2.0/avr25/tiny-stack -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack \ -L/usr/lib/gcc/avr/5.2.0 -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib testOs.o \ --start-group -lgcc -lm -lc -lattiny13a --end-groupРазница в том, что без -mmcu=dev GCC по умолчанию использует файл avr2 specs и не связывает какой-либо файл CRT.
Изучите объектные файлы (*.o) и выходные файлы (*.elf) с помощью avr-objdump:
avr-objdump -xd testOs_nodev.elfВы заметите, что файлы *_nodev.elf не содержат правильной информации об архитектуре (avr вместо avr: 25) и никакого кода запуска (сравните testOs_correct.elf с testOs_nodev.elf). Секция кода представляет собой дословную копию того, что было поставлено в объектном файле.
Если какая-либо часть моей разработки кажется неясной или нуждается в дополнительном объяснении, не стесняйтесь спрашивать (комментировать).
qaru.site
c - Оптимизация этого кода (AVR)
У меня есть обработчик прерываний, который просто не работает достаточно быстро для того, что я хочу делать. В основном я использую его для генерации синусоидальных волн, выводя значение из таблицы поиска в ПОРТ на микроконтроллере AVR, но, к сожалению, этого не происходит достаточно быстро, чтобы я мог получить частоту волны, которую я хочу. Мне сказали, что я должен рассмотреть возможность его реализации в сборке, поскольку сборка, сгенерированная компилятором, может быть немного неэффективной и может быть оптимизирована, но после просмотра кода сборки я действительно не вижу, что я могу сделать лучше.
Это код C:
const uint8_t amplitudes60[60] = {127, 140, 153, 166, 176, 191, 202, 212, 221, 230, 237, 243, 248, 251, 253, 254, 253, 251, 248, 243, 237, 230, 221, 212, 202, 191, 179, 166, 153, 140, 127, 114, 101, 88, 75, 63, 52, 42, 33, 24, 17, 11, 6, 3, 1, 0, 1, 3, 6, 11, 17, 24, 33, 42, 52, 63, 75, 88, 101, 114}; const uint8_t amplitudes13[13] = {127, 176, 221, 248, 202, 153, 101, 52, 17, 1, 6, 33, 75}; const uint8_t amplitudes10[10] = {127, 176, 248, 202, 101, 52, 17, 1, 33, 75}; volatile uint8_t numOfAmps = 60; volatile uint8_t *amplitudes = amplitudes60; volatile uint8_t amplitudePlace = 0; ISR(TIMER1_COMPA_vect) { PORTD = amplitudes[amplitudePlace]; amplitudePlace++; if(amplitudePlace == numOfAmps) { amplitudePlace = 0; } }амплитуды и numOfAmps оба изменены другой подпрограммы обработки прерывания, которая работает гораздо медленнее, чем этот (он в основном выполняется для изменения частоты, которые играются). В конце дня я не буду использовать эти точные массивы, но это будет очень похоже на настройку. Скорее всего, у меня будет массив с 60 значениями, а другой - всего 30. Это потому, что я строю частотную подметальную машину, а на более низких частотах я могу позволить себе больше образцов, поскольку у меня больше часов, чтобы играть, но на более высоких частотах я очень привязан к времени.
Я действительно понимаю, что я могу заставить его работать с более низкой частотой дискретизации, но я не хочу проходить менее 30 выборок за период. Я не думаю, что указатель на массив делает его медленнее, поскольку сборка получает значение из массива, а сборка для получения значения из указателя на массив кажется одинаковым (что имеет смысл).
На самой высокой частоте, которую мне приходится производить, мне сказали, что я смогу заставить ее работать примерно с 30 образцами за период синусоидальной волны. На данный момент с 30 образцами, самый быстрый из них будет работать примерно на половину необходимой максимальной частоты, что, я думаю, означает, что мое прерывание должно работать в два раза быстрее.
Для этого кода при имитации требуется 65 циклов. Опять же, мне сказали, что я смогу довести его до 30 циклов в лучшем случае.
Это ASM код, созданный, с моим мышлением о том, что каждая строка делает рядом с ней:
ISR(TIMER1_COMPA_vect) { push r1 push r0 in r0, 0x3f ; save status reg push r0 eor r1, r1 ; generates a 0 in r1, used much later push r24 push r25 push r30 push r31 ; all regs saved PORTD = amplitudes[amplitudePlace]; lds r24, 0x00C8 ; r24 <- amplitudePlace I’m pretty sure lds r30, 0x00B4 ; these two lines load in the address of the lds r31, 0x00B5 ; array which would explain why it’d a 16 bit number ; if the atmega8 uses 16 bit addresses add r30, r24 ; aha, this must be getting the ADDRESS OF THE element adc r31, r1 ; at amplitudePlace in the array. ld r24, Z ; Z low is r30, makes sense. I think this is loading ; the memory located at the address in r30/r31 and ; putting it into r24 out 0x12, r24 ; fairly sure this is putting the amplitude into PORTD amplitudePlace++; lds r24, 0x011C ; r24 <- amplitudePlace subi r24, 0xFF ; subi is subtract imediate.. 0xFF = 255 so I’m ; thinking with an 8 bit value x, x+1 = x - 255; ; I might just trust that the compiler knows what it’s ; doing here rather than try to change it to an ADDI sts 0x011C, r24 ; puts the new value back to the address of the ; variable if(amplitudePlace == numOfAmps) lds r25, 0x00C8 ; r24 <- amplitudePlace lds r24, 0x00B3 ; r25 <- numOfAmps cp r24, r24 ; compares them brne .+4 ; 0xdc <__vector_6+0x54> { amplitudePlace = 0; sts 0x011C, r1 ; oh, this is why r1 was set to 0 earlier } } pop r31 ; restores the registers pop r30 pop r25 pop r24 pop r19 pop r18 pop r0 out 0x3f, r0 ; 63 pop r0 pop r1 retiМое другое мнение - возможно, утверждение if можно было бы избавиться, если бы я мог решить, как получить n-битовый int-тип данных в C, чтобы число обернулось, когда оно достигнет конца? Под этим я имею в виду, что у меня было бы 2^n - 1 выборки, а затем переменная амплитуды Place просто продолжала бы подсчитывать, так что, когда она достигнет 2^n, она переполнится и будет сброшена до нуля.
Я попытался смоделировать код без бит if, и в то время как он улучшил скорость, потребовалось всего около 10 циклов, так что это было около 55 циклов для одного исполнения, которое все еще недостаточно быстро, к сожалению поэтому мне нужно оптимизировать код еще больше, что сложно рассмотреть, так как это всего лишь 2 строки!
Моя единственная реальная мысль - посмотреть, могу ли я хранить статические таблицы поиска где-нибудь, для чего требуется меньше тактовых циклов? Инструкции LDS, которые он использует для доступа к массиву, я думаю, что все это занимает 2 цикла, поэтому я, вероятно, не собираюсь экономить много времени, но на этом этапе я готов попробовать что угодно.
Я полностью потерял место, куда идти. Я не вижу, как я мог бы сделать свой C-код более эффективным, но я только новичок в этом, поэтому я мог что-то упустить.Я бы хотел, чтобы какая-то помощь .. Я понимаю, что это довольно специфическая и связанная с этим проблема, и обычно я стараюсь избегать задавать такие вопросы здесь, но я долгое время работал над этим, Я действительно сделаю любую помощь, которую я смогу получить.
stackoverrun.com
avr-gcc: опции компилятора C для микроконтроллеров AVR | avr
В этой статье рассматриваются специфичные для AVR особенности использования инструментов GNU (перевод документации по компилятору C avr-gcc, ассемблеру avr-as, линкеру/компоновщику avr-ld). Обычно документация для этих инструментов довольно объемная, и поставляется в виде файлов texinfo. Опции командной строки более детально описаны в соответствующей документации.
[Опции компилятора C avr-gcc]
Опции, специфичные для разновидности микроконтроллера AVR (Machine-specific options)
Интерфейс компилятора C avr-gcc распознает опции, относящиеся к микроконтроллеру. В дополнение к макросам препроцессора, показанных в таблице далее, препроцессор также определяет макросы __AVR и __AVR__ (со значением 1), когда компилируется цель AVR (AVR target). Макросы AVR будут определены в стандартном режиме gnu89 (по умолчанию) и в режиме gnu99, но не будут определены в режимах c89 и c99.
-mmcu=architecture
В поле architecture опции закодирован тип микроконтроллера. Сейчас известны следующие архитектуры:
Архитектура | Макросы | Описание |
avr1 | __AVR_ARCH__=1__AVR_ASM_ONLY____AVR_2_BYTE_PC__ (2) | Простое ядро CPU, поддерживается только ассемблер |
avr2 | __AVR_ARCH__=2__AVR_2_BYTE_PC__ (2) | "Классическое" ядро CPU, до 8 килобайт ROM |
avr25 (1) | __AVR_ARCH__=25__AVR_HAVE_MOVW__ (1)__AVR_HAVE_LPMX__ (1)__AVR_2_BYTE_PC__ (2) | "Классическое" ядро CPU с поддержкой инструкций 'MOVW' и 'LPM Rx, Z[+]', до 8 килобайт ROM |
avr3 | __AVR_ARCH__=3__AVR_MEGA__ (5)__AVR_HAVE_JMP_CALL__ (4)__AVR_2_BYTE_PC__ (2) | "Классическое" ядро CPU, от 16 до 64 килобайт ROM |
avr31 | __AVR_ARCH__=31__AVR_MEGA__ (5)__AVR_HAVE_JMP_CALL__ (4)__AVR_HAVE_RAMPZ__ (4)__AVR_HAVE_ELPM__ (4)__AVR_2_BYTE_PC__ (2) | "Классическое" ядро CPU, 128 килобайт ROM |
avr35 (3) | __AVR_ARCH__=35__AVR_MEGA__ (5)__AVR_HAVE_JMP_CALL__ (4)__AVR_HAVE_MOVW__ (1)__AVR_HAVE_LPMX__ (1)__AVR_2_BYTE_PC__ (2) | "Классическое" ядро CPU с поддержкой инструкций 'MOVW' и 'LPM Rx, Z[+]', от 18 до 64 килобайт ROM |
avr4 | __AVR_ARCH__=4__AVR_ENHANCED__ (5)__AVR_HAVE_MOVW__ (1)__AVR_HAVE_LPMX__ (1)__AVR_HAVE_MUL__ (1)__AVR_2_BYTE_PC__ (2) | "Усиленное (enhanced)" ядро CPU, до 8 килобайт ROM |
avr5 | __AVR_ARCH__=5__AVR_MEGA__ (5)__AVR_ENHANCED__ (5)__AVR_HAVE_JMP_CALL__ (4)__AVR_HAVE_MOVW__ (1)__AVR_HAVE_LPMX__ (1)__AVR_HAVE_MUL__ (1)__AVR_2_BYTE_PC__ (2) | "Усиленное (enhanced)" ядро CPU, от 16 до 64 килобайт ROM |
avr51 | __AVR_ARCH__=51__AVR_MEGA__ (5)__AVR_ENHANCED__ (5)__AVR_HAVE_JMP_CALL__ (4)__AVR_HAVE_MOVW__ (1)__AVR_HAVE_LPMX__ (1)__AVR_HAVE_MUL__ (1)__AVR_HAVE_RAMPZ__ (4)__AVR_HAVE_ELPM__ (4)__AVR_HAVE_ELPMX__ (4)__AVR_2_BYTE_PC__ (2) | "Усиленное (enhanced)" ядро CPU, 128 килобайт ROM |
avr6 (2) | __AVR_ARCH__=6__AVR_MEGA__ (5)__AVR_ENHANCED__ (5)__AVR_HAVE_JMP_CALL__ (4)__AVR_HAVE_MOVW__ (1)__AVR_HAVE_LPMX__ (1)__AVR_HAVE_MUL__ (1)__AVR_HAVE_RAMPZ__ (4)__AVR_HAVE_ELPM__ (4)__AVR_HAVE_ELPMX__ (4)__AVR_3_BYTE_PC__ (2) | "Усиленное (enhanced)" ядро CPU, 256 килобайт ROM |
Примечания:(1) Появилось в GCC 4.2(2) Неофициальный патч для GCC 4.1(3) Появилось в GCC 4.2.3(4) Появилось в GCC 4.3(5) Устарело.
По умолчанию генерируется код для архитектуры avr2.
Внимание: когда используется опция -mmcu=architecture, но не опция -mmcu=MCU, подключаемый файл <avr/io.h> работать не будет, поскольку он не сможет выбрать определения (definitions) для конкретного типа микроконтроллера AVR.
-mmcu=MCU type
Сейчас avr-gcc понимает следующие типы микроконтроллеров (MCU types), перечисленные в таблице. В таблице также перечислены соответствующие типы архитектур для указанных микроконтроллеров, и показаны макросы препроцессора, которые будут заданы при использовании опции -mmcu.
Внимание, очень важно: тип микроконтроллера нужно указывать в нижнем регистре, т. е. маленькими буквами! Не надо умничать, и задавать что-то типа -mmcu=ATmega32U4, компилятор avr-gcc Вас не поймет и выдаст ошибку (надо было задать -mmcu=atmega32u4):
myfile.c:1:0: error: unrecognized argument to -mmcu= option: 'ATmega32U4' myfile.c:1:0: note: See --target-help for supported MCUsИтак, поддерживаемые имена MCU для опции -mmcu:
Архитектура | Имя MCU |
Макрос |
avr1 | at90s1200 | __AVR_AT90S1200__ |
attiny11 | __AVR_ATtiny11__ | |
attiny12 | __AVR_ATtiny12__ | |
attiny15 | __AVR_ATtiny15__ | |
attiny28 | __AVR_ATtiny28__ | |
avr2 | at90s2313 | __AVR_AT90S2313__ |
at90s2323 | __AVR_AT90S2323__ | |
at90s2333 | __AVR_AT90S2333__ | |
at90s2343 | __AVR_AT90S2343__ | |
attiny22 | __AVR_ATtiny22__ | |
attiny26 | __AVR_ATtiny26__ | |
at90s4414 | __AVR_AT90S4414__ | |
at90s4433 | __AVR_AT90S4433__ | |
at90s4434 | __AVR_AT90S4434__ | |
at90s8515 | __AVR_AT90S8515__ | |
at90c8534 | __AVR_AT90C8534__ | |
at90s8535 | __AVR_AT90S8535__ | |
avr2/avr25 (1) | at86rf401 | __AVR_AT86RF401__ |
ata6289 | __AVR_ATA6289__ | |
attiny13 | __AVR_ATtiny13__ | |
attiny13a | __AVR_ATtiny13A__ | |
attiny2313 | __AVR_ATtiny2313__ | |
attiny2313a | __AVR_ATtiny2313A__ | |
attiny24 | __AVR_ATtiny24__ | |
attiny24a | __AVR_ATtiny24A__ | |
attiny25 | __AVR_ATtiny25__ | |
attiny261 | __AVR_ATtiny261__ | |
attiny261a | __AVR_ATtiny261A__ | |
attiny4313 | __AVR_ATtiny4313__ | |
attiny43u | __AVR_ATtiny43U__ | |
attiny44 | __AVR_ATtiny44__ | |
attiny44a | __AVR_ATtiny44A__ | |
attiny45 | __AVR_ATtiny45__ | |
attiny461 | __AVR_ATtiny461__ | |
attiny461a | __AVR_ATtiny461A__ | |
attiny48 | __AVR_ATtiny48__ | |
attiny84 | __AVR_ATtiny84__ | |
attiny84a | __AVR_ATtiny84A__ | |
attiny85 | __AVR_ATtiny85__ | |
attiny861 | __AVR_ATtiny861__ | |
attiny861a | __AVR_ATtiny861A__ | |
attiny87 | __AVR_ATtiny87__ | |
attiny88 | __AVR_ATtiny88__ | |
avr3 | atmega603 | __AVR_ATmega603__ |
at43usb355 | __AVR_AT43USB355__ | |
avr3/avr31 (3) | atmega103 | __AVR_ATmega103__ |
at43usb320 | __AVR_AT43USB320__ | |
avr3/avr35 (2) | at90usb82 | __AVR_AT90USB82__ |
at90usb162 | __AVR_AT90USB162__ | |
atmega8u2 | __AVR_ATmega8U2__ | |
atmega16u2 | __AVR_ATmega16U2__ | |
atmega32u2 | __AVR_ATmega32U2__ | |
attiny167 | __AVR_ATtiny167__ | |
avr3 | at76c711 | __AVR_AT76C711__ |
avr4 | atmega48 | __AVR_ATmega48__ |
atmega48a | __AVR_ATmega48A__ | |
atmega48p | __AVR_ATmega48P__ | |
atmega8 | __AVR_ATmega8__ | |
atmega8515 | __AVR_ATmega8515__ | |
atmega8535 | __AVR_ATmega8535__ | |
atmega88 | __AVR_ATmega88__ | |
atmega88a | __AVR_ATmega88A__ | |
atmega88p | __AVR_ATmega88P__ | |
atmega88pa | __AVR_ATmega88PA__ | |
atmega8hva | __AVR_ATmega8HVA__ | |
at90pwm1 | __AVR_AT90PWM1__ | |
at90pwm2 | __AVR_AT90PWM2__ | |
at90pwm2b | __AVR_AT90PWM2B__ | |
at90pwm3 | __AVR_AT90PWM3__ | |
at90pwm3b | __AVR_AT90PWM3B__ | |
at90pwm81 | __AVR_AT90PWM81__ | |
avr5 | at90can32 | __AVR_AT90CAN32__ |
at90can64 | __AVR_AT90CAN64__ | |
at90pwm216 | __AVR_AT90PWM216__ | |
at90pwm316 | __AVR_AT90PWM316__ | |
at90scr100 | __AVR_AT90SCR100__ | |
at90usb646 | __AVR_AT90USB646__ | |
at90usb647 | __AVR_AT90USB647__ | |
at94k | __AVR_AT94K__ | |
atmega16 | __AVR_ATmega16__ | |
atmega161 | __AVR_ATmega161__ | |
atmega162 | __AVR_ATmega162__ | |
atmega163 | __AVR_ATmega163__ | |
atmega164a | __AVR_ATmega164A__ | |
atmega164p | __AVR_ATmega164P__ | |
atmega165 | __AVR_ATmega165__ | |
atmega165a | __AVR_ATmega165A__ | |
atmega165p | __AVR_ATmega165P__ | |
atmega168 | __AVR_ATmega168__ | |
atmega168a | __AVR_ATmega168A__ | |
atmega168p | __AVR_ATmega168P__ | |
atmega169 | __AVR_ATmega169__ | |
atmega169a | __AVR_ATmega169A__ | |
atmega169p | __AVR_ATmega169P__ | |
atmega169pa | __AVR_ATmega169PA__ | |
atmega16a | __AVR_ATmega16A__ | |
atmega16hva | __AVR_ATmega16HVA__ | |
atmega16hva2 | __AVR_ATmega16HVA2__ | |
atmega16hvb | __AVR_ATmega16HVB__ | |
atmega16hvbrevb | __AVR_ATmega16HVBREVB__ | |
atmega16m1 | __AVR_ATmega16M1__ | |
atmega16u4 | __AVR_ATmega16U4__ | |
atmega32 | __AVR_ATmega32__ | |
atmega323 | __AVR_ATmega323__ | |
atmega324a | __AVR_ATmega324A__ | |
atmega324p | __AVR_ATmega324P__ | |
atmega324pa | __AVR_ATmega324PA__ | |
atmega325 | __AVR_ATmega325__ | |
atmega325a | __AVR_ATmega325A__ | |
atmega325p | __AVR_ATmega325P__ | |
atmega3250 | __AVR_ATmega3250__ | |
atmega3250a | __AVR_ATmega3250A__ | |
atmega3250p | __AVR_ATmega3250P__ | |
atmega328 | __AVR_ATmega328__ | |
atmega328p | __AVR_ATmega328P__ | |
atmega329 | __AVR_ATmega329__ | |
atmega329a | __AVR_ATmega329A__ | |
atmega329p | __AVR_ATmega329P__ | |
atmega329pa | __AVR_ATmega329PA__ | |
atmega3290 | __AVR_ATmega3290__ | |
atmega3290a | __AVR_ATmega3290A__ | |
atmega3290p | __AVR_ATmega3290P__ | |
atmega32c1 | __AVR_ATmega32C1__ | |
atmega32hvb | __AVR_ATmega32HVB__ | |
atmega32hvbrevb | __AVR_ATmega32HVBREVB__ | |
atmega32m1 | __AVR_ATmega32M1__ | |
atmega32u4 | __AVR_ATmega32U4__ | |
atmega32u6 | __AVR_ATmega32U6__ | |
atmega406 | __AVR_ATmega406__ | |
atmega64 | __AVR_ATmega64__ | |
atmega640 | __AVR_ATmega640__ | |
atmega644 | __AVR_ATmega644__ | |
atmega644a | __AVR_ATmega644A__ | |
atmega644p | __AVR_ATmega644P__ | |
atmega644pa | __AVR_ATmega644PA__ | |
atmega645 | __AVR_ATmega645__ | |
atmega645a | __AVR_ATmega645A__ | |
atmega645p | __AVR_ATmega645P__ | |
atmega6450 | __AVR_ATmega6450__ | |
atmega6450a | __AVR_ATmega6450A__ | |
atmega6450p | __AVR_ATmega6450P__ | |
atmega649 | __AVR_ATmega649__ | |
atmega649a | __AVR_ATmega649A__ | |
atmega6490 | __AVR_ATmega6490__ | |
atmega6490a | __AVR_ATmega6490A__ | |
atmega6490p | __AVR_ATmega6490P__ | |
atmega649p | __AVR_ATmega649P__ | |
atmega64c1 | __AVR_ATmega64C1__ | |
atmega64hve | __AVR_ATmega64HVE__ | |
atmega64m1 | __AVR_ATmega64M1__ | |
m3000 | __AVR_M3000__ | |
avr5/avr51 (3) | at90can128 | __AVR_AT90CAN128__ |
at90usb1286 | __AVR_AT90USB1286__ | |
at90usb1287 | __AVR_AT90USB1287__ | |
atmega128 | __AVR_ATmega128__ | |
atmega1280 | __AVR_ATmega1280__ | |
atmega1281 | __AVR_ATmega1281__ | |
atmega1284p | __AVR_ATmega1284P__ | |
avr6 | atmega2560 | __AVR_ATmega2560__ |
atmega2561 | __AVR_ATmega2561__ | |
avrxmega2 | atxmega16a4 | __AVR_ATxmega16A4__ |
atxmega16d4 | __AVR_ATxmega16D4__ | |
atxmega32a4 | __AVR_ATxmega32A4__ | |
atxmega32d4 | __AVR_ATxmega32D4__ | |
avrxmega4 | atxmega64a3 | __AVR_ATxmega64A3__ |
atxmega64d3 | __AVR_ATxmega64D3__ | |
avrxmega5 | atxmega64a1 | __AVR_ATxmega64A1__ |
atxmega64a1u | __AVR_ATxmega64A1U__ | |
avrxmega6 | atxmega128a3 | __AVR_ATxmega128A3__ |
atxmega128d3 | __AVR_ATxmega128D3__ | |
atxmega192a3 | __AVR_ATxmega192A3__ | |
atxmega192d3 | __AVR_ATxmega192D3__ | |
atxmega256a3 | __AVR_ATxmega256A3__ | |
atxmega256a3b | __AVR_ATxmega256A3B__ | |
atxmega256d3 | __AVR_ATxmega256D3__ | |
avrxmega7 | atxmega128a1 | __AVR_ATxmega128A1__ |
atxmega128a1u | __AVR_ATxmega128A1U__ | |
avrtiny10 | attiny4 | __AVR_ATtiny4__ |
attiny5 | __AVR_ATtiny5__ | |
attiny9 | __AVR_ATtiny9__ | |
attiny10 | __AVR_ATtiny10__ | |
attiny20 | __AVR_ATtiny20__ | |
attiny40 | __AVR_ATtiny40__ |
Примечания:(1) Архитектура 'avr25' появилась в GCC 4.2(2) Архитектура 'avr35' появилась в GCC 4.2.3(3) Архитектуры 'avr31' и 'avr51' появились в in GCC 4.3
-morder1-morder2
Изменение порядка назначения регистров. По умолчанию порядок следующий:
r24, r25, r18, r19, r20, r21, r22, r23, r30, r31, r26, r27, r28, r29, r17, r16, r15, r14, r13, r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r0, r1
order1 использует следующий порядок:
r18, r19, r20, r21, r22, r23, r24, r25, r30, r31, r26, r27, r28, r29, r17, r16, r15, r14, r13, r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r0, r1
order2 использует следующий порядок:
r25, r24, r23, r22, r21, r20, r19, r18, r30, r31, r26, r27, r28, r29, r17, r16, r15, r14, r13, r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0
-mint8
Подразумевает, что тип int соответствует 8-битному целому (8-bit integer). Имейте в виду, что библиотекой avr-libc реально не поддерживается такой режим, так что он обычно не должен использоваться. По умолчанию в качестве int используются 16-битные целые числа (16-bit integers).
-mno-interrupts
Генерирует код, который меняет указатель стека (stack pointer) без запрета прерываний. Обычно состояние регистра статуса SREG (status register SREG) сохраняется во временном регистре, прерывания запрещаются в во время изменения указателя стека, и значение регистра SREG восстанавливается. Если указать эту опцию, также будет определен макрос препроцессора __NO_INTERRUPTS__ в значении 1.
-mcall-prologues
Для функции пролога/эпилога (function prologue/epilogue) будут использоваться подпрограммы (subroutines). Для сложных функций, которые используют много регистров (состояние которых нужно сохранить/восстановить на входе/выходе функции), эта опция будет экономить некоторое количество памяти кода программ взамен на некоторое снижение быстродействия (increase execution time).
-mtiny-stack
"Маленький стек". В указателе стека изменяются только младшие 8 бит.
-mno-tablejump
Эта опция устарела, используйте вместо неё опцию -fno-jump-tables.
-mshort-calls
Для микроконтроллеров с памятью размером >8K будут использованы команды перехода rjmp/rcall (имеющие ограниченный адресный диапазон). На архитектурах avr2 и avr4 (у которых размер памяти flash меньше 8 кбайт) это всегда имеет место. На архитектурах avr3 и avr5 вызовы подпрограмм и переходы по адресу, которые выходят за этот диапазон, будут по умолчанию использовать инструкции jmp/call, которые могут закрыть все адресное пространство, однако это потребует большего размера flash ROM и увеличивает время выполнения.
-mrtl
Будет выведен дамп внутреннего результата компиляции (internal compilation result, так называемый RTL) в комментариях к генерируемому коду ассемблера. Эта опция используется для отладки avr-gcc.
-msize
Будет выведен дамп адреса, размера, и относительной стоимости каждого оператора в комментариях к генерируемому коду ассемблера. Эта опция используется для отладки avr-gcc.
-mdeb
Генерирует вывод некоторой отладочной информации в поток stderr (обычно консоль).
Выборочное описание некоторых главных опций компилятора (general compiler options)
Следующие общие опции компилятора gcc (general gcc options) могут представлять некоторый интерес для пользователей AVR.
-On
Уровень оптимизации n. Увеличение числа n означает увеличение степени оптимизации, при этом уровень 0 полностью отключает оптимизацию (это является поведением по умолчанию, когда опция -O отсутствует). Специальная опция -Os означает включение всех оптимизаций -O2, которые не должны привести к увеличению размера кода.
Имейте в виду, что при использовании -O3 компилятор gcc будет пытаться перевести во встраиваемый код (inline) все "простые" функции. Для микроконтроллеров AVR (AVR target) это приведет к пагубному росту используемого пространства под код. Единственно полезная оптимизация, которая также включается в -O3, является -frename-registers, однако эту опцию лучше активировать отдельно вручную.
Если просто указать опцию -O, то это будет эквивалентно указанию опции -O1.
Имейте в виду, что полное выключение оптимизации предотвратит выдачу некоторых предупреждений, так как генерация их зависит от шагов анализа кода, которые будут выполняться только при оптимизации (нерабочий код unreachable code, неиспользуемые переменные unused variables). См. также соответствующий вопрос в FAQ [1], который относится к отладке оптимизированного кода.
-Wa,assembler-options-Wl,linker-options
Передать список опций ассемблеру и линкеру соответственно.
-g
Сгенерировать отладочную информацию (debugging information), которая может быть использована отладчиком avr-gdb.
-ffreestanding
Предполагается использование "freestanding" environment (независимое окружение), что соответствует стандарту C. Это отключит все автоматически генерируемые встроенные функции (которые все еще можно вызвать с префиксом __builtin_, предварительно добавленным к действительному имени функции). Это также заставляет компилятор не жаловаться, когда функция main() декларируется как возвращающая void, что больше соответствует среде выполнения микроконтроллера, где приложение не может предоставить обоснованный код возврата для среды выполнения (в большинстве случаев из функции main() никогда не происходит возврат). Однако это также отключит все оптимизации, обычно выполняемые компилятором, который предполагает, что функции, известные под определенным именем, ведут себя как описано в стандарте. Например, E. g., применение функции strlen() к литеральной строке обычно заставляет компилятор просто заменить вызов функции действующей длиной строки, тогда как с опцией -ffreestanding, во время выполнения всегда будет вызвана strlen().
-funsigned-char
Заменяет любой неквалифицированный специально тип char на unsigned char. Без этой опции по умолчанию char соответствует signed char.
-funsigned-bitfields
Заменяет любой неквалифицированный специально тип битовых полей (unqualified bitfield type) на беззнаковый (unsigned). По умолчанию он со знаком (signed).
-fshort-enums
Выделение перечислимому типу (enum) только такое количество байтов, сколько требуется для объявленного диапазона возможных значений. В частности, перечислимый тип (enum type) будет эквивалентен самому маленькому целочисленному типу, который имеет достаточный размер.
-fpack-struct
Плотная упаковка всех полей структуры (structure members) без пустого выравнивающего байтового пространства.
-fno-jump-tables
Не генерировать инструкций табличного перехода (tablejump instructions). По умолчанию таблицы переходов могут быть использованы для оптимизации операторов switch. Когда эта возможность выключена, вместо таблицы переходов будет использована последовательность команд сравнения. Таблицы переходов (Jump tables) обычно в среднем работают быстрее, однако в частности для операторов switch, которые должны делать переход по метке default, это может привести к некоторой бесполезной потере памяти кода (flash memory).
Внимание: инструкции табличного перехода tablejump используют команду ассемблера LPM для доступа к таблицам перехода. Всегда используйте -fno-jump-tables, если Вы компилируете бутлоадер (bootloader) для устройств, которые имеют больше 64 килобайта памяти кода.
[Опции для ассемблера avr-as]
Опции, специфичные для разновидности микроконтроллера AVR (Machine-specific assembler options)
-mmcu=architecture-mmcu=MCU name
Ассемблер avr-as понимает те же самые опции -mmcu=, используемые для avr-gcc. По умолчанию подразумевается архитектура avr2, однако это может быть отменено использованием подходящей псевдоинструкции .arch внутри исходного кода программы ассемблера.
-mall-opcodes
Выключает проверку кода операций (opcode checking) для действующего типа микроконтроллера (actual MCU type) и позволяет ассемблировать любой возможный для AVR код операции (opcode).
-mno-skip-bug
Отключает выдачу предупреждения, когда происходит попытка пропуска команды/инструкции, состоящей из 2 слов (2-word instruction) с командой CPSE/SBIC/SBIS/SBRC/SBRS. Раннее выпущенные микроконтроллеры AVR пострадали от аппаратной ошибки, из-за которой эти инструкции не могли быть должным образом пропущены.
-mno-wrap
Запрет использования повторения инструкций RJMP/RCALL для перехода по целевому адресу для микроконтроллеров, у которых память кода больше 8 килобайт.
--gstabs
Генерировать символы отладки .stabs для строк исходного кода ассемблера. Это позволит отладчику avr-gdb выполнять трассировку по исходному коду ассемблера. Эта опция не должна использоваться, когда ассемблируются исходные коды, которые были сгенерированы компилятором C; эти файлы уже содержат соответствующую информацию о номерах строк файлов исходного кода C.
-a[cdhlmns=file]
Включить листинг ассемблера. Подопции следующие:
c пропустить ложные условные выражения (omit false conditionals)d пропустить директивы отладки (omit debugging directives)h включить код высокого уровня (include high-level source)l включить код ассемблера (include assembly)m включить развертывание кода макросов (include macro expansions)n пропустить обработку форм (omit forms processing)s включить символы (include symbols)=file установить имя для файла листинга
Различные подопции можно комбинировать в один список опций -a; в этом случае =file должна быть последней в этом списке.
Примеры опций ассемблера, передаваемых через компилятор C
Помните, что опции ассемблера могут быть переданы через интерфейс (командную строку) компилятора C опцией -Wa (см. выше). Так, чтобы включить исходный код C в файл листинга foo.lst, когда компилируется foo.c, должна использоваться следующая командная строка:
$ avr-gcc -c -O foo.c -o foo.o -Wa,-ahls=foo.lst
Чтобы сначала передать ассемблерный файл через препроцессор C и дать команду ассемблеру сгенерировать отладочную информацию с номерами строк для него, нужно использовать следующую командную строку:
$ avr-gcc -c -x assembler-with-cpp -o foo.o foo.S -Wa,--gstabs
Имейте в виду, что системы Unix имеют чувствительную к регистру символов файловые системы (case-distinguishing file systems), так что указание имени файла с суффиксом (расширением) .S (буква S в верхнем регистре, upper-case) сделает автоматическое подразумевание компилятором -x assembler-with-cpp, в то время как использование .s передало бы файл напрямую ассемблеру (не будет производится препроцессинг). При переносе проектов с Linux на Windows (для компиляции через avr-gcc пакета WinAVR) регистр имен файлов служит частым источником неприятных ошибок, требующих ручной корректировки makefile.
[Управление линковщиком avr-ld]
Выбранные опции линкера
Так как для линкера avr-ld нет специфичных для микроконтроллера AVR опций (machine-specific options), то пользователя AVR может заинтересовать некоторое количество стандартных опций.
-lname
Указание на использование архива библиотеки с именем libname.a, и использования его для разрешения нераспознанных в настоящий момент символов. Файл библиотеки будет искаться по пути, состоящем из встроенных записей, указанных во время компиляции (например, /usr/local/avr/lib на системах Unix), возможно расширенных записями пути, указанными опциями -L (которые в командной строке должны предшествовать опциям -l).
-Lpath
Дополнительный путь для поиска архивных библиотек, запрашиваемых опциями -l.
--defsym symbol=expr
Определение глобального символа symbol, используя для его значения выражение expr.
-M
Напечатать карту линковки (linker map) в stdout (обычно консоль).
-Map mapfile
Вывести карту линковки (linker map) в файл mapfile.
--cref
Вывести таблицу перекрестных ссылок (cross reference table) в файл карты линковки map file (в случае наличия опции -Map), или в stdout (обычно консоль).
--section-start sectionname=org
Начать секцию с именем sectionname по абсолютному адресу org.
-Tbss org-Tdata org-Ttext org
Начать соответственно секцию bss, data, или text по адресу org.
-T scriptfile
Использование файла scriptfile в качестве скрипта линковки (linker script), который заменит скрипт линковки по умолчанию (default linker script). Скрипты линковки по умолчанию размещены в местах, которые зависят от системы (например /usr/local/avr/lib/ldscripts на системах Unix), и состоит из имени архитектуры AVR (от avr2 до avr5) с добавленным суффиксом .x. Скрипты линковки описывают, как различные секции памяти должны быть слинкованы друг с другом.
Передача опций линкера (компоновщика) через компилятор C
По умолчанию все неизвестные аргументы командной строки (unknown non-option arguments) компилятора avr-gcc (например, все аргументы имени файла, которые не имеют суффикса, поддерживаемого avr-gcc) передаются напрямую линкеру. Таким образом все файлы, оканчивающиеся на .o (объектные файлы) и на .a (объектные библиотеки) передаются линкеру.
Системные библиотеки обычно передаются не по их явном имени файла, а через применение опции -l, которая использует аббревиатурную форму имени файла архива (см. выше). Линкер avr-libc поставляется с двумя системными библиотеками libc.a и libm.a. В то время как стандартная библиотека libc.a будет всегда использоваться для поиска нераспознанных ссылок (unresolved references), когда линкер был запущен через командную строку компилятора C (например, всегда подразумевается неявная опция -lc), библиотека математики libm.a нуждается в явном запросе с использованием -lm. См. также запись в FAQ [2], в котором это объясняется подробнее.
По сложившейся традиции Makefiles использует макрос типа LDLIBS для отслеживания -l (и возможно -L) опций, которые должны быть добавлены только к командной строке компилятора C только тогда, когда линкуется конечный бинарный файл. В отличие от него макрос LDFLAGS используется для хранения других опций командной строки для компилятора C, которые должны быть переданы как опции во время стадии линковки. Разница состоит в том, какие опции будут помещены раньше в командную строку, в то время как библиотеки должны быть помещены в конец, так как они должны использоваться только для того, чтобы разрешить глобальные символы, которые все еще не разрешены в этой точке сборки.
Специфические флаги линкера можно передать компилятору C через командную строку с использованием опции -Wl (см. выше). Эта опция требует, чтобы не было никаких добавленных пробелов в этой опции линкера, в то время как некоторые опции линкера выше (наподобие -Map или --defsym) требуют пробелов. В этих ситуациях пробелы можно заменить эквивалентными знаками минуса. Например, следующая командная строка может использоваться для компиляции foo.c в исполняемый файл, и для получения карты линковки (link map), которая содержит список перекрестных ссылок (cross-reference list) в файле foo.map:
$ avr-gcc -O -o foo.out -Wl,-Map=foo.map -Wl,--cref foo.c
Альтернативно запятая как заполнитель будет заменена пробелом перед передачей прежде, чем будет передана компоновщику. Например, для устройства с внешней SRAM должна использоваться следующая командная строка, которая укажет компоновщику поместить сегмент данных по адресу 0x2000 в SRAM:
$ avr-gcc -mmcu=atmega128 -o foo.out -Wl,-Tdata,0x802000
См. документацию по секции данных (data section [3]) чтобы стало ясно, для чего нужно 0x800000 добавить к действительному значению адреса. Имейте в виду, что стек все еще останется во внутреннем RAM благодаря символу __stack, который предоставлен кодом запуска среды выполнения. Вероятно, что это все равно хорошая идея (так как доступ к внутренней RAM быстрее), и даже требуемый для некоторых ранних микроконтроллеров, которые имели аппаратные ошибки, из-за которых нельзя было использовать стек во внешнем RAM. Обратите внимание также, что куча heap для malloc() будет все еще размещена после всех переменных в секции данных (data section), так что в этой ситуации не будет коллизии stack/heap.
Чтобы поменять место размещения стека по умолчанию (в верхней части внутренней RAM), можно поменять значение символа __stack в командной строке компоновщика. Поскольку компоновщик обычно вызывается через командную строку компилятора (compiler frontend), этого можно добиться использованием опции компилятора наподобие
-Wl,--defsym=__stack=0x8003ff
Эта опция сделает код, который использует пространство для стека начиная с адреса RAM 0x3ff, вниз. Тогда доступный размер области стека зависит от нижней границы адреса внутреннего RAM для конкретной модели микроконтроллера AVR. Приложение (программа firmware AVR) обязана удостовериться, что стек не вырос за пределы границы, а также должна принять меры, чтобы стек не столкнулся с памятью, выделенной под переменные компилятором (секции .data и .bss).
[Ссылки]
1. Why does the PC randomly jump around when single-stepping through my program in avr-gdb? site:nongnu.org - почему счетчик команд PC случайно перепрыгивает по коду, когда выполняется пошаговое выполнение моей программы в avr-gdb?2. I get "undefined reference to..." for functions like "sin()" site:nongnu.org - я получил сообщение "undefined reference to..." для функции наподобие "sin()". 3. The .data Section site:nongnu.org - описание секции .data.
microsin.net
Портирование кода IAR на AVR GCC | avr
Язык C был изначально разработан с целью портирования кода. Имеется два вида портирования - перенос приложения на другую платформу (другая операционная система и/или процессор), и перенос приложения на другой компилятор. Портирование на другой компилятор может быть усложнено, когда программа относится ко встраиваемым системам (embedded system - приборы и автоматика, построенные на микроконтроллере). Например, стандарт языка C странным образом не определяет правила для декларирования и определения обработчиков прерывания (Interrupt Service Routine, ISR). Разные компиляторы это делают по-разному, и используют разные регистры микроконтроллера, а также используют нестандартные структуры языка. В этой статье описаны некоторые методы и указания по портированию программ для AVR (код firmware) с проприетарного компилятора IAR (IDE проектирования IAR Embedded Workbench for AVR) на тулчейн GNU (AVR GCC, на платформе Windows это пакет WinAVR). Имейте в виду, что статья может оказаться неполным набором указаний по такому портированию. Здесь и далее перевод руководства "Porting From IAR to AVR GCC" с сайта www.nongnu.org.
[Регистры AVR]
Заголовочные файлы, описывающие адресное пространство регистров ввода/вывода (IO header files), содержат мнемонические идентификаторы для всех имен регистров и имен бит для каждой конкретной модели микроконтроллера. IAR имеет индивидуальные файлы заголовков для каждого процессора, и они должны быть подключены к коду, когда в нем используются имена регистров. Название подключаемого заголовочного файла часто связано с моделью применяемого микроконтроллера. Например:
#include < iom169.h >Примечание: IAR не всегда использует те же самые имена регистров или бит, которые определены в даташите Atmel для микроконтроллеров AVR.
AVR GCC также имеет индивидуальные заголовочные файлы для каждого процессора. Однако реальный тип процессора указывается как опция командной строки компилятора (опция -mmcu=тип_микроконтроллера). Это часто делается через переменные makefile, как например MCU=atmega32. Такой вариант реализации позволяет Вам подключать всегда один и тот же заголовочный файл для любого типа процессора:
#include < avr/io.h >Примечание: прямой слеш в имени файла avr/io.h для разделения подпапок может использоваться и в дистрибутивах тулчейна для Windows, и это является рекомендуемым методом для подключения файла заголовка IO (несмотря на то, что в именах путей Windows изначально использовался обратный слеш \). Использование прямого слеша / предпочтительнее, так как обратный слеш используется для указания символов типа \0, \n, \r и т. п.
Компилятор (из опции командной строки -mcu) знает тип процессора, и может с помощью одного вышеуказанного файла подключить тот индивидуальный заголовочный файл IO, который действительно необходим. Достоинство такого метода в том, что Вам нужно указать только один стандартный заголовочный файл avr/io.h, и можете проще портировать Ваше приложение на другой тип процессора без необходимости корректировки всех модулей для подключения нового файла заголовка IO.
Тулчейн AVR (WinAVR + библиотека avr-libc) пытается точно придерживаться оригинальных названий регистров и бит, которые можно найти в даташите AVR. Может быть некоторое несоответствие между именами регистров в IO заголовках IAR по сравнению с IO заголовками AVR GCC.
[Обработчики прерывания ISR (Interrupt Service Routines)]
Как уже упоминалось, язык C не имеет собственного стандарта для определения ISR. Так что у каждого компилятора может оказаться свой собственный способ, как это нужно делать. IAR декларирует ISR так:
#pragma vector=TIMER0_OVF_vect __interrupt void MotorPWMBottom() { // код обработчика прерывания }В AVR GCC Вы декларируете ISR так:
ISR(PCINT1_vect) { // код обработчика прерывания }AVR GCC использует макрос для определения ISR. Этот макрос требует подключения файла заголовка:
#include < avr/interrupt.h >Имена разных векторов прерываний можно найти в индивидуальном файле заголовка IO, который должен подключаться через файл avr/io.h.
Примечание: имена векторов прерываний в AVR GCC были изменены для соответствия именам векторов в IAR. Это значительно упрощает портирование приложений с IAR на AVR GCC.
[Встроенные в язык подпрограммы, соответствующие командам ассемблера (Intrinsic Routines)]
IAR имеет некоторые подпрограммы intrinsic, такие как __enable_interrupts(), __disable_interrupts(), __watchdog_reset().
Эти функции intrinsic компилируются в специальные коды команд ассемблера AVR (SEI, CLI, WDR).
Имеются эквивалентные макросы в AVR GCC, однако все они не размещены в одном заголовочном файле. AVR GCC имеет sei() для замены __enable_interrupts() и cli() для __disable_interrupts(). Оба эти макроса размещены в файле заголовка avr/interrupts.h.
Также AVR GCC имеет макрос wdt_reset(), который заменяет __watchdog_reset(). Однако весь программный интерфейс сторожевого таймера (Watchdog Timer API) в AVR GCC можно найти в заголовочном файле avr/wdt.h.
[Переменные, размещенные в памяти Flash]
Язык C не был разработан для Гарвардской архитектуры процессоров, в которой заданы разные адресные пространства памяти (отдельно для кода и отдельно для переменных). Это означает, что нужны некоторые нестандартные пути для определения переменных, которые размещены в области памяти программ (для AVR это память Flash).
IAR использует нестандартное ключевое слово для декларирования переменной в памяти программ:
__flash int mydata[] = ....AVR GCC использует атрибуты переменной для достижения того же самого эффекта:
int mydata[] __attribute__((progmem))Примечание: см. руководство пользователя GCC (GCC User Manual) для дополнительной информации по атрибутам переменной.
Библиотека avr-libc предоставляет удобный макрос для атрибута переменной, размещаемой во Flash:
#include < avr/pgmspace.h > . . . int mydata[] PROGMEM = ....Примечание: макрос PROGMEM раскрывается в атрибут переменной progmem. Этот макрос требует подключения заголовочного файла avr/pgmspace.h. Это канонический метод для определения переменной в области памяти программ.
Чтобы прочитать данные из flash, используются макросы pgm_read_*(), также заданные в файле avr/pgmspace.h. В этом файле определены все макросы, которые нужны для работы с памятью программ (Flash).
Есть также метод для определения переменных в памяти программ, который является общим для двух компиляторов (IAR и AVR GCC). Создайте заголовочный файл, который имеет следующие определения:
#if defined(__ICCAVR__) // IAR C Compiler #define FLASH_DECLARE(x) __flash x #endif #if defined(__GNUC__) // GNU Compiler #define FLASH_DECLARE(x) x __attribute__((__progmem__)) #endifЭтот кусок кода проверяет версию компилятора (какой компилятор используется - IAR или GCC) и определяет макрос FLASH_DECLARE(x), который будет декларировать переменную в памяти программ, используя подходящий метод для каждого компилятора. Вы можете использовать его так:
FLASH_DECLARE(int mydata[] = ...);[Функция main() без возврата значения (Non-Returning main)]
Декларирование main() без кода возврата в IAR делается так:
__C_task void main(void) { // код программы }Чтобы выполнить то же самое в AVR GCC, сделайте следующее:
void main(void) __attribute__((noreturn)); void main(void) { // код программы }Примечание: см. руководство пользователя GCC (GCC User Manual) для дополнительной информации по атрибутам функции.
В AVR GCC нужно задать прототип для main(), где будет указано, что функция main() имеет тип "noreturn". Затем определите main() как обычно. Имейте в виду, что возвращаемый тип для функции main() теперь будет void.
[Резервирование регистров]
Компилятор IAR позволяет пользователю зарезервировать регистры общего назначения от r15 и ниже путем использования опций компилятора и следующих ключевых слов синтаксиса:
__regvar __no_init volatile unsigned int filteredTimeSinceCommutation @14;Эта строка блокирует r14 для исключительного использования в Вашем коде под именем переменной "filteredTimeSinceCommutation". Это означает, что компилятор не может использовать этот регистр для генерации общего кода.
Чтобы выполнить то же самое в AVR GCC, сделайте следующее:
register unsigned char counter asm("r3");Обычно таким способом можно использовать регистры от r2 до r15.
Примечание: не резервируйте r0 или r1, которые используются внутри компилятора для временного хранения данных и для нулевой величины. Резервирование регистров не рекомендуется в AVR GCC, так как это выводит эти регистры из-под контроля компилятора, что может ухудшить качество генерируемого объектного кода (который, кстати говоря, и так хуже кода, генерируемого компилятором IAR). Так что используйте резервирование регистров на собственный страх и риск.
microsin.net
Missed Optimization / AVR / Сообщество EasyElectronics.ru
Missed Optimization
Часто бывает удобно упаковать несколько логически связанных атрибутов в одну POD структуру и работать с ними, как с единым целым. К томе-же, если структура не большая и целиком помещается в регистры, то это должно быть еще и эффективно. Должно, но… Примеров таких структур много, это может быть точка:struct Point { int x; int y; }; Цвет пикселя:struct Color { uint8_t r, g, b; }; Или мы захотим сделать 3-х байтный указатель для AVR:struct Ptr24 { uint16_t low; uint8_t high; }; Давайте разберёмся как компиляторы работают с такими структурам. Разбираться будем на примерах для платформы AVR, так как она хорошо многим знакома и имеет относительно простой и понятный ассемблер, к тому-же выравнивание структур на этой платформе равно 1 и по идее не должно оказывать никакого влияния. Хотя всё описанное в равной степени относится и к другим платформам. Сравнивать будем традиционно компиляторы avr-gcc и IAR.Структура, которую будем использовать для наших тестов:
enum{ Size = 3}; typedef struct { uint8_t bytes[Size]; } Bar; Есть такой хитрый вид оптимизации SRA — scalar replacement of aggregates, при его использовании компилятор начинает рассматривать структуру не как просто кусок памяти определённого размера, а как сумму полей его составляющую. Это даёт компилятору возможность применить другие виды оптимизации, например, хранить структуру в регистрах, избавится от неиспользуемых полей, эффективно её копировать, и передавать как параметр в функции и т. д. Посмотрим как с этим обстоят дела у наших подопытных на практике.Тест 1. Глобальная переменная:Bar bar; void Foo1() { PORTA = bar.bytes[0]++; PORTB = bar.bytes[1]++; PORTC = bar.bytes[2]++; } Ассемблерный листинг: avr-gcc:void Foo1() { PORTA = bar.bytes[0]++; 92: lds r24, 0x0064 96: out 0x1b, r24 98: subi r24, 0xFF 9a: sts 0x0064, r24 PORTB = bar.bytes[1]++; 9e: lds r24, 0x0065 a2: out 0x18, r24 a4: subi r24, 0xFF a6: sts 0x0065, r24 PORTC = bar.bytes[2]++; aa: lds r24, 0x0066 ae: out 0x15, r24 b0: subi r24, 0xFF b2: sts 0x0066, r24 } b6: 08 95 retIAR for AVR:
void Foo1() { PORTA = bar.bytes[0]++; 00000000 LDI R30, LOW(bar) 00000002 LDI R31, (bar) >> 8 00000004 LD R16, Z 00000006 OUT 0x1B, R16 00000008 LD R16, Z 0000000A INC R16 0000000C ST Z, R16 PORTB = bar.bytes[1]++; 0000000E LDD R16, Z+1 00000010 OUT 0x18, R16 00000012 LDD R16, Z+1 00000014 INC R16 00000016 STD Z+1, R16 PORTC = bar.bytes[2]++; 00000018 LDD R16, Z+2 0000001A OUT 0x15, R16 0000001C LDD R16, Z+2 0000001E INC R16 00000020 STD Z+2, R16 } 00000022 RET Здесь всё впорядке, между компиляторями практически паритет — gcc проигрывает 2 байта памяти, но выигрывает 3 такта по скорости.Тест 2. Локальная переменная.void Foo2() { Bar bar = {{1, 2, 3}}; PORTA = bar.bytes[0]; PORTB = bar.bytes[1]; PORTC = bar.bytes[2]; } avr-gcc:void Foo2() { b8: ldi r24, 0x01 ba: out 0x1b, r24 PORTB = bar.bytes[1]; bc: ldi r24, 0x02 be: out 0x18, r24 PORTC = bar.bytes[2]; c0: ldi r24, 0x03 c2: out 0x15, r24 } c4: ret IAR:void Foo2() { 00000000 LDI R30, LOW(`?<Constant {{(uint8_t)'\\001', (uint8_t)'\\002',`) 00000002 LDI R31, (`?<Constant {{(uint8_t)'\\001', (uint8_t)'\\002',`) >> 8 00000004 LPM R16, Z+ 00000006 LPM R17, Z+ 00000008 LPM R18, Z PORTA = bar.bytes[0]; PORTB = bar.bytes[1]; PORTC = bar.bytes[2]; 00000000 OUT 0x1B, R16 00000002 OUT 0x18, R17 00000004 OUT 0x15, R18 00000006 RET } Оптимизатор GCC сработал как надо, а вот IAR перемудрил сам себя, сохранив инициализатор структуры в памяти программ, в данном случае это было не уместно.Тест 3. Передача структуры как параметр функции по значению.void Foo3(Bar i) { PORTA = i.bytes[0]; PORTB = i.bytes[1]; PORTC = i.bytes[2]; } Структура в данном случае должна передоваться в регистрах, что в принципе и происходит. Но вот тут у нас начинаются первые чудеса с avr-gcc:void Foo3(Bar i) { c6: push r29 c8: push r28 ca: r28, 0x3d ; 61 cc: in r29, 0x3e ; 62 ce: subi r28, 0x03 ; 3 d0: out 0x3d, r28 ; 61 PORTA = i.bytes[0]; d2: out 0x1b, r22 ; 27 PORTB = i.bytes[1]; d4: out 0x18, r23 ; 24 PORTC = i.bytes[2]; d6: out 0x15, r24 ; 21 } d8: adiw r28, 0x03 ; 3 da: out 0x3d, r28 ; 61 dc: pop r28 de: pop r29 e0: ret Как видно он совершенно непонятно зачем создал кадр стека и выделил в нем место на 3 байта — как раз размер нашей структуры, но так им и не воспользовался. IAR в дела обстоят гораздо лучше и он генерирует вполне годный код:void Foo3(Bar i) { PORTA = i.bytes[0]; 00000000 OUT 0x1B, R16 PORTB = i.bytes[1]; 00000002 OUT 0x18, R17 PORTC = i.bytes[2]; 00000004 OUT 0x15, R18 } 00000006 RET Тест 4. Передача структуры как параметр функции по значению и ее возврат по значению.Bar Foo4(Bar i) { i.bytes[2] += 10; return i; } Чем дальше в лес, тем интереснее… avr-gcc чудит еще больше, генерируя совсем непотребный (хотя рабочий) код: Bar Foo4(Bar i) { e2: push r29 e4: push r28 e6: in r28, 0x3d ; 61 e8: in r29, 0x3e ; 62 ea: subi r28, 0x06 ; 6 ec: out 0x3d, r28 ; 61 ee: std Y+4, r22 ; 0x04 f0: std Y+5, r23 ; 0x05 i.bytes[2] += 10; return i; f2: subi r24, 0xF6 ; 246 f4: std Y+6, r24 ; 0x06 f6: movw r26, r28 f8: adiw r26, 0x01 ; 1 fa: movw r30, r28 fc: adiw r30, 0x04 ; 4 fe: ldi r24, 0x03 ; 3 100: ld r0, Z+ 102: st X+, r0 104: subi r24, 0x01 ; 1 106: brne .-8 ; 0x100 <Foo4+0x1e> 108: ldd r22, Y+1 ; 0x01 10a: ldd r23, Y+2 ; 0x02 } 10c: ldd r24, Y+3 ; 0x03 10e: ldi r25, 0x00 ; 0 110: adiw r28, 0x06 ; 6 112: out 0x3d, r28 ; 61 114: pop r28 116: pop r29 118: ret Здесь GCC инициализировал кадр стека выделил место под две структуры. Скопировал в первый буфер значения параметра из регистров, модифицировав один нужный байт, потом скопировал первый буфер во второй. После чего извлёк значение из стека опять в регистры, да, да, в те-же в которых оно и было, при вызове функции, вернул стек на место и вышел из функции. Жесть! IAR тут повел себя лучше, но не на много. Он скопировал параметры в стек только один раз :) Ну и за счёт того, что в IAR отдельный стек данных и он уже заранее подготовлен, код получается покомпактней. Но всё равно, зачем копировать параметр в стек и тутже извлекать его обратно?!!!Bar Foo4(Bar i) { 00000000 SBIW R29:R28, 3 00000002 ST Y, R16 00000004 STD Y+1, R17 00000006 STD Y+2, R18 i.bytes[2] += 10; 00000008 LDD R16, Y+2 0000000A SUBI R16, 246 0000000C STD Y+2, R16 return i; 0000000E LD R16, Y 00000010 LDD R18, Y+2 00000012 ADIW R29:R28, 3 00000014 RET } Это явный баг в оптимизаторах обоих компиляторах, только у IAR он несколько нивелирован отдельным стеком данных. В GCC этот баг проявляется на всех платформах, начиная на x86 и заканчивая ARM и AVR и отмечен в баг-трекере более десяти раз под разными названиями. Присутствует начиная с GCC 4.2. и по сей день в GCC 4.6. Причем на платформах чувствительных к выравниванию данных, например на ARM, помимо игрищь со стеком начинаются еще и пляски с выравниванием данных.И самое интересное, размер структуры в самом начале, я выбрал равным 3 байтам не случайно, если его сделать кратным слову, или двойному слову, например, 2, 4 или 8 байт, то все эти извращения волшебным образом исчезают и GCC начинает генерировать совершенно идеальный код, вида:
Bar Foo4(Bar i) { b8: subi r24, 0xF6 ; 246 ba: ret } В IAR-е размер структуры и выравнивание никак качественно не влияют на генерируемый код, и он упорно продолжает складывать структуру в стек.Выводы:
1) Не доверяйте компиляторам, всегда проверяйте, что он там нагенерировал. 2) Выравнивайте структуры по размеру слова или двойного слова, даже на архитектурах, теоретически не чувствительных к выравниванию.we.easyelectronics.ru
WinAVR. Использование инструментов GNU #01. Опции C-компилятора AVR-GCC
Сохранить или поделиться
Это краткая сводка характерных для AVR аспектов использования инструментов GNU. Обычно общая документация этих инструментов довольно велика. В этом разделе руководства детально раскрыты опции командной строки.
Опции C-компилятора avr-gcc
Опции для платформы AVR
Следующие характерные для платформы опции распознаются препроцессором C-компилятора. В дополнение к макросам препроцессора, показанным в таблице ниже, препроцессор будет определять макросы __AVR и __AVR__ (в значение 1), когда компилирует для AVR. Макрос AVR будет также определятся, когда используется стандарт уровней gnu89 (по умолчанию) и gnu99, но не c89 и c99.
-mmcu=архитектураКомпилирует код для архитектуры.В настоящее время известны следующие архитектуры:
avr1 | __AVR_ARCH__=1__AVR_ASM_ONLY____AVR_2_BYTE_PC__ [2] | “простое” ядро, поддерживает только ассемблер |
avr2 | __AVR_ARCH__=2__AVR_2_BYTE_PC__ [2] | “классическое” ядро с размером программной области памяти до 8 кбайт |
avr25 [1] | __AVR_ARCH__=25__AVR_HAVE_MOVW__ [1]__AVR_HAVE_LPMX__ [1]__AVR_2_BYTE_PC__ [2] | “классическое” ядро с инструкциями ‘MOVW’ и ‘LPM Rx, Z[+]’ и размером программной области памяти до 8 кбайт |
avr3 | __AVR_ARCH__=3__AVR_MEGA__ [5]__AVR_HAVE_JMP_CALL__ [4]__AVR_2_BYTE_PC__ [2] | “классическое” ядро с размером программной области памяти от 16 до 64 кбайт |
avr31 | __AVR_ARCH__=31__AVR_MEGA____AVR_HAVE_RAMPZ__ [4]__AVR_HAVE_ELPM__ [4]__AVR_2_BYTE_PC__ [2] | “классическое” ядро с размером программной области памяти 128 кбайт |
avr35 [3] | __AVR_ARCH__=35__AVR_MEGA__ [5]__AVR_HAVE_JMP_CALL__ [4]__AVR_HAVE_MOVW__ [1]__AVR_HAVE_LPMX__ [1]__AVR_2_BYTE_PC__ [2] | “классическое” ядро с инструкциями ‘MOVW’ и ‘LPM Rx, Z[+]’ и размером программной области памяти от 16 до 64 кбайт |
avr4 | __AVR_ARCH__=4__AVR_ENHANCED__ [5]__AVR_HAVE_MOVW__ [1]__AVR_HAVE_LPMX__ [1]__AVR_HAVE_MUL__ [1]__AVR_2_BYTE_PC__ [2] | “расширенное” ядро с размером программной области памяти до 8 кбайт |
avr5 | __AVR_ARCH__=5__AVR_MEGA__ [5]__AVR_ENHANCED__ [5]__AVR_HAVE_JMP_CALL__ [4]__AVR_HAVE_MOVW__ [1]__AVR_HAVE_LPMX__ [1]__AVR_HAVE_MUL__ [1]__AVR_2_BYTE_PC__ [2] | “расширенное” ядро с размером программной области памяти от 16 до 64 кбайт |
avr51 | __AVR_ARCH__=51__AVR_MEGA____AVR_ENHANCED____AVR_HAVE_MOVW__ [1]__AVR_HAVE_LPMX__ [1]__AVR_HAVE_MUL__ [1]__AVR_HAVE_RAMPZ__ [4]__AVR_HAVE_ELPM__ [4]__AVR_HAVE_ELPMX__ [4]__AVR_2_BYTE_PC__ [2] | “расширенное” ядро с размером программной области памяти 128 кбайт |
avr6 [2] | __AVR_ARCH__=6__AVR_MEGA__ [5]__AVR_ENHANCED__ [5]__AVR_HAVE_JMP_CALL__ [4]__AVR_HAVE_MOVW__ [1]__AVR_HAVE_LPMX__ [1]__AVR_HAVE_MUL__ [1]__AVR_HAVE_RAMPZ__ [4]__AVR_HAVE_ELPM__ [4]__AVR_HAVE_ELPMX__ [4]__AVR_3_BYTE_PC__ [2] | “расширенное” ядро с размером программной области памяти 256 кбайт |
- [1] Начиная с GCC 4.2
- [2] Неофициальный патч для GCC 4.1
- [3] Начиная с GCC 4.2.3
- [4] Начиная с GCC 4.3
- [5] Устаревшее.
По умолчанию код генерируется для архитектуры avr2.
Обратите внимание, что, когда используется -mmcu=архитектура, а не -mmcu=тип МК, присоединяемый файл <avr/io.h> не сможет работать до тех пор, пока не сможет решить, описание какого устройства выбрать.
-mmcu=тип МКЗадает тип МК.В настоящее время avr-gcc понимает следующие типы микроконтроллеров. Таблица сопоставляет их именам архитектур, передаваемых avr-gcc, и показывает обозначение препроцессора объявляемое опцией -mmcu.
avr1 | at90s1200 | __AVR_AT90S1200__ |
avr1 | attiny11 | __AVR_ATtiny11__ |
avr1 | attiny12 | __AVR_ATtiny12__ |
avr1 | attiny15 | __AVR_ATtiny15__ |
avr1 | attiny28 | __AVR_ATtiny28__ |
avr2 | at90s2313 | __AVR_AT90S2313__ |
avr2 | at90s2323 | __AVR_AT90S2323__ |
avr2 | at90s2333 | __AVR_AT90S2333__ |
avr2 | at90s2343 | __AVR_AT90S2343__ |
avr2 | attiny22 | __AVR_ATtiny22__ |
avr2 | attiny26 | __AVR_ATtiny26__ |
avr2 | at90s4414 | __AVR_AT90S4414__ |
avr2 | at90s4433 | __AVR_AT90S4433__ |
avr2 | at90s4434 | __AVR_AT90S4434__ |
avr2 | at90s8515 | __AVR_AT90S8515__ |
avr2 | at90c8534 | __AVR_AT90C8534__ |
avr2 | at90s8535 | __AVR_AT90S8535__ |
avr2/avr25 [1] | at86rf401 | __AVR_AT86RF401__ |
avr2/avr25 [1] | ata6289 | __AVR_ATA6289__ |
avr2/avr25 [1] | attiny13 | __AVR_ATtiny13__ |
avr2/avr25 [1] | attiny13a | __AVR_ATtiny13A__ |
avr2/avr25 [1] | attiny2313 | __AVR_ATtiny2313__ |
avr2/avr25 [1] | attiny24 | __AVR_ATtiny24__ |
avr2/avr25 [1] | attiny25 | __AVR_ATtiny25__ |
avr2/avr25 [1] | attiny261 | __AVR_ATtiny261__ |
avr2/avr25 [1] | attiny43u | __AVR_ATtiny43U__ |
avr2/avr25 [1] | attiny44 | __AVR_ATtiny44__ |
avr2/avr25 [1] | attiny45 | __AVR_ATtiny45__ |
avr2/avr25 [1] | attiny461 | __AVR_ATtiny461__ |
avr2/avr25 [1] | attiny48 | __AVR_ATtiny48__ |
avr2/avr25 [1] | attiny84 | __AVR_ATtiny84__ |
avr2/avr25 [1] | attiny85 | __AVR_ATtiny85__ |
avr2/avr25 [1] | attiny861 | __AVR_ATtiny861__ |
avr2/avr25 [1] | attiny87 | __AVR_ATtiny87__ |
avr2/avr25 [1] | attiny88 | __AVR_ATtiny88__ |
avr3 | atmega603 | __AVR_ATmega603__ |
avr3 | at43usb355 | __AVR_AT43USB355__ |
avr3/avr31 [3] | atmega103 | __AVR_ATmega103__ |
avr3/avr31 [3] | at43usb320 | __AVR_AT43USB320__ |
avr3/avr35 [2] | at90usb82 | __AVR_AT90USB82__ |
avr3/avr35 [2] | at90usb162 | __AVR_AT90USB162__ |
avr3/avr35 [2] | attiny167 | __AVR_ATtiny167__ |
avr3 | at76c711 | __AVR_AT76C711__ |
avr4 | atmega48 | __AVR_ATmega48__ |
avr4 | atmega48p | __AVR_ATmega48P__ |
avr4 | atmega8 | __AVR_ATmega8__ |
avr4 | atmega8515 | __AVR_ATmega8515__ |
avr4 | atmega8535 | __AVR_ATmega8535__ |
avr4 | atmega88 | __AVR_ATmega88__ |
avr4 | atmega88p | __AVR_ATmega88P__ |
avr4 | atmega8hva | __AVR_ATmega8HVA__ |
avr4 | at90pwm1 | __AVR_AT90PWM1__ |
avr4 | at90pwm2 | __AVR_AT90PWM2__ |
avr4 | at90pwm2b | __AVR_AT90PWM2B__ |
avr4 | at90pwm3 | __AVR_AT90PWM3__ |
avr4 | at90pwm3b | __AVR_AT90PWM3B__ |
avr4 | at90pwm81 | __AVR_AT90PWM81__ |
avr5 | at90pwm216 | __AVR_AT90PWM216__ |
avr5 | at90pwm316 | __AVR_AT90PWM316__ |
avr5 | at90can32 | __AVR_AT90CAN32__ |
avr5 | at90can64 | __AVR_AT90CAN64__ |
avr5 | at90usb646 | __AVR_AT90USB646__ |
avr5 | at90usb647 | __AVR_AT90USB647__ |
avr5 | atmega16 | __AVR_ATmega16__ |
avr5 | atmega161 | __AVR_ATmega161__ |
avr5 | atmega162 | __AVR_ATmega162__ |
avr5 | atmega163 | __AVR_ATmega163__ |
avr5 | atmega164p | __AVR_ATmega164P__ |
avr5 | atmega165 | __AVR_ATmega165__ |
avr5 | atmega165p | __AVR_ATmega165P__ |
avr5 | atmega168 | __AVR_ATmega168__ |
avr5 | atmega168p | __AVR_ATmega168P__ |
avr5 | atmega169 | __AVR_ATmega169__ |
avr5 | atmega169p | __AVR_ATmega169P__ |
avr5 | atmega16hva | __AVR_ATmega16HVA__ |
avr5 | atmega16m1 | __AVR_ATmega16M1__ |
avr5 | atmega16u4 | __AVR_ATmega16U4__ |
avr5 | atmega32 | __AVR_ATmega32__ |
avr5 | atmega323 | __AVR_ATmega323__ |
avr5 | atmega324p | __AVR_ATmega324P__ |
avr5 | atmega325 | __AVR_ATmega325__ |
avr5 | atmega325p | __AVR_ATmega325P__ |
avr5 | atmega3250 | __AVR_ATmega3250__ |
avr5 | atmega3250p | __AVR_ATmega3250P__ |
avr5 | atmega328p | __AVR_ATmega328P__ |
avr5 | atmega329 | __AVR_ATmega329__ |
avr5 | atmega329p | __AVR_ATmega329P__ |
avr5 | atmega3290 | __AVR_ATmega3290__ |
avr5 | atmega3290p | __AVR_ATmega3290P__ |
avr5 | atmega32c1 | __AVR_ATmega32C1__ |
avr5 | atmega32hvb | __AVR_ATmega32HVB__ |
avr5 | atmega32m1 | __AVR_ATmega32M1__ |
avr5 | atmega32u4 | __AVR_ATmega32U4__ |
avr5 | atmega32u6 | __AVR_ATmega32U6__ |
avr5 | atmega406 | __AVR_ATmega406__ |
avr5 | atmega64 | __AVR_ATmega64__ |
avr5 | atmega640 | __AVR_ATmega640__ |
avr5 | atmega644 | __AVR_ATmega644__ |
avr5 | atmega644p | __AVR_ATmega644P__ |
avr5 | atmega645 | __AVR_ATmega645__ |
avr5 | atmega6450 | __AVR_ATmega6450__ |
avr5 | atmega649 | __AVR_ATmega649__ |
avr5 | atmega6490 | __AVR_ATmega6490__ |
avr5 | atmega64c1 | __AVR_ATmega64C1__ |
avr5 | atmega64m1 | __AVR_ATmega64M1__ |
avr5 | at94k | __AVR_AT94K__ |
avr5 | at90scr100 | __AVR_AT90SCR100__ |
avr5/avr51 [3] | atmega128 | __AVR_ATmega128__ |
avr5/avr51 [3] | atmega1280 | __AVR_ATmega1280__ |
avr5/avr51 [3] | atmega1281 | __AVR_ATmega1281__ |
avr5/avr51 [3] | atmega1284p | __AVR_ATmega1284P__ |
avr5/avr51 [3] | at90can128 | __AVR_AT90CAN128__ |
avr5/avr51 [3] | at90usb1286 | __AVR_AT90USB1286__ |
avr5/avr51 [3] | at90usb1287 | __AVR_AT90USB1287__ |
avr6 | atmega2560 | __AVR_ATmega2560__ |
avr6 | atmega2561 | __AVR_ATmega2561__ |
avrxmega2 | atxmega16a4 | __AVR_ATxmega16A4__ |
avrxmega2 | atxmega16d4 | __AVR_ATxmega16D4__ |
avrxmega2 | atxmega32d4 | __AVR_ATxmega32D4__ |
avrxmega3 | atxmega32a4 | __AVR_ATxmega32A4__ |
avrxmega4 | atxmega64a3 | __AVR_ATxmega64A3__ |
avrxmega5 | atxmega64a1 | __AVR_ATxmega64A1__ |
avrxmega6 | atxmega128a3 | __AVR_ATxmega128A3__ |
avrxmega6 | atxmega256a3 | __AVR_ATxmega256A3__ |
avrxmega6 | atxmega256a3b | __AVR_ATxmega256A3B__ |
avrxmega7 | atxmega128a1 | __AVR_ATxmega128A1__ |
- [1] Архитектура ‘avr25’, начиная с GCC 4.2
- [2] Архитектура ‘avr35’, начиная с GCC 4.2.3
- по умолчанию: r24, r25, r18, r19, r20, r21, r22, r23, r30, r31, r26, r27, r28, r29, r17, r16, r15, r14, r13, r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r0, r1
- порядок 1: r18, r19, r20, r21, r22, r23, r24, r25, r30, r31, r26, r27, r28, r29, r17, r16, r15, r14, r13, r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r0, r1
- порядок 2: r25, r24, r23, r22, r21, r20, r19, r18, r30, r31, r26, r27, r28, r29, r17, r16, r15, r14, r13, r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0
Некоторые основные опции компилятора
Следующие основные опции компилятора могут быть интересными пользователям AVR.
-OnУровень оптимизации.Увеличение n означает увеличение оптимизации. Уровень оптимизации 0 означает, что оптимизации нет совсем (это значение по умолчанию, когда опция -O не выставлена). Специальная опция -Os похожа на -O2, но при этом будет пропускаться несколько шагов, увеличивающих размер кода.
Обратите внимание, что при -O3, gcc пытается сделать инлайновыми все “простые” функции. Для AVR это обычно очень ухудшает программу из-за увеличения размера кода. Поэтому вместе с оптимизацией -O3 включаются и другие опции, например, -frename-registers, которые лучше включать вручную.
Простая опция -O эквивалентна -O1.
Обратите также внимание, что отключение всех оптимизаций предотвращает при компиляции выдачу некоторых предупреждений, зависящих от шагов анализа кода, которые выполняются только при оптимизации (невыполняемый код, неиспользуемые переменные).
Смотрите также соответствующий раздел FAQ для получения желаемого отлаженного и оптимизированного кода.
-Wa,опции ассемблера-Wl,опции компоновщикаПередача перечисленных опций ассемблеру и компоновщику соответственно.-gФормирование отладочной информации, которая может быть использована avr-gdb.-ffreestandingПредполагает “автономную” среду согласно стандарту Си. Это отключает автоматически встроенные функции (хотя они всё же могут быть переданы присоединением __builtin_ к реальному имени функции). Это также заставляет компилятор жаловаться, когда main() объявляется с пустым возвращаемым типом, что вполне логично в микроконтролерной среде, где приложение не может обеспечить значимую возвращаемую величину этой среде (в большинстве случаев из main() всё равно никак не возвращается). Однако, это также выключает все оптимизаци, выполняемые компилятором, который предполагает, что функции известны под определенными именами, описанными в стандарте. Например, применяя функцию strlen() к строковой константе обычно заствляет компилятор сразу заменить её вызов фактической длиной строки, хотя с -ffreestanding это всегда будет вызывать strlen() в реальном времени.-funsigned-charПриводит тип char без каких-либо условий к unsigned char. Без этой опции он по умолчанию signed char.-funsigned-bitfieldsПриводит тип bitfield без каких-либо условий к unsigned. По умолчанию он signed.-fshort-enumsНазначает тип enum как набор байтов, так как он нужен для объявленного диапазона возможных значений. В частности, тип enum эквивалентен наименьшему целочисленному типу, который имеет достаточную размерность.-fpack-structУпаковывает вместе все члены структуры без пустот.-fno-jump-tablesВыключает формирование инструкций табличных переходов. По умолчанию таблицы переходов могут использоваться для оптимизации операторов switch. При выключении же вместо этого используется последовательность операторов сравнения. Таблица переходов обычно в среднем быстрее, но, в частности, для операторов switch, где большинство переходов обращаются к метке default, они излишне расточительны к flash-памяти.ВНИМАНИЕ: Инструкции табличных переходов используют ассемблерную инструкцию LPM для доступа к таблицам переходов. Всегда используйте переключатель -fno-jump-tables, если компилируете загрузчик для устройств с памятью программ более 64 килобайт.
Перевод раздела Using the GNU tools из AVR Libc v.1.6.6
Дополнительные источники по теме:
- Гриффитс Артур. GCC. Настольная книга пользователей, программистов и системных администраторов. 2004
Сохранить или поделиться
radioprog.ru