2017-08-06 09:52:47 +02:00
|
|
|
# encoding: utf-8
|
|
|
|
# ruby: 2.4.2
|
|
|
|
=begin
|
2020-11-24 15:51:03 +01:00
|
|
|
Rakefile to manage compiling CuVoodoo STM32F4 firmware.
|
|
|
|
the firmware is for development boards based around a STM32F4xx micro-controller.
|
2017-08-06 09:52:47 +02:00
|
|
|
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
|
2020-11-24 15:51:03 +01:00
|
|
|
# supported are: WeAct MiniF4 with STM32F401
|
|
|
|
BOARD = ENV["BOARD"] || "MINIF401"
|
2020-11-27 15:29:57 +01:00
|
|
|
# get MCU from board
|
|
|
|
DEVICE = case BOARD
|
|
|
|
when "MINIF401"
|
|
|
|
"stm32f401cc"
|
|
|
|
else
|
|
|
|
raise "unknown MCU for board #{BOARD}"
|
|
|
|
end
|
2017-08-06 09:52:47 +02:00
|
|
|
|
|
|
|
# libopencm3 definitions
|
|
|
|
LIBOPENCM3_DIR = "libopencm3"
|
|
|
|
LIBOPENCM3_INC = LIBOPENCM3_DIR+"/include"
|
2020-11-27 15:29:57 +01:00
|
|
|
LIBOPENCM3_LIBS = LIBOPENCM3_DIR+"/lib"
|
2020-12-10 23:51:03 +01:00
|
|
|
# get libopencm3
|
|
|
|
unless File.file?("./#{LIBOPENCM3_DIR}/scripts/genlink.py") then
|
|
|
|
sh "git submodule init"
|
|
|
|
sh "git submodule update"
|
|
|
|
end
|
2020-11-27 15:29:57 +01:00
|
|
|
LIBOPENCM3_LIB = "opencm3_" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} FAMILY`
|
2017-08-06 09:52:47 +02:00
|
|
|
|
|
|
|
# source code used by the firmware
|
|
|
|
SRC_DIRS = [".", "lib"]
|
|
|
|
|
|
|
|
# cross-compiler environment
|
|
|
|
PREFIX = ENV["PREFIX"] || "arm-none-eabi"
|
2017-10-09 17:59:12 +02:00
|
|
|
CC = PREFIX+"-gcc"
|
2018-06-08 13:40:38 +02:00
|
|
|
# LD would be the proper linker, but gcc comes with essential library path finder
|
|
|
|
LD = PREFIX+"-gcc"
|
2017-08-06 09:52:47 +02:00
|
|
|
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)
|
2020-11-28 15:19:13 +01:00
|
|
|
cflags << "-ggdb3"
|
2017-08-06 09:52:47 +02:00
|
|
|
# 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"
|
|
|
|
# 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
|
2020-11-27 15:29:57 +01:00
|
|
|
cflags << "-D#{BOARD}"
|
|
|
|
cflags << `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} CPPFLAGS`
|
2017-08-06 09:52:47 +02:00
|
|
|
# render cflags
|
|
|
|
cflags = cflags.compact*' '
|
|
|
|
|
|
|
|
# linker flags
|
2018-06-08 13:40:38 +02:00
|
|
|
ldflags = []
|
2017-08-06 09:52:47 +02:00
|
|
|
# build static binary (no shared libraries on the micro-controller)
|
|
|
|
ldflags << "-static"
|
|
|
|
# don't include the system start files
|
|
|
|
ldflags << "-nostartfiles"
|
2018-06-08 13:40:38 +02:00
|
|
|
# linker specific flags
|
|
|
|
ldflags_linker = [ENV["LDFLAGS"]]
|
2017-08-06 09:52:47 +02:00
|
|
|
# only keep used sections
|
2018-06-08 13:40:38 +02:00
|
|
|
ldflags_linker = ["--gc-sections"]
|
2019-11-19 10:23:48 +01:00
|
|
|
# show memory usage
|
|
|
|
ldflags_linker << "--print-memory-usage"
|
2018-06-08 13:40:38 +02:00
|
|
|
# add libopencm3 libraries
|
2020-11-27 15:29:57 +01:00
|
|
|
library_paths = [LIBOPENCM3_LIBS]
|
2018-06-08 13:40:38 +02:00
|
|
|
# project libraries
|
2020-11-27 15:29:57 +01:00
|
|
|
ldlibs = [LIBOPENCM3_LIB]
|
2018-06-08 13:40:38 +02:00
|
|
|
# general libraries (gcc provides the ARM ABI)
|
|
|
|
ldlibs_linker = ["m", "c", "nosys", "gcc"]
|
2017-08-06 09:52:47 +02:00
|
|
|
|
2020-11-24 15:51:03 +01:00
|
|
|
# target micro-controller information (ARM Cortex-M4 supports thumb and thumb2, but does not include a floating point unit)
|
2020-11-27 15:29:57 +01:00
|
|
|
archflags = "-mthumb"
|
|
|
|
archflags += " -mcpu=" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} CPU`
|
|
|
|
archflags += " -mfloat-abi=" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} FPU`.split("-")[0]
|
|
|
|
archflags += " -mfpu=" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} FPU`.split("-")[1..-1]*"-"
|
2017-08-06 09:52:47 +02:00
|
|
|
|
|
|
|
desc "compile firmwares"
|
|
|
|
task :default => FIRMWARES
|
2018-02-18 15:20:01 +01:00
|
|
|
task :compile => FIRMWARES
|
2017-08-06 09:52:47 +02:00
|
|
|
|
|
|
|
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
|
2021-03-10 14:13:54 +01:00
|
|
|
def dependencies(source, done = [])
|
2017-08-06 09:52:47 +02:00
|
|
|
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
|
2021-03-10 14:13:54 +01:00
|
|
|
d_file = d_file.split(': ')[1].gsub("\n", '').gsub('\\ ', '').gsub(/\s+/, ' ').split(' ') # get a list of dependencies
|
2017-08-06 09:52:47 +02:00
|
|
|
d_list = [] # list of dependencies
|
|
|
|
# only save dependencies which are in our source directories
|
|
|
|
d_file.each do |d|
|
|
|
|
SRC_DIRS.each do |dir|
|
2021-03-10 14:13:54 +01:00
|
|
|
if File.dirname(d) == dir then
|
2021-03-10 14:14:19 +01:00
|
|
|
d_list << d unless d.end_with?(".inc")
|
2017-08-06 09:52:47 +02:00
|
|
|
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 "compile libopencm3"
|
2020-12-10 23:51:03 +01:00
|
|
|
file "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a" do
|
2017-08-06 09:52:47 +02:00
|
|
|
sh "make --directory #{LIBOPENCM3_DIR}"
|
|
|
|
end
|
|
|
|
|
|
|
|
task :doc => ["Doxyfile", "README.md"] do |t|
|
|
|
|
sh "doxygen #{t.source}"
|
|
|
|
end
|
|
|
|
|
|
|
|
desc "compile source into object"
|
2020-11-27 15:29:57 +01:00
|
|
|
rule '.o' => ['.c', proc{|f| File.file?(f.ext("h")) ? f.ext("h") : []}, proc{|f| dependencies(f).collect{|d| File.file?(d.ext("h")) ? d.ext("h") : []}}, "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a"] do |t|
|
2017-10-04 14:25:34 +02:00
|
|
|
sh "#{CC} #{cflags} #{archflags} -o #{t.name} -c #{t.prerequisites[0]}"
|
2017-08-06 09:52:47 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
desc "generate dependencies"
|
2020-11-27 15:29:57 +01:00
|
|
|
rule '.d' => ['.c', "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a"] do |t|
|
2017-10-04 14:25:34 +02:00
|
|
|
sh "#{CC} #{cflags} #{archflags} -MM -MF #{t.name} -c #{t.prerequisites[0]}"
|
2017-08-06 09:52:47 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
desc "link binary"
|
2020-11-27 15:29:57 +01:00
|
|
|
rule '.elf' => ['.o', proc{|f| dependencies(f)}, '.ld', "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a"] do |t|
|
2018-06-08 13:40:38 +02:00
|
|
|
sh "#{LD} #{archflags} #{ldflags.join(' ')} #{t.prerequisites[0..-3].join(' ')} -T#{t.name.ext('ld')} #{ldflags_linker.collect{|flag| "-Wl,"+flag}.join(' ')} #{library_paths.collect{|path| "-L"+path}.join(' ')} #{ldlibs.collect{|lib| "-l"+lib}.join(' ')} -Wl,--start-group #{ldlibs_linker.collect{|lib| "-l"+lib}.join(' ')} -Wl,--end-group --output #{t.name}"
|
2017-08-06 09:52:47 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
desc "export binary"
|
|
|
|
rule '.bin' => '.elf' do |t|
|
2018-02-18 15:21:18 +01:00
|
|
|
sh "#{OBJCOPY} --output-target binary #{t.source} #{t.name}"
|
2017-08-06 09:52:47 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
desc "export intel hex file"
|
|
|
|
rule '.hex' => '.elf' do |t|
|
2018-02-18 15:21:18 +01:00
|
|
|
sh "#{OBJCOPY} --output-target ihex #{t.source} #{t.name}"
|
2017-08-06 09:52:47 +02:00
|
|
|
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)
|
2020-03-15 18:24:23 +01:00
|
|
|
SWD_ADAPTER = ENV["SWD_ADAPTER"] || "STLINKV2"
|
2017-08-06 09:52:47 +02:00
|
|
|
# openOCD path to control the adapter
|
|
|
|
OOCD = ENV["OOCD"] || "openocd"
|
|
|
|
# openOCD adapted name
|
2019-04-01 15:17:06 +02:00
|
|
|
OOCD_INTERFACE = ENV["OOCD_INTERFACE"] || (SWD_ADAPTER=="STLINKV2" ? "stlink" : "")
|
2017-08-06 09:52:47 +02:00
|
|
|
# openOCD target for the micro-controller
|
2020-11-24 15:51:03 +01:00
|
|
|
OOCD_TARGET = "stm32f4x"
|
2017-08-06 09:52:47 +02:00
|
|
|
# Black Magic Probe port
|
|
|
|
BMP_PORT = ENV["BMP_PORT"] || "/dev/ttyACM0"
|
|
|
|
|
2020-11-27 16:39:11 +01:00
|
|
|
desc "flash application"
|
|
|
|
task :flash => :dfu_application
|
|
|
|
|
2017-08-06 09:52:47 +02:00
|
|
|
desc "flash application using USB DFU"
|
2020-11-27 16:39:11 +01:00
|
|
|
task :dfu_application => APPLICATION+".bin" do |t|
|
2018-08-11 18:41:23 +02:00
|
|
|
sh "dfu-util --device 1209:4356 --download #{t.source}"
|
2017-08-06 09:52:47 +02:00
|
|
|
end
|
|
|
|
|
2020-11-27 16:39:11 +01:00
|
|
|
desc "flash application using USB DFU"
|
|
|
|
task :dfu_bootloader => BOOTLOADER+".bin" do |t|
|
|
|
|
sh "dfu-util --device 0483:df11 --cfg 1 --intf 0 --alt 0 --dfuse-address 0x08000000 --download #{t.source} --reset"
|
|
|
|
end
|
|
|
|
|
2020-11-24 15:51:03 +01:00
|
|
|
desc "remove STM32F4 protection using SWD"
|
2019-04-01 15:16:09 +02:00
|
|
|
task :remove_protection do
|
|
|
|
case SWD_ADAPTER
|
|
|
|
when "STLINKV2"
|
2020-11-30 14:51:06 +01:00
|
|
|
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'stm32f2x unlock 0' --command 'reset init' --command 'flash protect 0 0 last off' --command 'reset init' --command 'stm32f2x mass_erase 0' --command 'shutdown'"
|
2019-04-01 15:16:09 +02:00
|
|
|
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='monitor option erase' --eval-command='monitor erase_mass' --eval-command='kill' --eval-command='quit'"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-06 09:52:47 +02:00
|
|
|
desc "flash bootloader using SWD"
|
2020-11-27 16:39:11 +01:00
|
|
|
task :swd_bootloader => BOOTLOADER+".hex" do |t|
|
2017-08-06 09:52:47 +02:00
|
|
|
case SWD_ADAPTER
|
|
|
|
when "STLINKV2"
|
2020-11-24 15:51:03 +01:00
|
|
|
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'flash erase_sector 0 0 last' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
|
2017-08-06 09:52:47 +02:00
|
|
|
when "BMP"
|
2020-01-04 14:32:52 +01:00
|
|
|
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='monitor erase_mass' --eval-command='load' --eval-command='kill' --eval-command='quit' #{t.source}"
|
2017-08-06 09:52:47 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-27 16:39:11 +01:00
|
|
|
task :swd => :swd_application
|
|
|
|
|
2017-08-06 09:52:47 +02:00
|
|
|
desc "flash application using SWD"
|
2020-11-27 16:39:11 +01:00
|
|
|
task :swd_application => APPLICATION+".hex" do |t|
|
2017-08-06 09:52:47 +02:00
|
|
|
case SWD_ADAPTER
|
|
|
|
when "STLINKV2"
|
2020-11-24 15:51:03 +01:00
|
|
|
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --file target/#{OOCD_TARGET}.cfg --command 'adapter speed 100' --command 'init' --command 'halt' --command 'reset init' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
|
2017-08-06 09:52:47 +02:00
|
|
|
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
|
2020-11-24 15:51:03 +01:00
|
|
|
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' #{t.source}")
|
2017-08-06 09:52:47 +02:00
|
|
|
when "BMP"
|
2018-02-18 15:21:18 +01:00
|
|
|
exec("#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}")
|
2017-08-06 09:52:47 +02:00
|
|
|
end
|
|
|
|
end
|
2020-01-04 14:33:23 +01:00
|
|
|
|
|
|
|
# debug application using GDB
|
|
|
|
desc "debug bootloader using GDB"
|
|
|
|
task :debug_bootloader => BOOTLOADER+".elf" do |t|
|
|
|
|
case SWD_ADAPTER
|
|
|
|
when "STLINKV2"
|
|
|
|
# for GDB to work with openOCD the firmware needs to be reloaded
|
2020-11-24 15:51:03 +01:00
|
|
|
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset init' #{t.source}")
|
2020-01-04 14:33:23 +01:00
|
|
|
when "BMP"
|
|
|
|
exec("#{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
|