## This library is free software: you can redistribute it and/or modify ## it under the terms of the GNU Lesser General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This library is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU Lesser General Public License for more details. ## ## You should have received a copy of the GNU Lesser General Public License ## along with this library. If not, see . ## ## the make file provide rule to compile and flash firmware for STM32F1 micro-controllers ## it uses libopencm3 # be silent per default, but 'make V=1' will show all compiler calls. ifneq ($(V),1) Q := @ NULL := 1> /dev/null 2> /dev/null endif # the final binary name (without extension) BINARY = firmware # which development board is used # supported are: SYSTEM_BOARD, MAPLE_MINI, BLUE_PILL BOARD = BLUE_PILL # source files CSRC = $(wildcard *.c) CHDR = $(wildcard *.h) OBJ = $(patsubst %.c,%.o,$(CSRC)) # figure out based on the includes which library files are used in the main CSRC files DEPENDENCIES = $(patsubst %.c,%.inc,$(CSRC)) # my library collection LIB = lib # the library files to use # this will be populated using includes based DEPENDENCIES LIB_CSRC = LIB_CHDR = $(patsubst %.c,%.h,$(LIB_CSRC)) LIB_OBJ = $(patsubst %.c,%.o,$(LIB_CSRC)) # populates LIB_CSRC based on the library files used -include $(DEPENDENCIES) # executables PREFIX ?= arm-none-eabi CC := $(PREFIX)-gcc CXX := $(PREFIX)-g++ LD := $(PREFIX)-gcc AR := $(PREFIX)-ar AS := $(PREFIX)-as OBJCOPY := $(PREFIX)-objcopy OBJDUMP := $(PREFIX)-objdump GDB := $(PREFIX)-gdb # opencm3 libraries OPENCM3_DIR := libopencm3 INCLUDE_DIR = $(OPENCM3_DIR)/include LIB_DIR = $(OPENCM3_DIR)/lib SCRIPT_DIR = $(OPENCM3_DIR)/scripts # verify if libopencm3 has been downloaded OPENCM3_DIR_EXISTS = $(shell [ -d $(OPENCM3_DIR) ] && echo 1 || echo 0 ) ifeq ($(OPENCM3_DIR_EXISTS), 0) $(info run "git submodule init" and "git submodule update" before runnig make) $(error libopencm3 repository is not initialized) endif # device flags DEFS += -DSTM32F1 -D$(BOARD) # C flags CFLAGS += -Os -g CFLAGS += -std=c99 -Wpedantic -Wall -Werror -Wundef -Wextra -Wshadow -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes -Wstrict-overflow=5 CFLAGS += -fno-common -ffunction-sections -fdata-sections CFLAGS += -I. -I$(INCLUDE_DIR) $(patsubst %,-I%,$(LIB)) CFLAGS += $(DEFS) # linker script ifeq ($(BOARD),SYSTEM_BOARD) LDSCRIPT = stm32f103x8-dfu.ld else ifeq ($(BOARD),BLUE_PILL) LDSCRIPT = stm32f103x8-dfu.ld else ifeq ($(BOARD),MAPLE_MINI) LDSCRIPT = stm32f103xb-dfu.ld endif # linker flags LDFLAGS += --static -nostartfiles LDFLAGS += -L$(LIB_DIR) LDFLAGS += -I. $(patsubst %,-I%,$(LIB)) LDFLAGS += -T$(LDSCRIPT) LDFLAGS += -Wl,-Map=$(*).map LDFLAGS += -Wl,--gc-sections ifeq ($(V),99) LDFLAGS += -Wl,--print-gc-sections endif # used libraries LIBNAME = opencm3_stm32f1 LDLIBS += -lm -l$(LIBNAME) LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group # device specific flags FP_FLAGS ?= -msoft-float ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd # SWD adapter used # supported are : st-link v2 (STLINKV2), black magic probe (BMP) SWD_ADAPTER ?= STLINKV2 ifeq ($(SWD_ADAPTER),STLINKV2) # OpenOCD configuration OOCD ?= openocd OOCD_INTERFACE ?= stlink-v2 OOCD_TARGET ?= stm32f1x else ifeq ($(SWD_ADAPTER),BMP) # the black magic probe has a SWD controller built in BMPPORT ?= /dev/ttyACM0 endif # which USB CDC ACM port is used bu the device, so we can reset it ifeq ($(SWD_ADAPTER),STLINKV2) ACMPORT = /dev/ttyACM0 else ifeq ($(SWD_ADAPTER),BMP) ACMPORT = /dev/ttyACM2 endif ACMPORT_EXISTS = $(shell [ -e $(ACMPORT) ] && echo 1 || echo 0 ) # compile target rules all: elf elf: $(BINARY).elf bin: $(BINARY).bin hex: $(BINARY).hex srec: $(BINARY).srec list: $(BINARY).list %.bin %.hex %.srec: %.elf $(Q)$(OBJCOPY) -Osrec $(<) $(@) %.map %.list: %.elf $(Q)$(OBJDUMP) -S $(<) > $(@) %.elf: $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a $(OBJ) $(LIB_OBJ) $(info compiling $(@)) $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJ) $(LIB_OBJ) $(LDLIBS) -o $(@) $(Q)size $(@) %.o: %.c $(CHDR) $(LIB_CHDR) $(Q)$(CC) $(CFLAGS) $(ARCH_FLAGS) -o $(@) -c $(<) # generate dependencies %.d: %.c @# check which libraries are used $(Q)$(CC) $(CFLAGS) $(ARCH_FLAGS) -MM -MF $(@) -o /dev/null -c $(<) # figure out which library source files are used for later inclusion %.inc: %.d $(Q)grep -o -e " ${LIB}\/[^ ]*\.h" $(<) | sed -e 's/\.h$$/.c/g' -e 's/^/LIB_CSRC +=/' > $(@) # doxygen documentation doc: Doxyfile README.md $(CSRC) $(CHDR) $(LIB_CSRC) $(LIB_CHDR) $(Q)doxygen $(<) clean: $(Q)$(RM) $(BINARY).elf $(BINARY).bin $(BINARY).hex $(BINARY).map $(OBJ) $(LIB_OBJ) $(LIB)/*.o $(DEPENDENCIES) # make libopencm3 if not done $(LIB_DIR)/lib$(LIBNAME).a: $(info compiling libopencm3 library) $(Q)$(MAKE) -C $(OPENCM3_DIR) flash: $(BINARY).hex $(info flashing $(<) using SWD) ifeq ($(SWD_ADAPTER),STLINKV2) $(Q)$(OOCD) --file interface/$(OOCD_INTERFACE).cfg --file target/$(OOCD_TARGET).cfg --command "init" --command "reset init" --command "flash write_image erase $(<)" --command "reset" --command "shutdown" $(NULL) else ifeq ($(SWD_ADAPTER),BMP) $(Q)$(GDB) --eval-command="target extended-remote $(BMPPORT)" --eval-command="monitor version" --eval-command="monitor swdp_scan" --eval-command="attach 1" --eval-command="load" --eval-command="detach" --eval-command="kill" --eval-command="quit" $(<) endif # reset device by setting the data width to 5 bis on the USB CDC ACM port reset: ifeq ($(ACMPORT_EXISTS), 1) $(Q)stty --file $(ACMPORT) 115200 raw cs5 $(Q)sleep 0.5 endif # debug using GDB debug: $(BINARY).elf ifeq ($(SWD_ADAPTER),STLINKV2) # for GDB to work with openOCD the firmware needs to be reloaded $(Q)$(GDB) --eval-command="target remote | $(OOCD) --file interface/$(OOCD_INTERFACE).cfg --file target/$(OOCD_TARGET).cfg --command \"gdb_port pipe; log_output /dev/null; init\"" --eval-command="monitor reset halt" --eval-command="load" --eval-command="monitor reset init" $(<) else ifeq ($(SWD_ADAPTER),BMP) $(Q)$(GDB) --eval-command="target extended-remote $(BMPPORT)" --eval-command="monitor version" --eval-command="monitor swdp_scan" --eval-command="attach 1" $(<) endif .PHONY: clean elf bin hex srec list libraries flash reset