include config.mk CC ?= gcc AVR_CC ?= avr-gcc AVR_SIZE ?= avr-size GDB ?= avr-gdb OBJCOPY ?= avr-objcopy AVRDUDE ?= avrdude QEMU ?= qemu-system-avr REAL_ELF = build/altimeter.elf SIM_ELF = build/altimeter_sim.elf # options for native (i.e. unit test) UNITY_SRC ?= unity/src TEST_RUNNER ?= unity-test-runner CFLAGS += -Wall -Wextra -I$(UNITY_SRC) -I$(TEST_RUNNER) -g3 LDFLAGS += -lm # options for cross-compile MCU ?= atmega32u4 SIM_MCU ?= atmega2560 # Compiler flags for cross-compile AVR_COMMON_CFLAGS += -Wall -Wextra -DF_CPU=16000000UL AVR_CFLAGS += $(AVR_COMMON_CFLAGS) -mmcu=$(MCU) -O3 SIM_CFLAGS += $(AVR_COMMON_CFLAGS) -mmcu=$(SIM_MCU) -g3 -gdwarf-2 -DWDT_DISABLE # Linker flags for cross-compile AVR_COMMON_LDFLAGS += -Wl,-u,vfprintf -lprintf_flt AVR_LDFLAGS += $(AVR_COMMON_LDFLAGS) -mmcu=$(MCU) SIM_LDFLAGS += $(AVR_COMMON_LDFLAGS) -mmcu=$(SIM_MCU) $(shell mkdir -p build/{real,sim,native{,/$(UNITY_SRC),/$(TEST_RUNNER)}}) all: build/altimeter_sim.elf build/altimeter.hex test size # Run the sim build software in qemu, halted ready for `make gdb` to attach and # continue. Note that sim build mocks out some hardware components emu: $(SIM_ELF) $(QEMU) -s -S -nographic -machine mega2560 -bios $< # Attach GDB session to qemu instance started with `make emu` gdb: $(GDB) -ex "target remote :1234" $(SIM_ELF) # Flash AVR software to microcontroller with AVRdude flash: build/altimeter.hex $(AVRDUDE) -F -V -c avr109 -p $(MCU) -P $(PORT) -b 115200 -U flash:w:$< clean: rm -rf build/ BUILD_DIR = build SIM_DIR = $(BUILD_DIR)/sim REAL_DIR = $(BUILD_DIR)/real NATIVE_DIR = $(BUILD_DIR)/native TEST_OBJ = \ $(NATIVE_DIR)/$(UNITY_SRC)/unity.o \ $(NATIVE_DIR)/$(TEST_RUNNER)/test_runner.o \ $(NATIVE_DIR)/test_util.o \ $(NATIVE_DIR)/test_data_manager.o \ $(NATIVE_DIR)/data_manager.o \ $(NATIVE_DIR)/barometer_sim.o \ $(NATIVE_DIR)/timer_linux.o \ $(NATIVE_DIR)/util.o REAL_OBJ = \ $(REAL_DIR)/barometer_sim.o \ $(REAL_DIR)/display_sim.o \ $(REAL_DIR)/altimeter.o \ $(REAL_DIR)/util.o \ $(REAL_DIR)/timer.o \ $(REAL_DIR)/ui.o \ $(REAL_DIR)/data_manager.o SIM_OBJ = \ $(SIM_DIR)/barometer_sim.o \ $(SIM_DIR)/display_sim.o \ $(SIM_DIR)/altimeter.o \ $(SIM_DIR)/util.o \ $(SIM_DIR)/timer.o \ $(SIM_DIR)/ui.o \ $(SIM_DIR)/data_manager.o ALL_OBJ = $(TEST_OBJ) $(REAL_OBJ) $(SIM_OBJ) ALL_SOURCE = $(ALL_OBJ:.o=.c) test: build/native/unity-test-runner/test_runner ./$^ build/native/unity-test-runner/test_runner: $(TEST_OBJ) $(CC) $(LDFLAGS) -Wl,-T,$(TEST_RUNNER)/linker_list.lds -o $@ $^ # ELF for real hardware. No mock/sim hardware included (except barometer, # haven't written that code yet) $(REAL_ELF): $(REAL_OBJ) $(AVR_CC) $(AVR_LDFLAGS) -o $@ $^ size: $(REAL_ELF) $(AVR_SIZE) -C --mcu="$(MCU)" "$(REAL_ELF)" # ELF for simulator/emu. Note that whever I/O is required, the *_sim.{o,c} # versions of each component will provide a mocked interface. This allows for # operation in QEMU (see `emu` recipe) without requring SPI, I²C and # peripherals to be emulated. Useful for UI testing and development etc. build/altimeter_sim.elf: $(SIM_OBJ) $(AVR_CC) $(SIM_LDFLAGS) -o $@ $^ build/sim/%.o: %.c build/sim/%.d $(AVR_CC) $(SIM_CFLAGS) -c -o $@ $< build/real/%.o: %.c build/real/%.d $(AVR_CC) $(AVR_CFLAGS) -c -o $@ $< build/native/%.o: %.c build/native/%.d $(CC) $(CFLAGS) -c -o $@ $< build/%.hex: build/%.elf $(OBJCOPY) -O ihex -R .eeprom $< $@ build/sim/%.d: %.c @set -e; rm -f $@; \ $(AVR_CC) $(SIM_CFLAGS) -MM -MG $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ build/real/%.d: %.c @set -e; rm -f $@; \ $(AVR_CC) $(AVR_CFLAGS) -MM -MG $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ build/native/%.d: %.c @set -e; rm -f $@; \ $(CC) $(CFLAGS) -MM -MG $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ include $(ALL_SOURCE:.c=.d) .PHONY: all emu gdb flash clean test size