Makefile básico para avr-gcc

7

Eu gostaria de fazer um makefile para compilar programas c para o arduino. Estou familiarizado com o make, mas nunca o usei com o avr-gcc. Qual é a maneira mais simples de colocar os comandos abaixo em um makefile?

$ avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o led.o led.c
$ avr-gcc -mmcu=atmega328p led.o -o led
$ avr-objcopy -O ihex -R .eeprom led led.hex
$ avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:led.hex
connorwstein
fonte
Como este é um fórum do Arduino, seria mais politicamente correto compilar -I/usr/share/arduino/hardware/arduino/cores/arduino -I/usr/share/arduino/hardware/arduino/variants/standarde vincular libcore.a. :-)
Edgar Bonet

Respostas:

5

Não é diferente trabalhar com o Make e qualquer outra forma de GCC. Basta definir sua variável CC e CFLAGS de acordo e trabalhar como normalmente.

Por exemplo, eu acabei de ler este:

CC=avr-gcc
OBJCOPY=avr-objcopy

CFLAGS=-Os -DF_CPU=16000000UL -mmcu=atmega328p
PORT=/dev/ttyACM0

led.hex: led.elf
    ${OBJCOPY} -O ihex -R .eeprom led.elf led.hex

led.elf: led.o
    ${CC} -o led.elf led.o

install: led.hex
    avrdude -F -V -c arduino -p ATMEGA328P -P ${PORT} -b 115200 -U flash:w:led.hex

Isso significa que qualquer compilação C automática será feita com avr-gcc e os sinalizadores especificados em CFLAGS. Por padrão, ele cria o arquivo hexadecimal usando OBJCOPY, que é definido como avr, que depende do arquivo led.elf - para obter esse arquivo, ele executa o destino led.elf, que vincula o arquivo de objeto led.o a as bibliotecas padrão usando o que foi definido no CC. Para fazer isso, é necessário led.o, e isso é feito automaticamente usando o programa especificado em CC e os sinalizadores em CFLAGS. Em seguida, você pode, opcionalmente make install, executar avrdudea instalação do arquivo hexadecimal no chip.

Você pode torná-lo ainda mais genérico para copiá-lo em outros projetos e fazer as alterações mínimas necessárias:

BIN=led
OBJS=led.o test.o

CC=avr-gcc
OBJCOPY=avr-objcopy
CFLAGS=-Os -DF_CPU=16000000UL -mmcu=atmega328p
PORT=/dev/ttyACM0

${BIN}.hex: ${BIN}.elf
    ${OBJCOPY} -O ihex -R .eeprom $< $@

${BIN}.elf: ${OBJS}
    ${CC} -o $@ $^

install: ${BIN}.hex
    avrdude -F -V -c arduino -p ATMEGA328P -P ${PORT} -b 115200 -U flash:w:$<

clean:
    rm -f ${BIN}.elf ${BIN}.hex ${OBJS}

Que usa "variáveis ​​automáticas" e substituição simples de nome. BINcontém a "base" dos seus arquivos binários, OBJScontém a lista de arquivos de objetos. $ @ é o nome do destino atual, $ <é o nome do primeiro pré-requisito e $ ^ é a lista de todos os pré-requisitos. Basta mudar BINe OBJSse adequar. Como bônus, joguei make cleanpara remover os arquivos compilados e deixar você com a fonte.

Majenko
fonte
o makefile publicado precisa de outra linha perto do topo; que diz: '.PHONY: instalar limpo'
user3629249
@ user3629249 Por quê? O makefile como publicado funciona perfeitamente. Você só precisa de .PHONY para destinos chamados como pré-requisitos, não para destinos chamados manualmente.
Majenko
11
@Majenko É uma boa prática criar um alvo falso para qualquer coisa que não seja realmente um nome de arquivo. Se você criar um arquivo chamado installou um arquivo clean(shell scripts, talvez?), makePoderá pensar que eles são Up to datee não fazem nada.
wchargin 24/05
@WChargin Se você faz algo tão estúpido quanto isso, merece que não funcione. Seus scripts de shell devem ser clean.she install.shse você precisar deles.
Majenko
2

A resposta aceita é ótima, pois me deu uma lição valiosa em todos os tipos de ferramentas de depuração (avr-objdump -D tornou-se um amigo próximo). Ou seja, a linha:

${OBJCOPY} -O ihex -R .eeprom $< $@

está faltando o sinalizador de arquitetura e deve ler

$ {OBJCOPY} -mmcu = atmega328p -O ihex -R .eeprom $ <$ @

Sem o sinalizador de arquitetura -mmcu, o avr-gcc acha que estamos compilando a arquitetura 8515 (definitivamente não) e produz o arquivo .elf sem instruções iniciais para a inicialização, ou seja, sem instruções para chamar a função "principal" etc.

Isso resulta em comportamento confuso, pois qualquer programa simples (por exemplo, piscar) com apenas a função "principal" funciona perfeitamente, mas se você definir outra função antes ou depois da "principal", ela executa essa função e nunca chama "principal" ou reinicia o tempo todo etc.

Também não sou um fã em particular de evitar a verificação do tipo MCU correto e do programa carregado, portanto, eu recomendaria não usar -F e -V e usar -v.

Portanto, a resposta melhorada pode ser:

PKG=led
BIN=${PKG}
OBJS=${PKG}.o
MCU=atmega328p

CC=avr-gcc
OBJCOPY=avr-objcopy
CFLAGS=-Os -DF_CPU=16000000UL -mmcu=${MCU} -Wall
PORT=/dev/ttyACM0

${BIN}.hex: ${BIN}.elf
        ${OBJCOPY} -O ihex $< $@

${BIN}.elf: ${OBJS}
        ${CC} -mmcu=${MCU} -o $@ $^

install: ${BIN}.hex
        avrdude -v -c arduino -p ${MCU} -P ${PORT} -b 115200 -U flash:w:$<

clean:
        rm -f ${BIN}.elf ${BIN}.hex ${OBJS}
Robert Špendl
fonte
Você escreveu: “ Sem o sinalizador de arquitetura -mmcu, o avr-gcc acha que estamos compilando para a arquitetura 8515 ”. Na verdade, é avr2: “Dispositivos 'clássicos' com até 8 KiB de memória de programa.”
Edgar Bonet
Eu estava consultando a referência da Atmel em atmel.com/webdoc/avrlibcreferencemanual/… Eles estão enganados?
Robert Špendl
Talvez eles signifiquem o MCU AT90S8515 que, diferentemente de seu substituto (ATmega8515), possui uma arquitetura avr2. A página para a qual você vincula pode ter sido escrita em um período em que “8515” não era ambíguo. E eles não chamam isso de “arquitetura”, já que é apenas um dos muitos MCUs que compartilham a arquitetura avr2.
Edgar Bonet