Makefile di base per avr-gcc


7

Vorrei creare un makefile per la compilazione di programmi c per Arduino. Ho una certa familiarità con make ma non l'ho mai usato con avr-gcc. Qual è il modo più semplice per mettere i comandi di seguito in un 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

Dato che si tratta di un forum Arduino, sarebbe politicamente più corretto compilare -I/usr/share/arduino/hardware/arduino/cores/arduino -I/usr/share/arduino/hardware/arduino/variants/standarde collegarsi libcore.a. :-)
Edgar Bonet,

Risposte:


5

Non è diverso lavorare con Make e qualsiasi altra forma di GCC. Basta impostare la variabile CC e la variabile CFLAGS di conseguenza e lavorare normalmente.

Ad esempio, ho appena rovesciato questo:

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

Ciò significa che qualsiasi compilazione C automatica verrà eseguita con avr-gcc e i flag specificati in CFLAGS. Per impostazione predefinita eseguirà il file esadecimale utilizzando OBJCOPY, che è impostato su avr, che si basa sul file led.elf - quindi per ottenere quel file viene eseguito il target led.elf, che collega il file oggetto led.o con le librerie predefinite usando qualunque cosa sia stata impostata in CC. Per fare ciò ha bisogno di led.o e lo fa automaticamente usando il programma specificato in CC e i flag in CFLAGS. È quindi possibile facoltativamente a make installquale verrà eseguito avrdudeper installare il file esadecimale nel chip.

Puoi renderlo ancora più generico in modo da poterlo copiare in altri progetti e apportare le modifiche minime necessarie:

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}

Che utilizza "variabili automatiche" e semplice sostituzione del nome. BINcontiene la "base" dei file binari, OBJScontiene l'elenco dei file oggetto. $ @ è il nome della destinazione corrente, $ <è il nome del primo prerequisito e $ ^ è l'elenco di tutti i prerequisiti. Basta cambiare BINe OBJSadattarsi. Come bonus ho buttato dentro make cleanper rimuovere i file compilati e lasciarti solo con la fonte.


il makefile pubblicato ha bisogno di un'altra riga vicino alla cima; che dice: '.PHONY: install clean'
user3629249

@ user3629249 Perché? Il makefile come pubblicato funziona perfettamente. Hai solo bisogno di .PHONY per target chiamati come prerequisiti, non target chiamati manualmente quali sono.
Majenko

1
@Majenko È buona norma creare un obiettivo falso per tutto ciò che non è in realtà un nome file. Se crei un file chiamato installo un file chiamato clean(script di shell, forse?), Allora makepotresti pensare che sono Up to datee non fanno nulla.
wchargin,

@WChargin Se fai qualcosa di così stupido, meriti che non funzioni. I tuoi script di shell dovrebbero essere clean.she install.shse devi averli.
Majenko

2

La risposta accettata è ottima in quanto mi ha dato una lezione preziosa in tutti i tipi di strumenti di debug (avr-objdump -D è diventato un caro amico). Vale a dire, la linea:

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

manca la bandiera dell'architettura e dovrebbe leggere

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

Senza il flag -mmcu architecture, avr-gcc indovina che stiamo compilando l'architettura 8515 (sicuramente no) e produce il file .elf senza le istruzioni iniziali per l'inizializzazione, cioè senza istruzioni per chiamare la funzione "principale" ecc.

Ciò comporta un comportamento confuso poiché qualsiasi programma semplice (ad es. Lampeggio) con solo la funzione "principale" funziona perfettamente, ma se si definisce un'altra funzione prima o dopo la "principale", esegue quella funzione e non chiama mai "principale" o si riavvia tutto il tempo ecc.

Inoltre non sono un fan particolare di evitare la verifica del corretto tipo di MCU e del programma caricato, quindi raccomanderei di non usare -F e -V e usare invece -v.

Quindi, la risposta migliorata potrebbe essere:

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}

Hai scritto: " Senza la bandiera dell'architettura -mmcu, avr-gcc suppone che stiamo compilando l'architettura 8515 ". In realtà è avr2: "Dispositivi" classici "con un massimo di 8 KiB di memoria del programma."
Edgar Bonet,

Mi riferivo al riferimento Atmel atmel.com/webdoc/avrlibcreferencemanual/… Si sbagliano?
Robert Špendl,

Forse intendono l'MCU AT90S8515 che, a differenza della sua sostituzione (ATmega8515), ha un'architettura avr2. La pagina a cui ti colleghi potrebbe essere stata scritta in un momento in cui "8515" non era ambiguo. E non la chiamano "architettura", poiché è solo una delle molte MCU che condividono l'architettura avr2.
Edgar Bonet,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.