## 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 # main names (without extension, for input source file and output binary) APPLICATION = application BOOTLOADER = bootloader FIRMWARE = $(APPLICATION) $(BOOTLOADER) # which development board is used # supported are: SYSTEM_BOARD, MAPLE_MINI, BLUE_PILL, CORE_BOARD BOARD = BLUE_PILL # source files (this will be populated using includes based DEPENDENCIES) CSRC = global.c # headers corresponding to source files CHDR = $(patsubst %.c,%.h,$(CSRC)) # objects compiled from source files OBJ = $(patsubst %.c,%.o,$(CSRC)) # figure out based on the main sources files which library files are used DEPENDENCIES = $(patsubst %,%.inc,$(FIRMWARE)) # populates CSRC based on the library files used -include $(DEPENDENCIES) # executables for linking, compiling, debugging, ... # use ELLCC cross-compiling chain (based on clang/llvm + musl) ELLCC := /opt/ellcc/ # use ELLCC as compile CC := $(ELLCC)bin/ecc -target arm-none-eabi LD := $(PREFIX)-ld LD := $(ELLCC)bin/ecc-ld -m armelf AR := $(ELLCC)bin/ecc-ar AS := $(ELLCC)bin/ecc-as OBJCOPY := $(ELLCC)bin/ecc-objcopy OBJDUMP := $(ELLCC)bin/ecc-objdump GDB := $(ELLCC)bin/ecc-gdb # ecc-gdb (0.13.3) is buggy (crash on kill, can't load elf) GDB := arm-none-eabi-gdb # opencm3 libraries OPENCM3_DIR := libopencm3 OPENCM3_INC = $(OPENCM3_DIR)/include OPENCM3_LIB = $(OPENCM3_DIR)/lib # library for the STM32F1 (provided by opencm3) STM32F1_LIB = opencm3_stm32f1 # linker script for STM32F103x8 boards (MAPLE_MINI has STM32F103xB with just more 128 kB flash instead of 64 kB, thus is compatible) ifeq ($(BOARD),SYSTEM_BOARD) LDSCRIPT = $(OPENCM3_DIR)/lib/stm32/f1/stm32f103x8.ld else ifeq ($(BOARD),BLUE_PILL) LDSCRIPT = $(OPENCM3_DIR)/lib/stm32/f1/stm32f103x8.ld else ifeq ($(BOARD),CORE_BOARD) LDSCRIPT = $(OPENCM3_DIR)/lib/stm32/f1/stm32f103x8.ld else ifeq ($(BOARD),MAPLE_MINI) LDSCRIPT = $(OPENCM3_DIR)/lib/stm32/f1/stm32f103xb.ld endif LDSCRIPT = application.ld # device micro-controller and board DEFS += -DSTM32F1 -D$(BOARD) # C flags # optimize for size CFLAGS += -Os # add debug symbols (remove for smaller release) CFLAGS += -ggdb # use C99 (supported by most an sufficient) CFLAGS += -std=c99 # have strict warning (for better code) CFLAGS += -Wpedantic -Wall -Werror -Wundef -Wextra -Wshadow -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes -Wstrict-overflow=5 # add options for better code optimization CFLAGS += -fno-common -ffunction-sections -fdata-sections # use variable size enum (opencm3, gcc, and compiler-rt do) #CFLAGS += -fshort-enums # use no variable size enum (ELLCC/musl does not) CFLAGS += -fno-short-enums # don't use system main definition (the starting point) CFLAGS += -ffreestanding # don't use the standard library CFLAGS += -nostdlib -nostdinc # include ELLCC libraries CFLAGS += -I $(ELLCC)libecc/include/ -I $(ELLCC)libecc/include/arm/ # include own libraries CFLAGS += -I . -I lib # include opencm3 libraries CFLAGS += -I $(OPENCM3_INC) # add defines for micro-controller and board CFLAGS += $(DEFS) # linker flags # build static binary (no shared libraries on the micro-controller) LDFLAGS += -static # don's include the system start files LDFLAGS += -nostartfiles # only keep used sections LDFLAGS += --gc-sections # don't use system libraries LDFLAGS += -nostdlib -nostdinc # add ELLCC standard libraries (for libc, libm, libgcc) LDFLAGS += --library-path $(ELLCC)libecc/lib/cortex-m3-linux/ # opencm3 libraries LDFLAGS += --library-path $(OPENCM3_LIB) # linker script with definitions for micro-controller #LDFLAGS += --script $(LDSCRIPT) # used libraries (gcc provides the ARM ABI, not sure how to replace with compiler-rt) LDLIBS += --library $(STM32F1_LIB) --library c --library m --library gcc # target micro-controller information (ARM Cortex-M3 supports thumb and thumnb2, but does not include a floating point unit) ARCH_FLAGS = -mthumb -mcpu=cortex-m3 -msoft-float # 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 BMP_PORT ?= /dev/ttyACM0 endif # compile target rules all: elf hex bin elf: $(patsubst %,%.elf,$(FIRMWARE)) bin: $(patsubst %,%.bin,$(FIRMWARE)) hex: $(patsubst %,%.hex,$(FIRMWARE)) %.hex: %.elf $(Q)$(OBJCOPY) --strip-all --strip-debug --output-target ihex $(<) $(@) %.bin: %.elf $(Q)$(OBJCOPY) --strip-all --strip-debug --output-target binary $(<) $(@) %.map %.list: %.elf $(Q)$(OBJDUMP) -S $(<) > $(@) %.elf: %.o %.ld $(OBJ) $(OPENCM3_LIB)/lib$(STM32F1_LIB).a $(info linking $(@)) $(Q)$(LD) $(LDFLAGS) --script $(*).ld $(<) $(OBJ) $(LDLIBS) -o $(@) $(Q)size $(@) %.o: %.c $(CHDR) $(info compiling $(@)) $(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$$|CSRC +=\1.c\n-include\1.inc|g' -e 's|.*${*}.*||g' > $(@) # doxygen documentation doc: Doxyfile README.md $(patsubst %,%.c,$(FIRMWARE)) $(CSRC) $(CHDR) $(Q)doxygen $(<) clean: $(Q)$(RM) $(BOOTLOADER).elf $(BOOTLOADER).bin $(BOOTLOADER).hex $(OBJ) $(DEPENDENCIES) # make libopencm3 if library for STM32F1 is not yet existing $(OPENCM3_LIB)/lib$(STM32F1_LIB).a: $(info compiling libopencm3 library) git submodule init git submodule update $(Q)$(MAKE) CFLAGS=-fno-short-enums -C $(OPENCM3_DIR) # flash application using DFU flash: $(APPLICATION).bin $(Q)dfu-util -d c440:0d00 -D $(<) # flash bootloader using SWD flash_bootloader: $(BOOTLOADER).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 $(BMP_PORT)" --eval-command="set confirm off" --eval-command="monitor swdp_scan" --eval-command="attach 1" --eval-command="load" --eval-command="detach" --eval-command="quit" $(<) endif # flash application using SWD flash_application: $(APPLICATION).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 $(BMP_PORT)" --eval-command="set confirm off" --eval-command="monitor swdp_scan" --eval-command="attach 1" --eval-command="load" --eval-command="detach" --eval-command="quit" $(<) endif # reset device by setting the data width to 5 bis on the USB CDC ACM port ifeq ($(SWD_ADAPTER)$(BMP_PORT),BMP/dev/ttyACM0) ACM_PORT := /dev/ttyACM2 else ACM_PORT := /dev/ttyACM0 endif reset: $(Q)stty --file $(ACM_PORT) raw cs5 $(Q)sleep 0.5 # debug application using GDB debug: $(APPLICATION).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 $(BMP_PORT)" --eval-command="monitor version" --eval-command="monitor swdp_scan" --eval-command="attach 1" $(<) endif .PHONY: clean elf bin hex srec list flash reset