diff --git a/Makefile b/Makefile deleted file mode 100644 index 0bac133..0000000 --- a/Makefile +++ /dev/null @@ -1,227 +0,0 @@ -## 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 = CORE_BOARD - -# 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 -# libraries with source code used (also to be compiled) -SRCLIBS = . lib -# source files (this will be populated using includes based DEPENDENCIES) -CSRC = -# headers (unique, and if existing) corresponding to source files -CHDR = $(sort $(patsubst %.c,%.h,$(wildcard $(CSRC)))) -# objects (unique, and if existing) compiled from source files -OBJ = $(sort $(patsubst %.c,%.o,$(wildcard $(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 clang to compile, GNU ARM toolchain for the rest -PREFIX ?= arm-none-eabi -# use ELLCC as compile -CC := clang -target $(PREFIX) -LD := $(PREFIX)-ld -LD := $(PREFIX)-ld -AR := $(PREFIX)-ar -AS := $(PREFIX)-as -OBJCOPY := $(PREFIX)-objcopy -OBJDUMP := $(PREFIX)-objdump -GDB := $(PREFIX)-gdb - -# 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 (clang doesn't but opencm3, and gcc 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 (only if you provide an alternative libc library) -#CFLAGS += -nostdlib -nostdinc -# include own libraries -CFLAGS += $(foreach lib,$(SRCLIBS),-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 (only if you provide an alternative libc library) -#LDFLAGS += -nostdlib -nostdinc -# add standard libraries (for libc, libm, libnosys, libgcc) -LDFLAGS += --library-path /usr/arm-none-eabi/lib/armv7-m/ -LDFLAGS += --library-path /usr/lib/gcc/arm-none-eabi/*/armv7-m/ -# opencm3 libraries -LDFLAGS += --library-path $(OPENCM3_LIB) -# used libraries (gcc provides the ARM ABI) -LDLIBS += --library $(STM32F1_LIB) --library c --library m --library nosys --library gcc - -# target micro-controller information (ARM Cortex-M3 supports thumb and thumb2, 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 ?= BMP -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) $(OPENCM3_LIB)/lib$(STM32F1_LIB).a - $(info compiling $(@)) - $(Q)$(CC) $(CFLAGS) $(ARCH_FLAGS) -o $(@) -c $(<) - -# find out which library source files also need to be compiled and linked, based on its dependencies -%.inc: %.c $(OPENCM3_LIB)/lib$(STM32F1_LIB).a - $(Q)echo "" > $(@) - $(Q)for dependency in $(shell $(CC) $(CFLAGS) $(ARCH_FLAGS) -MM -c $(<)); do \ - if [ -f "$${dependency}" ]; then \ - for lib in $(SRCLIBS); do \ - if [ `dirname "$${dependency}"` = "$${lib}" ]; then \ - if [ -f `echo "$${dependency}" | sed -e 's|\(.*\)\.h$$|\1.c|'` ]; then \ - echo "$${dependency}" | sed -e 's|\(.*\)\.h$$|CSRC += \1.c\n-include \1.inc|g' -e 's|.*${*}.*||g' >> $(@); \ - fi; \ - fi; \ - done; \ - fi; \ - done - -# get libopencm3 -$(OPENCM3_DIR)/Makefile: - $(info checking out libopencm3 submodule) - $(Q)git submodule init - $(Q)git submodule update - -# compile libopencm3 -$(OPENCM3_LIB)/lib$(STM32F1_LIB).a: $(OPENCM3_DIR)/Makefile - $(info compiling libopencm3 submodule) - $(Q)$(MAKE) --directory $(OPENCM3_DIR) - -# doxygen documentation -doc: Doxyfile README.md $(patsubst %,%.c,$(FIRMWARE)) $(CSRC) $(CHDR) - $(Q)doxygen $(<) - -clean: - $(Q)$(RM) $(BOOTLOADER).elf $(BOOTLOADER).bin $(BOOTLOADER).hex $(APPLICATION).elf $(APPLICATION).bin $(APPLICATION).hex $(OBJ) $(DEPENDENCIES) *.inc lib/*.inc - -# 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="kill" --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 diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..55df3ad --- /dev/null +++ b/Rakefile @@ -0,0 +1,242 @@ +# encoding: utf-8 +# ruby: 2.4.2 +=begin +Rakefile to manage compile CuVoodoo STM32F1 firmware. +the firmware is for development board based around a STM32F1xx micro-controller. +the firmware uses the libopencm3 library providing support for this micro-controller. +=end +require 'rake' +require 'rake/clean' + +# the firmwares to compile +BOOTLOADER = "bootloader" +APPLICATION = "application" +FIRMWARES = [BOOTLOADER, APPLICATION] + +# which development board is used +# supported are: SYSTEM_BOARD, MAPLE_MINI, BLUE_PILL, CORE_BOARD +BOARD = ENV["BOARD"] || "CORE_BOARD" + +# libopencm3 definitions +LIBOPENCM3_DIR = "libopencm3" +LIBOPENCM3_INC = LIBOPENCM3_DIR+"/include" +LIBOPENCM3_LIB = LIBOPENCM3_DIR+"/lib" +# STM32F1 library use for this project provided libtm +STM32F1_LIB = "opencm3_stm32f1" + +# source code used by the firmware +SRC_DIRS = [".", "lib"] + +# cross-compiler environment +PREFIX = ENV["PREFIX"] || "arm-none-eabi" +CC = "clang -target #{PREFIX}" # use clang instead of gcc +LD = PREFIX+"-ld" +AR = PREFIX+"-ar" +AS = PREFIX+"-as" +OBJCOPY = PREFIX+"-objcopy" +OBJDUMP = PREFIX+"-objdump" +GDB = PREFIX+"-gdb" + +# compiler flags +cflags = [ENV["CFLAGS"]] +# 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 (clang doesn't but opencm3, and gcc do) +cflags << "-fshort-enums" +# don't use system main definition (the starting point) +cflags << "-ffreestanding" +# don't use the standard library (only if you provide an alternative libc library) +#cflags << "-nostdlib -nostdinc" +# include own libraries +cflags += SRC_DIRS.collect {|srd_dir| "-I #{srd_dir}"} +# include libopencm3 library +cflags << "-I #{LIBOPENCM3_INC}" +# add defines for micro-controller and board +cflags << "-DSTM32F1 -D#{BOARD}" +# render cflags +cflags = cflags.compact*' ' + +# linker flags +ldflags = [ENV["LDFLAGS"]] +# build static binary (no shared libraries on the micro-controller) +ldflags << "-static" +# don't include the system start files +ldflags << "-nostartfiles" +# only keep used sections +ldflags << "--gc-sections" +# don't use system libraries (only if you provide an alternative libc library) +#ldflags << "-nostdlib -nostdinc" +# add standard libraries (for libc, libm, libnosys, libgcc) and libopencm3 +library_paths = ["/usr/arm-none-eabi/lib/armv7-m/", "/usr/lib/gcc/arm-none-eabi/*/armv7-m/", LIBOPENCM3_LIB] +ldflags += library_paths.collect {|library_path| "--library-path #{library_path}"} +ldflags *= ' ' +# used libraries (gcc provides the ARM ABI) +ldlibs = [STM32F1_LIB, "c", "m", "nosys", "gcc"] +ldlibs = ldlibs.collect {|library| "--library #{library}"} +ldlibs *= ' ' + +# target micro-controller information (ARM Cortex-M3 supports thumb and thumb2, but does not include a floating point unit) +archflags = "-mthumb -mcpu=cortex-m3 -msoft-float" + +desc "compile firmwares" +task :default => FIRMWARES + +FIRMWARES.each do |firmware| + desc "compile #{firmware} firmware" + task firmware => [firmware+".elf", firmware+".bin", firmware+".hex"] + CLOBBER.include(firmware+".elf") + CLOBBER.include(firmware+".bin") + CLOBBER.include(firmware+".hex") + CLOBBER.include(firmware+".list") + CLOBBER.include(firmware+".map") +end + +# get dependencies of a file +# done is a list of already known dependencies +def dependencies(source, done=[]) + d_path = source.ext("d") # get the dependency file + Rake::Task[d_path].invoke # ensure the dependency file exists + d_file = IO.read(d_path) # read the dependencies from dependency file + d_file = d_file.split(': ')[1].gsub("\n",'').gsub('\\ ','').gsub(/\s+/,' ').split(' ') # get a list of dependencies + d_list = [] # list of dependencies + # only save dependencies which are in our source directories + d_file.each do |d| + SRC_DIRS.each do |dir| + if File.dirname(d)==dir then + d_list << d + end + end + end + # get the dependencies of these dependencies, if we don't know them already + done << source.ext("o") + done.uniq! + d_list.each do |d| + d = d.ext("o") + next if done.include? d + done += dependencies(d, done) + end + done.uniq! + return done +end + +desc "get libopencm3" +file LIBOPENCM3_DIR+"/Makefile" do + sh "git submodule init" + sh "git submodule update" +end + +desc "compile libopencm3" +file "#{LIBOPENCM3_LIB}/lib#{STM32F1_LIB}.a" => LIBOPENCM3_DIR+"/Makefile" do + sh "make --directory #{LIBOPENCM3_DIR}" +end + +task :doc => ["Doxyfile", "README.md"] do |t| + sh "doxygen #{t.source}" +end + +desc "compile source into object" +rule '.o' => '.c' do |t| + sh "#{CC} #{cflags} #{archflags} -o #{t.name} -c #{t.source}" +end + +desc "generate dependencies" +rule '.d' => '.c' do |t| + sh "#{CC} #{cflags} #{archflags} -MM -MF #{t.name} -c #{t.source}" +end + +desc "link binary" +rule '.elf' => [proc{|f| dependencies(f)}, '.ld', "#{LIBOPENCM3_LIB}/lib#{STM32F1_LIB}.a"] do |t| + sh "#{LD} #{ldflags} --script #{t.name.ext('ld')} #{t.prerequisites[0..-3].join(' ')} #{ldlibs} -o #{t.name}" + sh "size #{t.name}" +end + +desc "export binary" +rule '.bin' => '.elf' do |t| + sh "#{OBJCOPY} --strip-all --strip-debug --output-target binary #{t.source} #{t.name}" +end + +desc "export intel hex file" +rule '.hex' => '.elf' do |t| + sh "#{OBJCOPY} --strip-all --strip-debug --output-target ihex #{t.source} #{t.name}" +end + +desc "export list" +rule '.list' => '.elf' do |t| + sh "#{OBJDUMP} -S #{t.source} > #{t.name}" +end + +desc "export map" +rule '.map' => '.elf' do |t| + sh "#{OBJDUMP} -S #{t.source} > #{t.name}" +end + +SRC_DIRS.each do |src_dir| + CLEAN.include(src_dir+"/*.o") + CLEAN.include(src_dir+"/*.d") +end + +# SWD/JTAG adapter used +# supported are : STLINKV2 (ST-Link V2), BMP (Black Magic Probe) +SWD_ADAPTER = ENV["SWD_ADAPTER"] || "BMP" +# openOCD path to control the adapter +OOCD = ENV["OOCD"] || "openocd" +# openOCD adapted name +OOCD_INTERFACE = ENV["OOCD_INTERFACE"] || (SWD_ADAPTER=="STLINKV2" ? "stlink-v2" : "") +# openOCD target for the micro-controller +OOCD_TARGET = "stm32f1x" +# Black Magic Probe port +BMP_PORT = ENV["BMP_PORT"] || "/dev/ttyACM0" + +desc "flash application using USB DFU" +task :flash => APPLICATION+".bin" do |t| + sh "dfu-util -d c440:0d00 -D #{t.source}" +end + +desc "flash bootloader using SWD" +task :flash_bootloader => BOOTLOADER+".hex" do |t| + case SWD_ADAPTER + when "STLINKV2" + sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'reset init' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'" + when "BMP" + sh "#{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='kill' --eval-command='quit' #{t.source}" + end +end + +desc "flash application using SWD" +task :flash_application => APPLICATION+".hex" do |t| + case SWD_ADAPTER + when "STLINKV2" + sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'reset init' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'" + when "BMP" + sh "#{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='kill' --eval-command='quit' #{t.source}" + end +end + +# debug application using GDB +desc "debug application using GDB" +task :debug => APPLICATION+".elf" do |t| + case SWD_ADAPTER + when "STLINKV2" + # for GDB to work with openOCD the firmware needs to be reloaded + sh "#{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' #{t.source}" + when "BMP" + sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}" + end +end + +# reset device by setting the data width to 5 bis on the USB CDC ACM port +ACM_PORT = ENV["ACM_PORT"] || ("/dev/ttyACM0"==BMP_PORT ? "/dev/ttyACM2" : "/dev/ttyACM0") + +desc "reset application using serial" +task :reset do + sh "stty --file #{ACM_PORT} raw cs5" + sleep 0.5 +end