The accepted answer is great as it has given me a valuable lesson in all kinds of debugging tools (avr-objdump -D has become a close friend). Namely, the line:
${OBJCOPY} -O ihex -R .eeprom $< $@
is missing the architecture flag and should read
${OBJCOPY} -mmcu=atmega328p -O ihex -R .eeprom $< $@
Without the -mmcu architecture flag, avr-gcc guesses we are compiling for 8515 architecture (definitely not) and it produces the .elf file without initial instructions for initializing, i.e. without instructions to call the "main" function etc.
This results in confusing behavior as any simple program (e.g. blink) with only the "main" function works perfectly, but if you define another function before or after the "main", it runs that function and never calls "main" or it restarts all the time etc.
I am also not a particular fan of avoiding the verification of correct MCU type and uploaded program, so I'd advocate not to use -F and -V and use -v instead.
So, the improved answer could be:
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}
-I/usr/share/arduino/hardware/arduino/cores/arduino -I/usr/share/arduino/hardware/arduino/variants/standard
and link withlibcore.a
. :-)