From 1dcc61138813a9e0f20f01664f7b7cae66f97957 Mon Sep 17 00:00:00 2001 From: Jay Blackman Date: Sun, 1 Jun 2025 04:53:54 +1000 Subject: [PATCH] PICO: Makefile uf2 support using picotool (#14402) * Adding picotool build recipe in makefiles. * Use semaphore in directory for default goal recipe for target * Suggestions from coderabbitai * Further coderabbit suggestions * Wrong case * Minor change to improve logic * Further improvements. - submodules replaced with specific submodule for pico_sdk (to avoid all developers needing this) * Removing need for remote on git submodule update for configs, as we have the commit occurring daily. - made sure config also build uf2 * Simplified firmware output selection for target * Moved UF2 outside of EXST * Missed two remnants of HEX_TARGETS * Adding check for target * As target is known default output can be set in platform mk file or target mk file - no need for file indicator (i.e. .exe or .uf2) * Update config.mk for less verbosity --- Makefile | 141 +++++++++++++++++------------- mk/build_verbosity.mk | 1 + mk/config.mk | 12 +-- mk/tools.mk | 51 +++++++++++ src/platform/SIMULATOR/mk/SITL.mk | 4 + 5 files changed, 142 insertions(+), 67 deletions(-) diff --git a/Makefile b/Makefile index 7be4e6a6d2..c6d2c6463d 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ # Things that the user might override on the commandline # -# The target to build, see BASE_TARGETS/EXE_TARGETS below +# The target or config to build TARGET ?= CONFIG ?= @@ -57,7 +57,11 @@ CFLAGS_DISABLED := FORKNAME = betaflight # Working directories +# ROOT_DIR is the full path to the directory containing this Makefile +ROOT_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +# ROOT is the relative path to the directory containing this Makefile ROOT := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + PLATFORM_DIR := $(ROOT)/src/platform SRC_DIR := $(ROOT)/src/main LIB_MAIN_DIR := $(ROOT)/lib/main @@ -90,12 +94,9 @@ MAKE_PARALLEL = $(if $(filter -j%, $(MAKEFLAGS)),$(EMPTY),-j$(DEFAULT_PAR # pre-build sanity checks include $(MAKE_SCRIPT_DIR)/checks.mk -# list of targets that are executed on host (using exe as goal) -EXE_TARGETS := SITL - # basic target list PLATFORMS := $(sort $(notdir $(patsubst /%,%, $(wildcard $(PLATFORM_DIR)/*)))) -BASE_TARGETS := $(filter-out $(EXE_TARGETS),$(sort $(notdir $(patsubst %/,%,$(dir $(wildcard $(PLATFORM_DIR)/*/target/*/target.mk)))))) +BASE_TARGETS := $(sort $(notdir $(patsubst %/,%,$(dir $(wildcard $(PLATFORM_DIR)/*/target/*/target.mk))))) # configure some directories that are relative to wherever ROOT_DIR is located TOOLS_DIR ?= $(ROOT)/tools @@ -126,7 +127,7 @@ FC_VER_PATCH := $(shell grep " FC_VERSION_PATCH" src/main/build/version.h | awk FC_VER := $(FC_VER_MAJOR).$(FC_VER_MINOR).$(FC_VER_PATCH) -# import config handling +# import config handling (must occur after the hydration of hex, exe and uf2 targets) include $(MAKE_SCRIPT_DIR)/config.mk # default xtal value @@ -134,7 +135,7 @@ HSE_VALUE ?= 8000000 CI_EXCLUDED_TARGETS := $(sort $(notdir $(patsubst %/,%,$(dir $(wildcard $(PLATFORM_DIR)/*/target/*/.exclude))))) CI_COMMON_TARGETS := STM32F4DISCOVERY CRAZYBEEF4SX1280 CRAZYBEEF4FR MATEKF405TE AIRBOTG4AIO TBS_LUCID_FC IFLIGHT_BLITZ_F722 NUCLEOF446 SPRACINGH7EXTREME SPRACINGH7RF -CI_TARGETS := $(filter-out $(CI_EXCLUDED_TARGETS), $(BASE_TARGETS) $(EXE_TARGETS)) $(filter $(CI_COMMON_TARGETS), $(BASE_CONFIGS)) +CI_TARGETS := $(filter-out $(CI_EXCLUDED_TARGETS), $(BASE_TARGETS) $(filter $(CI_COMMON_TARGETS), $(BASE_CONFIGS))) PREVIEW_TARGETS := MATEKF411 AIKONF4V2 AIRBOTG4AIO ZEEZF7V3 FOXEERF745V4_AIO KAKUTEH7 TBS_LUCID_FC SITL SPRACINGH7EXTREME SPRACINGH7RF TARGET_PLATFORM := $(notdir $(patsubst %/,%,$(subst target/$(TARGET)/,, $(dir $(wildcard $(PLATFORM_DIR)/*/target/$(TARGET)/target.mk))))) @@ -142,7 +143,8 @@ TARGET_PLATFORM_DIR := $(PLATFORM_DIR)/$(TARGET_PLATFORM) LINKER_DIR := $(TARGET_PLATFORM_DIR)/link ifneq ($(TARGET),) -include $(TARGET_PLATFORM_DIR)/target/$(TARGET)/target.mk +TARGET_DIR = $(TARGET_PLATFORM_DIR)/target/$(TARGET) +include $(TARGET_DIR)/target.mk endif REVISION := norevision @@ -221,24 +223,17 @@ ifneq ($(HSE_VALUE),) DEVICE_FLAGS := $(DEVICE_FLAGS) -DHSE_VALUE=$(HSE_VALUE) endif -TARGET_DIR = $(TARGET_PLATFORM_DIR)/target/$(TARGET) endif # TARGET specified +ifeq ($(or $(CONFIG),$(TARGET)),) +.DEFAULT_GOAL := all +else +.DEFAULT_GOAL := fwo +endif + # openocd specific includes include $(MAKE_SCRIPT_DIR)/openocd.mk -ifeq ($(CONFIG),) -ifeq ($(TARGET),) -.DEFAULT_GOAL := all -else ifneq ($(filter $(TARGET),$(EXE_TARGETS)),) -.DEFAULT_GOAL := exe -else -.DEFAULT_GOAL := hex -endif -else # ifeq ($(CONFIG),) -.DEFAULT_GOAL := hex -endif - INCLUDE_DIRS := $(INCLUDE_DIRS) \ $(ROOT)/lib/main/MAVLink @@ -364,6 +359,12 @@ CPPCHECK = cppcheck $(CSOURCES) --enable=all --platform=unix64 \ $(addprefix -isystem,$(SYS_INCLUDE_DIRS)) \ -I/usr/include -I/usr/include/linux +ifneq ($(filter fwo hex uf2 bin elf zip, $(MAKECMDGOALS)),) + ifeq ($(TARGET),) + $(error "You must specify a target to build.") + endif +endif + TARGET_NAME := $(TARGET) ifneq ($(CONFIG),) @@ -378,21 +379,22 @@ TARGET_FULLNAME = $(FORKNAME)_$(FC_VER)_$(TARGET_NAME) # # Things we will build # -TARGET_BIN = $(BIN_DIR)/$(TARGET_FULLNAME).bin -TARGET_HEX = $(BIN_DIR)/$(TARGET_FULLNAME).hex -TARGET_EXE = $(BIN_DIR)/$(TARGET_FULLNAME) -TARGET_DFU = $(BIN_DIR)/$(TARGET_FULLNAME).dfu -TARGET_ZIP = $(BIN_DIR)/$(TARGET_FULLNAME).zip -TARGET_OBJ_DIR = $(OBJECT_DIR)/$(TARGET_NAME) -TARGET_ELF = $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME).elf -TARGET_EXST_ELF = $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME)_EXST.elf -TARGET_UNPATCHED_BIN = $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME)_UNPATCHED.bin -TARGET_LST = $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME).lst -TARGET_OBJS = $(addsuffix .o,$(addprefix $(TARGET_OBJ_DIR)/,$(basename $(SRC)))) -TARGET_DEPS = $(addsuffix .d,$(addprefix $(TARGET_OBJ_DIR)/,$(basename $(SRC)))) -TARGET_MAP = $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME).map +TARGET_BIN := $(BIN_DIR)/$(TARGET_FULLNAME).bin +TARGET_HEX := $(BIN_DIR)/$(TARGET_FULLNAME).hex +TARGET_UF2 := $(BIN_DIR)/$(TARGET_FULLNAME).uf2 +TARGET_EXE := $(BIN_DIR)/$(TARGET_FULLNAME) +TARGET_DFU := $(BIN_DIR)/$(TARGET_FULLNAME).dfu +TARGET_ZIP := $(BIN_DIR)/$(TARGET_FULLNAME).zip +TARGET_OBJ_DIR := $(OBJECT_DIR)/$(TARGET_NAME) +TARGET_ELF := $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME).elf +TARGET_EXST_ELF := $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME)_EXST.elf +TARGET_UNPATCHED_BIN := $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME)_UNPATCHED.bin +TARGET_LST := $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME).lst +TARGET_OBJS := $(addsuffix .o,$(addprefix $(TARGET_OBJ_DIR)/,$(basename $(SRC)))) +TARGET_DEPS := $(addsuffix .d,$(addprefix $(TARGET_OBJ_DIR)/,$(basename $(SRC)))) +TARGET_MAP := $(OBJECT_DIR)/$(FORKNAME)_$(TARGET_NAME).map -TARGET_EXST_HASH_SECTION_FILE = $(TARGET_OBJ_DIR)/exst_hash_section.bin +TARGET_EXST_HASH_SECTION_FILE := $(TARGET_OBJ_DIR)/exst_hash_section.bin ifeq ($(DEBUG_MIXED),yes) TARGET_EF_HASH := $(shell echo -n -- "$(EXTRA_FLAGS)" "$(OPTIONS)" "$(DEVICE_FLAGS)" "$(TARGET_FLAGS)" | openssl dgst -md5 -r | awk '{print $$1;}') @@ -407,6 +409,7 @@ CLEAN_ARTIFACTS += $(TARGET_HEX_REV) $(TARGET_HEX) CLEAN_ARTIFACTS += $(TARGET_ELF) $(TARGET_OBJS) $(TARGET_MAP) CLEAN_ARTIFACTS += $(TARGET_LST) CLEAN_ARTIFACTS += $(TARGET_DFU) +CLEAN_ARTIFACTS += $(TARGET_UF2) # Make sure build date and revision is updated on every incremental build $(TARGET_OBJ_DIR)/build/version.o : $(SRC) @@ -482,8 +485,12 @@ $(TARGET_ELF): $(TARGET_OBJS) $(LD_SCRIPT) $(LD_SCRIPTS) $(V1) $(CROSS_CC) -o $@ $(filter-out %.ld,$^) $(LD_FLAGS) $(V1) $(SIZE) $(TARGET_ELF) +$(TARGET_UF2): $(TARGET_ELF) + @echo "Creating UF2 $(TARGET_UF2)" "$(STDOUT)" + $(V1) $(PICOTOOL) uf2 convert $< $@ || { echo "Failed to convert ELF to UF2 format"; exit 1; } + $(TARGET_EXE): $(TARGET_ELF) - @echo Copy $< to $@ "$(STDOUT)" + @echo "Creating exe - copying $< to $@" "$(STDOUT)" $(V1) cp $< $@ # Compile @@ -539,17 +546,11 @@ $(TARGET_OBJ_DIR)/%.o: %.S ## all : Build all currently built targets all: $(CI_TARGETS) +.PHONY: $(BASE_TARGETS) $(BASE_TARGETS): - $(V0) @echo "Building target $@" && \ - $(MAKE) hex TARGET=$@ && \ - echo "Building $@ succeeded." + $(MAKE) fwo TARGET=$@ -$(EXE_TARGETS): - $(V0) @echo "Building executable target $@" && \ - $(MAKE) exe TARGET=$@ && \ - echo "Building $@ succeeded." - -TARGETS_CLEAN = $(addsuffix _clean,$(BASE_TARGETS) $(EXE_TARGETS)) +TARGETS_CLEAN = $(addsuffix _clean,$(BASE_TARGETS)) CONFIGS_CLEAN = $(addsuffix _clean,$(BASE_CONFIGS)) @@ -625,39 +626,56 @@ endif TARGETS_ZIP = $(addsuffix _zip,$(BASE_TARGETS)) ## _zip : build target and zip it (useful for posting to GitHub) +.PHONY: $(TARGETS_ZIP) $(TARGETS_ZIP): - $(V0) $(MAKE) hex TARGET=$(subst _zip,,$@) - $(V0) $(MAKE) zip TARGET=$(subst _zip,,$@) + $(V1) $(MAKE) $(MAKE_PARALLEL) zip TARGET=$(subst _zip,,$@) -zip: - $(V0) zip $(TARGET_ZIP) $(TARGET_HEX) +.PHONY: zip +zip: $(TARGET_HEX) + $(V1) zip $(TARGET_ZIP) $(TARGET_HEX) +.PHONY: binary binary: - $(V0) $(MAKE) $(MAKE_PARALLEL) $(TARGET_BIN) + $(V1) $(MAKE) $(MAKE_PARALLEL) $(TARGET_BIN) +.PHONY: hex hex: - $(V0) $(MAKE) $(MAKE_PARALLEL) $(TARGET_HEX) + $(V1) $(MAKE) $(MAKE_PARALLEL) $(TARGET_HEX) -.phony: exe +.PHONY: uf2 +uf2: + $(V1) $(MAKE) $(MAKE_PARALLEL) $(TARGET_UF2) + +.PHONY: exe exe: $(TARGET_EXE) -TARGETS_REVISION = $(addsuffix _rev,$(BASE_TARGETS)) +# FWO (Firmware Output) is the default output for building the firmware +.PHONY: fwo +fwo: +ifeq ($(DEFAULT_OUTPUT),exe) + $(V1) $(MAKE) exe +else ifeq ($(DEFAULT_OUTPUT),uf2) + $(V1) $(MAKE) uf2 +else + $(V1) $(MAKE) hex +endif + +TARGETS_REVISION = $(addsuffix _rev, $(BASE_TARGETS)) ## _rev : build target and add revision to filename +.PHONY: $(TARGETS_REVISION) $(TARGETS_REVISION): - $(V0) $(MAKE) hex REV=yes TARGET=$(subst _rev,,$@) + $(V1) $(MAKE) fwo REV=yes TARGET=$(subst _rev,,$@) -EXE_TARGETS_REVISION = $(addsuffix _rev,$(EXE_TARGETS)) -## _rev : build executable target and add revision to filename -$(EXE_TARGETS_REVISION): - $(V0) $(MAKE) exe REV=yes TARGET=$(subst _rev,,$@) - -all_rev: $(addsuffix _rev,$(CI_TARGETS)) +.PHONY: all_rev +all_rev: $(addsuffix _rev, $(CI_TARGETS)) +.PHONY: unbrick_$(TARGET) unbrick_$(TARGET): $(TARGET_HEX) $(V0) stty -F $(SERIAL_DEVICE) raw speed 115200 -crtscts cs8 -parenb -cstopb -ixon $(V0) stm32flash -w $(TARGET_HEX) -v -g 0x0 -b 115200 $(SERIAL_DEVICE) ## unbrick : unbrick flight controller +.PHONY: unbrick unbrick: unbrick_$(TARGET) ## cppcheck : run static analysis on C source code @@ -690,7 +708,7 @@ help: Makefile mk/tools.mk @echo "To populate configuration targets:" @echo " make configs" @echo "" - @echo "Valid TARGET values are: $(EXE_TARGETS) $(BASE_TARGETS)" + @echo "Valid TARGET values are: $(BASE_TARGETS)" @echo "" @sed -n 's/^## //p' $? @@ -698,7 +716,6 @@ help: Makefile mk/tools.mk targets: @echo "Platforms: $(PLATFORMS)" @echo "Valid targets: $(BASE_TARGETS)" - @echo "Executable targets: $(EXE_TARGETS)" @echo "Built targets: $(CI_TARGETS)" @echo "Default target: $(TARGET)" @echo "CI common targets: $(CI_COMMON_TARGETS)" diff --git a/mk/build_verbosity.mk b/mk/build_verbosity.mk index 9d2f5dc3f3..c1c6206b43 100644 --- a/mk/build_verbosity.mk +++ b/mk/build_verbosity.mk @@ -9,6 +9,7 @@ ifndef V export V0 := export V1 := $(AT) export STDOUT := +export MAKE := $(MAKE) --no-print-directory else ifeq ($(V), 0) export V0 := $(AT) export V1 := $(AT) diff --git a/mk/config.mk b/mk/config.mk index 5f85d4987d..d1c9e54c65 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -57,21 +57,23 @@ endif #config .PHONY: configs configs: ifeq ($(shell realpath $(CONFIG_DIR)),$(shell realpath $(CONFIGS_SUBMODULE_DIR))) - git submodule update --init --remote -- $(CONFIGS_SUBMODULE_DIR) + @echo "Updating config submodule: $(CONFIGS_SUBMODULE_DIR)" + $(V1) git submodule update --init -- $(CONFIGS_SUBMODULE_DIR) || { echo "Config submodule update failed. Please check your git configuration."; exit 1; } + @echo "Submodule update succeeded." else ifeq ($(wildcard $(CONFIG_DIR)),) @echo "Hydrating clone for configs: $(CONFIG_DIR)" - $(V0) git clone $(CONFIGS_REPO_URL) $(CONFIG_DIR) + $(V1) git clone $(CONFIGS_REPO_URL) $(CONFIG_DIR) else - $(V0) git -C $(CONFIG_DIR) pull origin + $(V1) git -C $(CONFIG_DIR) pull origin endif endif $(BASE_CONFIGS): @echo "Building target config $@" - $(V0) $(MAKE) $(MAKE_PARALLEL) hex CONFIG=$@ + $(V0) $(MAKE) fwo CONFIG=$@ @echo "Building target config $@ succeeded." ## _rev : build configured target and add revision to filename $(addsuffix _rev,$(BASE_CONFIGS)): - $(V0) $(MAKE) $(MAKE_PARALLEL) hex CONFIG=$(subst _rev,,$@) REV=yes + $(V0) $(MAKE) fwo CONFIG=$(subst _rev,,$@) REV=yes diff --git a/mk/tools.mk b/mk/tools.mk index 3dc42ab47a..0b53aedecb 100644 --- a/mk/tools.mk +++ b/mk/tools.mk @@ -331,3 +331,54 @@ breakpad_clean: $(V1) [ ! -d "$(BREAKPAD_DIR)" ] || $(RM) -rf $(BREAKPAD_DIR) @echo " CLEAN $(BREAKPAD_DL_FILE)" $(V1) $(RM) -f $(BREAKPAD_DL_FILE) + +# Raspberry Pi Pico tools +PICOTOOL_REPO := https://github.com/raspberrypi/picotool.git +PICOTOOL_DL_DIR := $(DL_DIR)/picotool +PICOTOOL_BUILD_DIR := $(PICOTOOL_DL_DIR)/build +PICOTOOL_DIR := $(TOOLS_DIR)/picotool +PICO_SDK_PATH ?= $(ROOT_DIR)/lib/main/pico-sdk +PICOTOOL ?= $(PICOTOOL_DIR)/picotool + +ifneq ($(filter picotool_install uf2,$(MAKECMDGOALS)),) + ifeq ($(wildcard $(PICO_SDK_PATH)/CMakeLists.txt),) + $(error "PICO_SDK_PATH ($(PICO_SDK_PATH)) does not point to a valid Pico SDK. Please 'make pico_sdk' to hydrate the Pico SDK.") + endif +endif + +ifneq ($(filter uf2,$(MAKECMDGOALS)),) + ifeq (,$(wildcard $(PICOTOOL))) + ifeq (,$(shell which picotool 2>/dev/null)) + $(error "picotool not in the PATH or configured. Run 'make picotool_install' to install in the tools folder.") + else + PICOTOOL := picotool + endif + endif +endif + +.PHONY: pico_sdk +pico_sdk: + @echo "Updating pico-sdk" + $(V1) git submodule update --init --recursive -- lib/main/pico-sdk || { echo "Failed to update pico-sdk"; exit 1; } + @echo "pico-sdk updated" + +.PHONY: picotool_install +picotool_install: | $(DL_DIR) $(TOOLS_DIR) +picotool_install: picotool_clean + @echo "\n CLONE $(PICOTOOL_REPO)" + $(V1) git clone --depth 1 $(PICOTOOL_REPO) "$(PICOTOOL_DL_DIR)" || { echo "Failed to clone picotool repository"; exit 1; } + @echo "\n BUILD $(PICOTOOL_BUILD_DIR)" + $(V1) [ -d "$(PICOTOOL_DIR)" ] || mkdir -p $(PICOTOOL_DIR) + $(V1) [ -d "$(PICOTOOL_BUILD_DIR)" ] || mkdir -p $(PICOTOOL_BUILD_DIR) + $(V1) cmake -S $(PICOTOOL_DL_DIR) -B $(PICOTOOL_BUILD_DIR) -D PICO_SDK_PATH=$(PICO_SDK_PATH) || { echo "CMake configuration failed"; exit 1; } + $(V1) $(MAKE) -C $(PICOTOOL_BUILD_DIR) || { echo "picotool build failed"; exit 1; } + $(V1) cp $(PICOTOOL_BUILD_DIR)/picotool $(PICOTOOL_DIR)/picotool || { echo "Failed to install picotool binary"; exit 1; } + @echo "\n VERSION:" + $(V1) $(PICOTOOL_DIR)/picotool version + +.PHONY: picotool_clean +picotool_clean: + @echo " CLEAN $(PICOTOOL_DIR)" + $(V1) [ ! -d "$(PICOTOOL_DIR)" ] || $(RM) -rf $(PICOTOOL_DIR) + @echo " CLEAN $(PICOTOOL_DL_DIR)" + $(V1) [ ! -d "$(PICOTOOL_DL_DIR)" ] || $(RM) -rf $(PICOTOOL_DL_DIR) diff --git a/src/platform/SIMULATOR/mk/SITL.mk b/src/platform/SIMULATOR/mk/SITL.mk index 989306556f..757b0e4da8 100644 --- a/src/platform/SIMULATOR/mk/SITL.mk +++ b/src/platform/SIMULATOR/mk/SITL.mk @@ -1,3 +1,7 @@ +# SITL Makefile for the simulator platform + +# Default output is an exe file +DEFAULT_OUTPUT := exe INCLUDE_DIRS := \ $(INCLUDE_DIRS) \