Тулчейн AVR GCC: avr-gcc, avr-libc и avrdude из командной строки
Как собрать программу для AVR без среды разработки: из чего состоит тулчейн AVR GCC, где взять свежую сборку для Windows, Linux и macOS, какими командами превратить файл на C в HEX и записать его в ATmega328P, как выглядит минимальный Makefile, что дают основные заголовки avr-libc и что означают частые предупреждения и ошибки.
Обновлено Редакция GAW
Тулчейн AVR GCC (AVR GNU toolchain) — набор свободных программ для сборки программ под 8-битные микроконтроллеры AVR: компилятор avr-gcc из проекта GCC, ассемблер, компоновщик и утилиты GNU Binutils (avr-as, avr-ld, avr-objcopy, avr-objdump, avr-size и другие), стандартная библиотека avr-libc с заголовками регистров и кодом запуска и программа прошивки avrdude. Компилятор, binutils и avr-libc работают и внутри сред разработки: Arduino IDE ставит их вместе с avrdude, Microchip Studio — свою сборку компилятора без avrdude. Здесь разобрано, как пользоваться им напрямую — из командной строки и Makefile.
Коротко
- Состав — avr-gcc (компилятор C и C++), binutils (avr-as, avr-ld, avr-objcopy, avr-objdump, avr-size), avr-libc (заголовки, код запуска, libc и libm), avrdude (запись в микроконтроллер).
- Свежие версии — Microchip AVR 8-Bit Toolchain 4.0.0; на его странице указаны GCC 15.1.0, Binutils 2.44, AVR-LibC 2.2.1. Последний выпуск AVR-LibC — 2.3.2 от 6 июня 2026 года, avrdude — 8.3 от 11 сентября 2026 года.
- Главные ключи —
-mmcu=atmega328p(на этапах компиляции и компоновки),-DF_CPU=16000000UL,-Os. Без-Oavr-gcc не оптимизирует код вовсе. - HEX для прошивки —
avr-objcopy -O ihex -R .eeprom firmware.elf firmware.hex. - Arduino IDE использует свою сборку: avr-gcc 7.3.0 с binutils 2.26 и avr-libc 2.0.0.
Из чего состоит тулчейн
| Программа | Проект | Что делает |
|---|---|---|
avr-gcc, avr-g++ | GCC | драйвер компилятора: вызывает препроцессор, компилятор C или C++, ассемблер и компоновщик |
avr-as | GNU Binutils | ассемблер |
avr-ld | GNU Binutils | компоновщик; обычно его вызывает сам avr-gcc |
avr-objcopy | GNU Binutils | переводит ELF в Intel HEX, Motorola S-record или двоичный образ, выделяет и удаляет секции |
avr-objdump | GNU Binutils | заголовки секций, дизассемблер с исходным текстом, отчёт о занятой памяти |
avr-size | GNU Binutils | размеры секций |
avr-nm, avr-readelf, avr-addr2line | GNU Binutils | таблица символов, содержимое ELF, адрес → файл и строка |
| avr-libc | AVR-LibC | заголовки <avr/io.h> и другие, код запуска crt<mcu>.o, библиотеки libc и libm, библиотека устройства lib<mcu>.a |
avrdude | AVRDUDE | записывает и читает флеш-память, EEPROM и фьюзы |
avr-gdb | GDB | отладчик; к микроконтроллеру подключается через отдельную программу-посредник, например AVaRICE для JTAG |
avr-gcc — только «драйвер»: он сам вызывает нужные программы в зависимости от расширения файла. Полная поддержка конкретного микроконтроллера складывается из четырёх частей: specs-файла устройства в компиляторе, заголовка <avr/io*.h>, кода запуска и библиотеки устройства — последние три даёт avr-libc. C++ поддерживается с ограничениями: по примечаниям Microchip к версии 3.7.0, стандартная библиотека C++ (libstdc++) в их тулчейне не поддерживается.
Где взять тулчейн
| Источник | GCC | Binutils | AVR-LibC | avrdude | Системы |
|---|---|---|---|---|---|
| Microchip AVR 8-Bit Toolchain 4.0.0 (24 сентября 2025 года) | 15.1.0 | 2.44 | 2.2.1 | не входит | Windows, Linux, macOS |
Debian 13 (trixie): пакеты gcc-avr, binutils-avr, avr-libc, avrdude | 14.2.0 | 2.43.50.20250108 — снимок разработки, не выпуск | 2.2.1 | 7.1 | Linux |
| Arduino AVR Boards 1.8.8: avr-gcc 7.3.0-atmel3.6.1-arduino7 и avrdude 8.0.0-arduino1 | 7.3.0 | 2.26 | 2.0.0 | 8.0 | Windows, Linux (x86, ARM), macOS |
| Сборка из исходников по руководству avr-libc | любая | любая | любая | — | Linux, BSD, Windows |
Microchip. На странице GCC Compilers for AVR лежат архивы версии 4.0.0: avr8-gnu-toolchain-4.0.0.52-win32.any.x86_64.zip для Windows, …-linux.any.x86_64.tar.gz для Linux и …-darwin.any.universal.tar.gz для macOS. Версии компонентов (GCC 15.1.0, Binutils 2.44, AVR-LibC 2.2.1) указаны там же, в описании тулчейна. Установщика нет: архив распаковывают в любую папку и добавляют её подпапку bin в переменную PATH. В avr/include лежат заголовки avr-libc, в avr/lib — библиотеки, код запуска и скрипты компоновщика. В примечаниях к версии 3.7.0 Microchip пишет, что обновлять поверх старой версии нельзя — новую ставят рядом. Microchip Studio при установке ставит собственную сборку этого тулчейна, какую именно — зависит от выпуска Studio. avrdude не входит ни в архив, ни в Studio, её скачивают отдельно со страницы релизов — подробно в статье «AVRDUDE».
Debian. Всё ставится одной командой:
sudo apt install gcc-avr binutils-avr avr-libc avrdude
Arduino IDE. Если IDE уже стоит, компилятор есть на диске: ядро Arduino AVR Boards кладёт его в папку Arduino15, в packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/, а avrdude — в packages/arduino/tools/avrdude/8.0.0-arduino1/. Где лежит Arduino15 в каждой системе, показано в статье «Arduino IDE 2». Учтите, что это GCC 7.3.0 с binutils 2.26 и avr-libc 2.0.0 — заметно старше текущих выпусков.
Версии. Узнать, что установлено, помогают команды из FAQ avr-libc. Если тулчейнов несколько, вызывайте программы по полному пути — иначе легко собрать одной версией, а проверить другой.
avr-gcc --version
echo "#include <avr/version.h>" | avr-gcc -xc - -E -dM | grep AVR_LIBC_VERSION_STRING
Новый микроконтроллер, которого нет в компиляторе. Старые сборки знают не все кристаллы: например, в списке устройств Microchip AVR 8-bit Toolchain 3.7.0 (GCC 7.3.0) нет ATmega4809 и ATtiny1624, а в текущем GCC оба есть (архитектура avrxmega3). Поддержку можно добавить пакетом устройств Microchip (DFP, файл .atpack — это zip-архив): в нём есть specs-файл, заголовки, код запуска и библиотека устройства. Пакет распаковывают и передают компилятору два пути — к specs-файлу ключом -B и к заголовкам ключом -I:
avr-gcc -mmcu=atmega4809 -B <dfp>/gcc/dev/atmega4809/ -I <dfp>/include/ -Os -c main.c
Здесь <dfp> — папка распакованного пакета ATmega_DFP; так же, со своим кристаллом в путях, подключают и другие пакеты.
Минимальная сборка: от main.c до записи в Arduino Uno
Возьмём программу, которая мигает светодиодом платы Arduino Uno: он подключён к выводу 13 платы, то есть к линии PB5 микроконтроллера ATmega328P, тактовая частота — 16 МГц.
/* blink.c - toggle the LED on Arduino Uno pin 13 (PB5) using avr-libc only */
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRB |= _BV(DDB5); /* PB5 as output */
for (;;) {
PORTB ^= _BV(PORTB5); /* toggle the LED */
_delay_ms(500);
}
}
Сборка и прошивка — пять команд:
# 1. Compile: device, clock frequency, optimize for size
avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL -Os -g -Wall -c blink.c -o blink.o
# 2. Link: -mmcu again, it selects the startup code and device libraries
avr-gcc -mmcu=atmega328p -g blink.o -o blink.elf
# 3. Convert the program to Intel HEX, without the EEPROM section
avr-objcopy -O ihex -R .eeprom blink.elf blink.hex
# 4. Check the size
avr-size blink.elf
# 5. Flash through the Uno bootloader (COM3 on Windows)
avrdude -p m328p -c arduino -P /dev/ttyACM0 -b 115200 -U flash:w:blink.hex:i
Что происходит на каждом шаге:
- Компиляция.
-mmcu=atmega328pзадаёт набор команд (ATmega328P относится к архитектуре avr5) и через встроенные макросы выбирает заголовок с регистрами этого кристалла.-DF_CPU=16000000ULопределяет частоту для<util/delay.h>.-Osвключает оптимизацию по размеру — для AVR это обычный выбор, а без ключа-Oкомпилятор не оптимизирует вовсе.-gдобавляет отладочную информацию: она остаётся в ELF и в HEX не попадает. - Компоновка.
-mmcuнужен и здесь: по нему avr-gcc подключает код запускаcrtatmega328p.oи библиотеки устройства. Результат — ELF с кодом, данными, таблицей символов и отладочной информацией. Маленькую программу можно собрать одной командой, без-c, но в проекте из нескольких файлов каждый компилируют отдельно и компонуют вместе. - HEX.
-R .eepromубирает секцию с данными для EEPROM: в ELF она лежит по адресам от 0x810000, которые к флеш-памяти не относятся. Так делает и ядро Arduino. Руководство avr-libc предлагает обратный способ — взять только нужные секции:avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex. Секцию.dataпропускать нельзя: в ней начальные значения переменных, которые код запуска копирует в ОЗУ. У кристаллов с отдельной секцией.rodata— ATtiny4…40 с урезанным ядром, tinyAVR 0/1/2, megaAVR 0, AVR Dx и Ex — к этому списку добавляют-j .rodata. Данные для EEPROM, если они есть, выносят в отдельный файл:avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex blink.elf blink.eep. - Размер.
avr-sizeпо умолчанию печатает столбцы text, data и bss. У AVR флеш-память занимают text и data (начальные значения переменных хранятся во флеш-памяти), статическое ОЗУ — data и bss. Отчёт о занятой памяти, а если в ELF записаны сведения о кристалле, то и с процентами заполнения, даётavr-objdump -P mem-usage blink.elf(binutils 2.26 и новее). Сведения о кристалле записывает в ELF код запуска avr-libc. В binutils 2.45 строка Program — это .text + .data + .rodata + .bootloader, в 2.26 (сборка Arduino) — .text + .data + .bootloader; строка Data — .data + .bss + .noinit. Ключиavr-size --mcu=atmega328p -C, которые часто встречаются в инструкциях, в документации GNU Binutils не описаны: проверьтеavr-size --help, прежде чем на них полагаться. Как читать вывод size, подробно разобрано в статье «Файлы прошивки». - Прошивка. Через загрузчик Uno — протоколом
arduinoна 115 200 бит/с; программатором USBasp —avrdude -c usbasp -p m328p -U flash:w:blink.hex:i. Ключи avrdude и готовые команды для других плат — в статье «AVRDUDE». avrdude умеет принимать и сам ELF (-U flash:w:blink.elf:e), если собрана с поддержкой ELF.
Содержимое получившегося HEX можно посмотреть и проверить контрольные суммы записей в просмотрщике HEX-файлов, а дизассемблированный листинг с исходным текстом выводит avr-objdump -h -S blink.elf > blink.lst — команды в нём описаны в статье «Система команд AVR».
Ключи, которые стоит знать
| Ключ | Что делает |
|---|---|
-mmcu=<кристалл> | выбирает микроконтроллер или архитектуру; без него действует архитектура avr2 — классические AVR до 8 КБ |
-DF_CPU=16000000UL | определяет макрос F_CPU — тактовую частоту в герцах для <util/delay.h> и <util/setbaud.h>. Он только сообщает частоту заголовкам; настоящую задают фьюзы, и новый ATmega328P работает на 1 МГц (внутренний RC-генератор 8 МГц и делитель CKDIV8) |
-Os | оптимизация по размеру: всё из -O2, кроме того, что обычно увеличивает код |
-Og | оптимизация, удобная для отладки |
-O3 | для AVR обычно проигрыш: встраивание функций и развёртка циклов раздувают код |
-g | отладочная информация для avr-gdb и листингов |
-c, -o файл | только компилировать, без компоновки; имя выходного файла |
-ffunction-sections -fdata-sections и -Wl,--gc-sections | каждая функция и переменная — в своей секции, компоновщик выбрасывает неиспользуемые |
-mrelax | компоновщик заменяет CALL и JMP на более короткие RCALL и RJMP, где хватает дальности |
-Wl,-Map,firmware.map | файл карты памяти: где лежит каждая секция и модуль; создаётся даже при переполнении памяти |
-save-temps | сохранить промежуточные файлы .i и .s, чтобы посмотреть, во что превратился код |
-MMD -MP | записать зависимости от заголовков в файлы .d для make |
Минимальный Makefile
Набирать команды каждый раз незачем — их собирает Makefile для GNU make. Этот вариант компилирует все файлы из списка SRC, следит за изменениями заголовков, печатает размер и прошивает плату командой make flash:
# Minimal Makefile for an ATmega328P project (GNU make)
MCU = atmega328p
F_CPU = 16000000UL
TARGET = blink
SRC = blink.c
# Override on the command line, e.g. make flash AVRDUDE_FLAGS="-c usbasp"
AVRDUDE_FLAGS ?= -c arduino -P /dev/ttyACM0 -b 115200
CC = avr-gcc
OBJCOPY = avr-objcopy
SIZE = avr-size
CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Os -g -std=gnu11 -Wall -Wextra \
-ffunction-sections -fdata-sections -MMD -MP
LDFLAGS = -mmcu=$(MCU) -g -Wl,--gc-sections -Wl,-Map,$(TARGET).map
OBJ = $(SRC:.c=.o)
all: $(TARGET).hex size
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET).elf: $(OBJ)
$(CC) $(LDFLAGS) $^ -o $@
$(TARGET).hex: $(TARGET).elf
$(OBJCOPY) -O ihex -R .eeprom $< $@
size: $(TARGET).elf
$(SIZE) $<
flash: $(TARGET).hex
avrdude -p $(MCU) $(AVRDUDE_FLAGS) -U flash:w:$<:i
clean:
rm -f $(OBJ) $(OBJ:.o=.d) $(TARGET).elf $(TARGET).hex $(TARGET).map
-include $(OBJ:.o=.d)
.PHONY: all size flash clean
Строки команд под целями должны начинаться с символа табуляции, а не с пробелов: так требует синтаксис правил GNU make. В Windows порт задают при вызове: make flash AVRDUDE_FLAGS="-c arduino -P COM3 -b 115200", для программатора USBasp — make flash AVRDUDE_FLAGS="-c usbasp". Цель clean вызывает rm, поэтому в Windows её запускают из оболочки, где эта команда есть. Пример Makefile посложнее — с листингом и файлами S-record и BIN — есть в руководстве avr-libc, в разделе о демо-проекте.
Заголовки avr-libc
| Заголовок | Что даёт | Пример |
|---|---|---|
<avr/io.h> | имена регистров и битов выбранного -mmcu кристалла (PORTB, DDRB, TCCR1B, DDB5), имена векторов прерываний, константы RAMEND, FLASHEND, E2END, SPM_PAGESIZE; заодно подключает <avr/sfr_defs.h> с макросом _BV(bit) = 1 << bit | DDRB |= _BV(DDB5); |
<util/delay.h> | задержки _delay_ms() и _delay_us() по частоте F_CPU | _delay_ms(500); |
<avr/interrupt.h> | sei() и cli() — разрешить и запретить прерывания; макрос ISR(вектор) для обработчика | ISR(TIMER1_COMPA_vect) { … } |
<avr/pgmspace.h> | PROGMEM, PSTR(), pgm_read_byte() и функции с суффиксом _P — константы во флеш-памяти вместо ОЗУ | pgm_read_byte(&table[i]) |
<avr/io.h>. Файл сам выбирает заголовок кристалла (<avr/iom328p.h> для ATmega328P) по макросам, которые задаёт -mmcu; подключать iom328p.h напрямую не нужно. Имена регистров и битов совпадают с даташитом, но у разных кристаллов одинаковые по смыслу биты иногда называются по-разному — при переносе программы сверяйтесь с заголовком.
<util/delay.h>. Перед подключением должен быть определён F_CPU — частота в герцах: строкой #define F_CPU 16000000UL выше #include или ключом -D. Функции работают как задумано, только если включена оптимизация и задержка — константа, известная при компиляции; тогда расчёт тактов выполняет компилятор, а в программу вставляется точный цикл. Прерывания функции задержки не запрещают, поэтому каждое сработавшее прерывание удлиняет задержку. Пределы и фактическое число тактов покажет калькулятор задержек AVR.
<avr/interrupt.h>. Обработчик объявляют макросом ISR() с именем вектора из заголовка кристалла. Переменная, которую меняет обработчик, а читает основная программа, должна быть volatile: иначе оптимизатор прочитает её один раз и больше не заглянет. Если прерывание разрешено, а обработчика нет, код запуска avr-libc отправляет его на __bad_interrupt, а оттуда — на __vector_default, который по умолчанию указывает на адрес 0: программа начинается заново. Это не аппаратный сброс: регистры периферии сохраняют свои значения, а в регистре MCUSR не появляется признак причины сброса. Поймать такие прерывания можно своим обработчиком ISR(BADISR_vect) — это и есть __vector_default. Пример — светодиод мигает по прерыванию таймера 1 в режиме CTC:
/* timer-blink.c - toggle PB5 every 0.5 s from a Timer1 compare interrupt */
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
static volatile uint8_t tick; /* set in the ISR, read in main() */
ISR(TIMER1_COMPA_vect)
{
tick = 1;
}
int main(void)
{
DDRB |= _BV(DDB5);
OCR1A = 31249; /* 16 MHz / 256 / (31249 + 1) = 2 Hz */
TCCR1A = 0; /* WGM11:10 = 0, outputs disconnected */
TCCR1B = _BV(WGM12) | _BV(CS12); /* CTC with TOP = OCR1A, clk/256 */
TIMSK1 = _BV(OCIE1A); /* enable compare match A interrupt */
sei();
for (;;) {
if (tick) {
tick = 0;
PORTB ^= _BV(PORTB5);
}
}
}
Период прерываний: T = N · (OCR1A + 1)/fCPU = 256 · 31 250/16 000 000 = 0,5 с. Бит WGM12 вместе с нулевыми WGM13, WGM11 и WGM10 включает режим 4 — CTC с вершиной OCR1A, CS12 выбирает делитель 256, OCIE1A разрешает прерывание по совпадению. Строка TCCR1A = 0 нужна, если код окажется в скетче Arduino: функция init() ядра заранее ставит бит WGM10, и вместе с WGM12 получился бы режим 5 — 8-битный Fast PWM с вершиной 0xFF, в котором совпадения с OCR1A = 31249 не будет. Как подобрать делитель и OCR для другой частоты, считает калькулятор таймеров МК, а режимы таймеров разобраны в статье «Таймеры AVR». Почему без volatile такой код ломается и что ещё важно в C для микроконтроллеров, рассказано в статье «Язык C для микроконтроллеров».
<avr/pgmspace.h>. У ATmega328P и других классических AVR константы и строковые литералы по умолчанию попадают в секцию .data: они занимают место и во флеш-памяти, и в ОЗУ, куда их копирует код запуска. Таблицы и строки, которые не меняются, объявляют с PROGMEM и читают специальными функциями:
#include <stdint.h>
#include <avr/pgmspace.h>
static const uint8_t table[] PROGMEM = { 1, 2, 4, 8, 16, 32, 64, 128 };
uint8_t bit_mask(uint8_t i)
{
return pgm_read_byte(&table[i & 7]); /* read from flash, not RAM */
}
Функции _P и pgm_read_byte() работают с первыми 64 КБ флеш-памяти. Для данных выше этой границы есть макросы pgm_read_*_far() и функции с суффиксом _PF (например, strlen_PF()): они принимают 32-битный адрес типа uint_farptr_t, который даёт pgm_get_far_address(). Другие заголовки avr-libc — <avr/sleep.h> для режимов сна (см. режимы сна AVR), <avr/eeprom.h>, <avr/wdt.h>, <util/setbaud.h> — устроены так же: каждый описан в руководстве avr-libc.
Частые ошибки и предупреждения
| Сообщение или симптом | Причина | Что сделать |
|---|---|---|
#warning "F_CPU not defined for <util/delay.h>" | F_CPU не определён, заголовок подставил 1 МГц | задать -DF_CPU=16000000UL или #define до #include; иначе на 16 МГц задержки в 16 раз короче |
#warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed" | сборка без оптимизации: по умолчанию действует -O0 | добавить -Os; без неё задержки намного длиннее и непредсказуемы, а в программу попадает библиотека плавающей точки |
#warning "device type not defined", затем DDRB, PORTB «не объявлены» | не указан -mmcu | добавить -mmcu= при компиляции и компоновке |
| программа собралась, но не работает | -mmcu не указан при компоновке или отличается от компиляции | одинаковый -mmcu на всех этапах. Начиная с GCC 5 без -mmcu драйвер берёт specs ядра avr2, а код запуска и библиотеку устройства подключает только для конкретного кристалла, — программа собирается без кода запуска и таблицы векторов |
компилятор не знает кристалл, указанный в -mmcu | кристалл новее тулчейна | свежий тулчейн или пакет устройств (DFP) с ключами -B и -I |
| переменная из обработчика прерывания «не меняется» | нет volatile | объявить переменную volatile |
| программа время от времени начинается заново, хотя сброса не было | разрешено прерывание без обработчика: переход на адрес 0 через __bad_interrupt | написать обработчик или запретить прерывание; для отладки — ISR(BADISR_vect) |
| ОЗУ быстро кончается, в .data много строк | строковые литералы копируются в ОЗУ | PROGMEM, PSTR() и функции _P |
_delay_ms(t) с переменной t: ошибка компиляции __builtin_avr_delay_cycles expects a compile time integer constant | с оптимизацией <util/delay.h> пересчитывает время в такты встроенной функцией компилятора, а ей нужна константа | константа в аргументе; переменную задержку набирают циклом из _delay_ms(1) или делают таймером |
_delay_ms(t) с переменной t ждёт слишком долго и раздувает код | так бывает только с -O0 или с макросом __DELAY_BACKWARD_COMPATIBLE__: пересчёт в такты идёт во время работы в числах с плавающей точкой | то же: константа, цикл из _delay_ms(1) или таймер |
компоновщик сообщает о переполнении области text или data | программа или данные не помещаются в память кристалла | -Os, --gc-sections, PROGMEM, причину ищут в файле карты (-Wl,-Map) |
| в HEX для флеш-памяти попали чужие данные с адресами от 0x810000 | в ELF есть секции .eeprom, .fuse, .lock или .signature — компоновщик кладёт их с адресов 0x810000, 0x820000, 0x830000 и 0x840000, — а avr-objcopy вызван без -R или -j | надёжнее всего явный список -j .text -j .data (и -j .rodata для кристаллов с этой секцией); вариант с -R требует перечислить все лишние секции |
Последний пункт касается программ, в которых служебные данные объявлены в коде: макрос FUSES из <avr/fuse.h> создаёт секцию .fuse, LOCKBITS из <avr/lock.h> — секцию .lock, а <avr/signature.h> — секцию .signature с сигнатурой кристалла. Эти секции нужны программе прошивки, которая берёт их из ELF, но в HEX для флеш-памяти им не место. Значения фьюзов для своей платы проверьте в калькуляторе фьюзов AVR, а обзор семейств AVR, интерфейсов прошивки и программаторов — в разделе «Микроконтроллеры AVR».
Частые вопросы
Как скомпилировать программу для ATmega328P через avr-gcc?
Тремя командами: avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL -Os -c main.c -o main.o компилирует, avr-gcc -mmcu=atmega328p main.o -o main.elf компонует, avr-objcopy -O ihex -R .eeprom main.elf main.hex делает HEX для прошивки. Ключ -mmcu нужен на обоих этапах: по нему выбираются набор команд, заголовок с регистрами, код запуска и библиотеки.
Что значит «F_CPU not defined for <util/delay.h>»?
Заголовок util/delay.h не нашёл макрос F_CPU с тактовой частотой в герцах и подставил 1 МГц. Если микроконтроллер работает на 16 МГц, все задержки станут в 16 раз короче. Задайте частоту ключом -DF_CPU=16000000UL или строкой #define F_CPU 16000000UL до подключения заголовка.
Почему _delay_ms работает неправильно?
Проверьте, совпадает ли F_CPU с настоящей тактовой частотой. F_CPU только сообщает частоту заголовку, а задают её фьюзы: новый ATmega328P с завода работает от внутреннего RC-генератора 8 МГц с делителем CKDIV8, то есть на 1 МГц, и при F_CPU=16000000UL задержки выйдут в 16 раз длиннее. Вторая причина — сборка без оптимизации (по умолчанию -O0): задержки становятся намного длиннее, в программу попадает библиотека плавающей точки. Нужен -Os и константа в аргументе. Прерывания во время задержки тоже её удлиняют.
Где взять avr-gcc для Windows?
Готовый архив AVR 8-Bit Toolchain выкладывает Microchip: последняя версия — 4.0.0, на странице тулчейна указаны GCC 15.1.0, Binutils 2.44 и AVR-LibC 2.2.1, есть сборки для Windows, Linux и macOS. Архив распаковывают и добавляют его папку bin в PATH. Ещё один вариант — компилятор из Arduino IDE: он лежит в папке Arduino15, но это старая версия GCC 7.3.0.
Как узнать размер прошивки после avr-gcc?
Командой avr-size firmware.elf: флеш-память занимают столбцы text и data, ОЗУ — data и bss. Отчёт о занятой памяти выдаёт avr-objdump -P mem-usage firmware.elf (binutils 2.26 и новее); проценты заполнения он показывает, только если в ELF записаны сведения о кристалле — их добавляет код запуска avr-libc. Ключей --mcu и -C у avr-size в документации GNU Binutils нет — они есть не во всех сборках.
Можно ли пользоваться avr-gcc из Arduino IDE?
Да: ядро Arduino AVR Boards ставит avr-gcc 7.3.0 и avrdude в папку Arduino15, в подпапки packages/arduino/tools/avr-gcc и packages/arduino/tools/avrdude. Их можно вызывать по полному пути из командной строки. В сборке Arduino — binutils 2.26 и avr-libc 2.0.0, это заметно старше текущих выпусков.
Источники
- AVR-LibC 2.3.2. User Manual: Toolchain Overview, Using the GNU tools, A simple project (demo), FAQ, модули <avr/io.h>, <util/delay.h>, <avr/interrupt.h>, <avr/pgmspace.h>, <avr/fuse.h> (исходники документации, тег avr-libc-2_3_2-release) — состав тулчейна, ключи -mmcu, -O, -g, -ffunction-sections, -mrelax, -save-temps, -O0 по умолчанию и -Os как обычный выбор, команды сборки демо-проекта и его Makefile, avr-objdump -P mem-usage, avr-objcopy для HEX и EEPROM, F_CPU и требования к оптимизации в util/delay.h, sei, cli, ISR и BADISR_vect, volatile, PROGMEM и строки в ОЗУ, версии инструментов; выпуск 2.3.2 от 6 июня 2026 года
- GCC Manual: AVR Options, Optimize Options, Preprocessor Options, Overall Options, AVR Built-in Functions (текущая версия на 20 октября 2026 года) — -mmcu и архитектуры avr2…avrxmega7, значение по умолчанию avr2, ATmega328P — avr5; полная поддержка устройства — crt, io-заголовок, библиотека устройства и specs-файл; ключи -D, -MMD, -MP, -c, -o; __builtin_avr_delay_cycles
- GNU Binutils documentation: objcopy, objdump, size; ld: MEMORY; исходники binutils 2.26 и 2.45 (binutils/od-elf32_avr.c, ld/scripttempl/avr.sc) — -O ihex, -j, -R, форматы вывода size, ключи size без --mcu и -C, ошибка компоновщика при переполнении области памяти, AVR-отчёт mem-usage в avr-objdump с версии 2.26, адреса областей eeprom, fuse, lock в скрипте компоновщика AVR
- Microchip. GCC Compilers for AVR and Arm-Based MCUs and MPUs (копия Web Archive от 11 июля 2026 года); AVR 8-bit GNU Toolchain 3.7.0 Release Notes (42372A) — AVR 8-Bit Toolchain 4.0.0 от 24 сентября 2025 года: GCC 15.1.0, Binutils 2.44, AVR-LibC 2.2.1, архивы для Windows, Linux и macOS; в примечаниях к 3.7.0 — состав пакета, папка bin в PATH, обновление установкой рядом, ограничения C++, пакеты поддержки устройств (DFP) с ключами -B и -I
- Arduino. Индекс пакетов package_index.json, репозиторий arduino/toolchain-avr (коммит 2c677fd) — Arduino AVR Boards 1.8.8 использует avr-gcc 7.3.0-atmel3.6.1-arduino7 и avrdude 8.0.0-arduino1; состав сборки Arduino: binutils 2.26, gcc 7.3.0, avr-libc 2.0.0, gdb 7.8; рецепты platform.txt (ArduinoCore-avr, коммит 11b9130)
- GCC 15.1.0: исходники gcc/config/avr (avr.cc, driver-avr.cc, gen-avr-mmcu-specs.cc) — ошибка «expects a compile time integer constant» у __builtin_avr_delay_cycles; без -mmcu — specs ядра avr2 без кода запуска и библиотеки устройства
- AVR-LibC 2.3.2: crt1/gcrt1.S; ArduinoCore-avr: cores/arduino/wiring.c (коммит 11b9130) — незанятые векторы → __bad_interrupt → __vector_default = __vectors (адрес 0); init() ядра Arduino ставит WGM10 в TCCR1A
- GNU Make Manual: Rule Syntax — строки рецепта начинаются с символа табуляции
- Debian 13 (trixie): пакеты gcc-avr, binutils-avr, avr-libc, avrdude — версии 14.2.0, 2.43.50.20250108, 2.2.1 и 7.1, страницы прочитаны 20 октября 2026 года
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — 16.9.2 — режим CTC таймера 1 (WGM13:0 = 4, вершина OCR1A), табл. 16-5 — делитель CS12:0, 16.11.8 — бит OCIE1A регистра TIMSK1
Нашли ошибку?
Смотрите также
- AVRDUDEПрошивка AVR из командной строки: ключи, Arduino, USBasp, фьюзы, ошибки
- Arduino IDE 2Установка, менеджер плат, порт, библиотеки, монитор порта, HEX-файл, ошибки загрузки
- Файлы прошивки: HEX, BIN, ELFELF, Intel HEX, S-record, BIN и UF2: адреса, секции, objcopy, size
- C для микроконтроллеровТипы, stdint, volatile, атомарность, регистры, константы во Flash
- Задержки AVR: _delay_msТакты и фактическое время _delay_ms, _delay_us, циклов; пределы и округление
- AVRATmega, ATtiny, AVR Dx/Ex: семейства, прошивка, инструменты