Makefile básico para avr-gcc

7

Me gustaría hacer un makefile para compilar programas c para el arduino. Estoy familiarizado con make pero nunca lo he usado con avr-gcc. ¿Cuál es la forma más sencilla en que podría poner los comandos a continuación en un archivo MAKE?

$ 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
fuente
Dado que este es un foro de Arduino, sería más políticamente correcto compilar -I/usr/share/arduino/hardware/arduino/cores/arduino -I/usr/share/arduino/hardware/arduino/variants/standardy enlazar libcore.a. :-)
Edgar Bonet

Respuestas:

5

No es diferente a trabajar con Make y cualquier otra forma de GCC. Simplemente configure su variable CC y la variable CFLAGS en consecuencia y trabaje como lo hace normalmente.

Por ejemplo, acabo de derribar 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

Eso significa que cualquier compilación automática de C se realizará con avr-gcc y los indicadores especificados en CFLAGS. Por defecto, creará el archivo hexadecimal utilizando OBJCOPY, que se establece en avr, que se basa en el archivo led.elf, por lo que para obtener ese archivo se ejecuta el objetivo led.elf, que vincula el archivo objeto led.o con las bibliotecas predeterminadas que usan lo que se configuró en CC. Para hacerlo necesita led.o, y lo hace automáticamente usando el programa especificado en CC y las banderas en CFLAGS. Entonces, opcionalmente, make installpuede ejecutar avrdudeel archivo hexadecimal en el chip.

Puede hacerlo aún más genérico para poder copiarlo en otros proyectos y realizar los cambios mínimos necesarios:

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 utiliza "variables automáticas" y un simple reemplazo de nombre. BINcontiene la "base" de sus archivos binarios, OBJScontiene la lista de archivos de objetos. $ @ es el nombre del objetivo actual, $ <es el nombre del primer requisito previo y $ ^ es la lista de todos los requisitos previos. Solo cámbielo BINy OBJSpara adaptarse Como beneficio adicional, lo he agregado make cleanpara eliminar los archivos compilados y simplemente dejarlo con la fuente.

Majenko
fuente
el archivo MAKE publicado necesita otra línea cerca de la parte superior; que dice: '.PHONY: install clean'
usuario3629249
@ user3629249 ¿Por qué? El archivo MAKE como publicado funciona perfectamente. Solo necesita .PHONY para los objetivos llamados como requisitos previos, no para los objetivos llamados manualmente, que son.
Majenko
1
@Majenko Es una buena práctica crear un objetivo falso para cualquier cosa que en realidad no sea un nombre de archivo. Si crea un archivo llamado installo un archivo llamado clean(¿scripts de shell, tal vez?), Entonces makepuede pensar que son Up to datey no hacen nada.
wchargin
@WChargin Si haces algo tan tonto como eso, entonces mereces que no funcione. Sus scripts de shell deberían ser clean.shy install.shsi debe tenerlos.
Majenko
2

La respuesta aceptada es excelente ya que me ha dado una valiosa lección en todo tipo de herramientas de depuración (avr-objdump -D se ha convertido en un amigo cercano). A saber, la línea:

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

le falta la bandera de arquitectura y debería leer

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

Sin el indicador de arquitectura -mmcu, avr-gcc supone que estamos compilando para la arquitectura 8515 (definitivamente no) y produce el archivo .elf sin instrucciones iniciales para la inicialización, es decir, sin instrucciones para llamar a la función "principal", etc.

Esto da como resultado un comportamiento confuso ya que cualquier programa simple (por ejemplo, parpadeo) con solo la función "principal" funciona perfectamente, pero si define otra función antes o después de "principal", ejecuta esa función y nunca llama a "principal" o se reinicia todo el tiempo etc.

Tampoco soy un fanático particular de evitar la verificación del tipo correcto de MCU y el programa cargado, por lo que recomendaría no usar -F y -V y usar -v en su lugar.

Entonces, la respuesta mejorada podría 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
fuente
Usted escribió: " Sin la bandera de arquitectura -mmcu, avr-gcc supone que estamos compilando para la arquitectura 8515 ". En realidad, es avr2: "dispositivos 'clásicos' con hasta 8 KiB de memoria de programa".
Edgar Bonet
Me refería a la referencia de Atmel atmel.com/webdoc/avrlibcreferencemanual/… ¿Están equivocados?
Robert Špendl
Tal vez se refieren a la MCU AT90S8515 que, a diferencia de su reemplazo (ATmega8515), tiene una arquitectura avr2. La página a la que enlaza puede haber sido escrita en un momento en que "8515" no era ambiguo. Y no lo llaman "arquitectura", ya que es solo una de las muchas MCU que comparten la arquitectura avr2.
Edgar Bonet