diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7d91d1c..94db62f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -226,20 +226,34 @@ DAPLink is the firmware running on the STM32F103 interface chip. It provides the DAPLink consists of **two parts**: -- **Bootloader** (first stage, flashed at `0x08000000`) — installed once at the factory, rarely updated. It provides the MAINTENANCE mode used to update the interface firmware. Updating the bootloader requires an external SWD probe and is not covered by these targets. -- **Interface firmware** (second stage, flashed at `0x08002000`) — the part that contains the I2C bridge, mass-storage, debug interface, and is updated routinely. This is what the `daplink-*` Makefile targets manage. +- **Bootloader** (first stage, flashed at `0x08000000`) — installed once at the factory, rarely updated. It provides the MAINTENANCE mode used to update the interface firmware. Updating it requires an external SWD probe. +- **Interface firmware** (second stage, flashed at `0x08002000`) — contains the I2C bridge, mass-storage, debug interface. Updated routinely, either via the MAINTENANCE USB volume or via an external SWD probe for recovery. ```bash -make daplink-firmware # Clone steamicc/DAPLink and build stm32f103xb_steami32_if -make daplink-update # Refresh the DAPLink clone -make daplink-deploy # Flash DAPLink interface firmware (default: usb mass-storage) -make daplink-deploy-usb # Flash DAPLink interface firmware via MAINTENANCE volume -make daplink-clean # Clean DAPLink build artifacts +make daplink-firmware # Build the interface firmware (stm32f103xb_steami32_if) +make daplink-bootloader # Build the bootloader (stm32f103xb_bl) +make daplink-update # Refresh the DAPLink clone +make daplink-clean # Clean DAPLink build artifacts + +# Routine interface update (no external probe) +make daplink-deploy # Alias for daplink-deploy-usb +make daplink-deploy-usb # Flash interface firmware via MAINTENANCE volume + +# External SWD probe required (recovery, CI, bricked boards) +make daplink-deploy-pyocd # Flash interface firmware via SWD (pyocd) +make daplink-deploy-openocd # Flash interface firmware via SWD (openocd) +make daplink-deploy-bootloader # Flash bootloader via SWD (default: pyocd) +make daplink-deploy-bootloader-pyocd # Flash bootloader via SWD (pyocd) +make daplink-deploy-bootloader-openocd # Flash bootloader via SWD (openocd) ``` The DAPLink source is cloned from [steamicc/DAPLink](https://github.com/steamicc/DAPLink) into `.build/DAPLink/` (gitignored). A Python virtualenv is created automatically inside the clone for the progen build tool. -**Maintenance mode:** to flash the DAPLink interface firmware, the board must be in maintenance mode. Power on the board with the RESET button held until a `MAINTENANCE` USB volume appears (instead of the usual `STeaMi` volume). The `make daplink-deploy-usb` target then copies the firmware to that volume and the board reboots automatically with the new interface firmware. +**MAINTENANCE mode (USB path):** power on the board with the RESET button held until a `MAINTENANCE` USB volume appears (instead of the usual `STeaMi` volume). `make daplink-deploy-usb` copies the interface firmware to that volume and the board reboots automatically. + +**External SWD probe (bootstrap warning):** the `daplink-deploy-*-pyocd` / `-openocd` and all `daplink-deploy-bootloader*` targets flash the DAPLink chip directly via SWD. They require an **external** probe (ST-Link, J-Link, or another CMSIS-DAP board) connected to the target board's SWD header. **A board cannot reflash its own on-board DAPLink via its own SWD pins** — use another board or a standalone probe. These paths are useful for recovering a bricked interface firmware, installing the bootloader at the factory, or automating CI flashing without manual button presses. + +The SWD commands assume an ST-Link probe by default. To use a different probe (another DAPLink board, J-Link, …), override the OpenOCD or pyOCD configuration via `DAPLINK_OPENOCD_INTERFACE`, `DAPLINK_OPENOCD_TRANSPORT`, or `DAPLINK_PYOCD_TARGET` (see `env.mk`). ## Notes diff --git a/Makefile b/Makefile index deccc2f..3c27a5a 100644 --- a/Makefile +++ b/Makefile @@ -151,14 +151,6 @@ echo " make daplink-$(2) (DAPLink firmware)"; \ exit 1 endef -# Variant for short names whose DAPLink counterpart does not exist yet -# (daplink-deploy-pyocd / daplink-deploy-openocd are tracked in #388). -define DEPRECATED_MICROPYTHON_ONLY -@echo "Error: 'make $(1)' has been renamed. Use:"; \ -echo " make micropython-$(2) (MicroPython firmware)"; \ -exit 1 -endef - .PHONY: firmware firmware-update firmware-clean deploy deploy-pyocd deploy-openocd deploy-usb firmware: $(call DEPRECATED_FIRMWARE,firmware,firmware) @@ -169,9 +161,9 @@ firmware-clean: deploy: $(call DEPRECATED_FIRMWARE,deploy,deploy) deploy-pyocd: - $(call DEPRECATED_MICROPYTHON_ONLY,deploy-pyocd,deploy-pyocd) + $(call DEPRECATED_FIRMWARE,deploy-pyocd,deploy-pyocd) deploy-openocd: - $(call DEPRECATED_MICROPYTHON_ONLY,deploy-openocd,deploy-openocd) + $(call DEPRECATED_FIRMWARE,deploy-openocd,deploy-openocd) deploy-usb: $(call DEPRECATED_FIRMWARE,deploy-usb,deploy-usb) @@ -202,11 +194,41 @@ micropython-clean: ## Clean MicroPython firmware build artifacts fi # --- DAPLink firmware --- -# These targets manage the DAPLink **interface firmware** only (the second -# stage of DAPLink, flashed at 0x08002000). The bootloader (first stage, -# flashed at 0x08000000) is installed once at the factory and is not -# managed here. A future `daplink-deploy-bootloader` target could be added -# if needed, but it requires an external SWD probe and is rarely necessary. +# These targets build and flash the DAPLink firmware that runs on the +# STM32F103 interface chip. DAPLink has two parts: +# +# * Bootloader (first stage, `stm32f103xb_bl`) at 0x08000000 +# → rarely updated, requires an external SWD probe. +# * Interface firmware (second stage, `stm32f103xb_steami32_if`) at 0x08002000 +# → updated routinely, typically via the MAINTENANCE USB volume, +# or via an external SWD probe for recovery / bricked boards. +# +# SWD targets (`daplink-deploy-pyocd`, `daplink-deploy-openocd`, +# `daplink-deploy-bootloader*`) need an EXTERNAL probe (ST-Link, J-Link, or +# another CMSIS-DAP board) connected to the SWD header of the target board. +# A board cannot reflash its own DAPLink chip via its own SWD pins. + +define DAPLINK_SWD_WARNING +@echo "================================================================" +@echo "Warning: this target flashes the DAPLink chip via SWD." +@echo "Requires an EXTERNAL probe (ST-Link / J-Link / CMSIS-DAP)" +@echo "connected to the target board's SWD header. A board cannot" +@echo "reflash its own on-board DAPLink via its own SWD pins." +@echo "================================================================" +endef + +define DAPLINK_OPENOCD_FLASH +openocd -f $(DAPLINK_OPENOCD_INTERFACE) \ + -f $(DAPLINK_OPENOCD_TARGET) \ + -c "transport select $(DAPLINK_OPENOCD_TRANSPORT)" \ + -c "reset_config none separate" \ + -c "init" \ + -c "reset halt" \ + -c "stm32f1x unlock 0" \ + -c "reset halt" \ + -c "program $(1) verify $(2)" \ + -c "reset; exit" +endef $(DAPLINK_DIR): @echo "Cloning DAPLink into $(CURDIR)/$(DAPLINK_DIR)..." @@ -248,6 +270,14 @@ daplink-firmware: $(DAPLINK_DIR) $(DAPLINK_GCC_DIR)/bin/arm-none-eabi-gcc $(DAPL ./venv/bin/python tools/progen_compile.py -t make_gcc_arm $(DAPLINK_TARGET) @echo "DAPLink firmware ready: $(DAPLINK_BUILD_DIR)/$(DAPLINK_TARGET)_crc.bin" +.PHONY: daplink-bootloader +daplink-bootloader: $(DAPLINK_DIR) $(DAPLINK_GCC_DIR)/bin/arm-none-eabi-gcc $(DAPLINK_DIR)/venv/.installed ## Build DAPLink bootloader for the STeaMi STM32F103 + @echo "Building DAPLink target $(DAPLINK_BL_TARGET) with gcc-arm-none-eabi $(DAPLINK_GCC_VERSION)..." + cd $(CURDIR)/$(DAPLINK_DIR) && \ + PATH="$(CURDIR)/$(DAPLINK_GCC_DIR)/bin:$(CURDIR)/$(DAPLINK_DIR)/venv/bin:$$PATH" \ + ./venv/bin/python tools/progen_compile.py -t make_gcc_arm $(DAPLINK_BL_TARGET) + @echo "DAPLink bootloader ready: $(DAPLINK_BL_BUILD_DIR)/$(DAPLINK_BL_TARGET)_crc.bin" + .PHONY: daplink-update daplink-update: $(DAPLINK_DIR) ## Update the DAPLink clone @set -e @@ -268,6 +298,33 @@ daplink-deploy-usb: $(DAPLINK_DIR) ## Flash DAPLink interface firmware via MAINT --build-target daplink-firmware \ $(DAPLINK_BUILD_DIR)/$(DAPLINK_TARGET)_crc.bin +.PHONY: daplink-deploy-pyocd +daplink-deploy-pyocd: daplink-firmware ## Flash DAPLink interface firmware via external SWD probe (pyocd) + $(DAPLINK_SWD_WARNING) + $(PYTHON) -m pyocd flash -t $(DAPLINK_PYOCD_TARGET) \ + --base-address $(DAPLINK_FLASH_ADDR) \ + $(DAPLINK_BUILD_DIR)/$(DAPLINK_TARGET)_crc.bin + +.PHONY: daplink-deploy-openocd +daplink-deploy-openocd: daplink-firmware ## Flash DAPLink interface firmware via external SWD probe (openocd) + $(DAPLINK_SWD_WARNING) + $(call DAPLINK_OPENOCD_FLASH,$(DAPLINK_BUILD_DIR)/$(DAPLINK_TARGET)_crc.bin,$(DAPLINK_FLASH_ADDR)) + +.PHONY: daplink-deploy-bootloader +daplink-deploy-bootloader: daplink-deploy-bootloader-pyocd ## Flash DAPLink bootloader via external SWD probe (default: pyocd) + +.PHONY: daplink-deploy-bootloader-pyocd +daplink-deploy-bootloader-pyocd: daplink-bootloader ## Flash DAPLink bootloader via external SWD probe (pyocd) + $(DAPLINK_SWD_WARNING) + $(PYTHON) -m pyocd flash -t $(DAPLINK_PYOCD_TARGET) \ + --base-address $(DAPLINK_BL_FLASH_ADDR) \ + $(DAPLINK_BL_BUILD_DIR)/$(DAPLINK_BL_TARGET)_crc.bin + +.PHONY: daplink-deploy-bootloader-openocd +daplink-deploy-bootloader-openocd: daplink-bootloader ## Flash DAPLink bootloader via external SWD probe (openocd) + $(DAPLINK_SWD_WARNING) + $(call DAPLINK_OPENOCD_FLASH,$(DAPLINK_BL_BUILD_DIR)/$(DAPLINK_BL_TARGET)_crc.bin,$(DAPLINK_BL_FLASH_ADDR)) + .PHONY: daplink-clean daplink-clean: ## Clean DAPLink firmware build artifacts @if [ -d "$(DAPLINK_DIR)" ]; then \ diff --git a/env.mk b/env.mk index 364dde8..cd82212 100644 --- a/env.mk +++ b/env.mk @@ -16,6 +16,18 @@ DAPLINK_BRANCH ?= release_letssteam DAPLINK_DIR ?= $(BUILD_DIR)/DAPLink DAPLINK_TARGET ?= stm32f103xb_steami32_if DAPLINK_BUILD_DIR ?= $(DAPLINK_DIR)/projectfiles/make_gcc_arm/$(DAPLINK_TARGET)/build +DAPLINK_BL_TARGET ?= stm32f103xb_bl +DAPLINK_BL_BUILD_DIR ?= $(DAPLINK_DIR)/projectfiles/make_gcc_arm/$(DAPLINK_BL_TARGET)/build + +# SWD flash configuration (external probe). Used by the `daplink-deploy-*` +# SWD targets. The STM32F103CB on the DAPLink chip is flash-compatible with +# pyOCD's built-in stm32f103rc target for the lower 128 KB. +DAPLINK_FLASH_ADDR ?= 0x08002000 +DAPLINK_BL_FLASH_ADDR ?= 0x08000000 +DAPLINK_PYOCD_TARGET ?= stm32f103rc +DAPLINK_OPENOCD_INTERFACE ?= interface/stlink.cfg +DAPLINK_OPENOCD_TARGET ?= target/stm32f1x.cfg +DAPLINK_OPENOCD_TRANSPORT ?= hla_swd # DAPLink requires gcc-arm-none-eabi 10.3-2021.10. System toolchains >= 11.3 # produce code that overflows m_text (see DAPLink docs/DEVELOPERS-GUIDE.md and