diff --git a/.gitattributes b/.gitattributes index 4e560bb50..ab32f7524 100644 --- a/.gitattributes +++ b/.gitattributes @@ -47,6 +47,8 @@ dfu-suffix binary dfu-util binary upload-reset binary hid-flash binary +uf2upload binary +uf2upload.exe binary *.class binary *.dll binary *.exe binary @@ -54,4 +56,3 @@ hid-flash binary *.jpg binary *.pdf binary *.png binary - diff --git a/LICENCE.md b/LICENCE.md index 6e92b637d..a61fc5827 100644 --- a/LICENCE.md +++ b/LICENCE.md @@ -4,6 +4,7 @@ This files includes licensing information for parts of this repository. * [busybox-w32](https://frippery.org/busybox/) * [dfu-util](http://dfu-util.sourceforge.net/) (also available [here](src/dfu-util/COPYING)) * upload-reset +* uf2upload [GPLv3](#gplv3) is used for: * [HID-flash](https://github.com/Serasidis/STM32_HID_Bootloader) diff --git a/README.md b/README.md index 391dbc37b..914d9eba8 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,20 @@ [![GitHub commits](https://img.shields.io/github/commits-since/stm32duino/Arduino_Tools/2.5.0.svg)](https://github.com/stm32duino/Arduino_Tools/compare/2.4.0...main) Contains upload tools for STM32 based boards and some other usefull scripts. + +## UF2 uploader + +`uf2upload` is a self-contained host tool for a board with a UF2 mass-storage +bootloader. It first checks whether the target UF2 volume is already mounted; +when it is, it copies the converted image directly. Otherwise it performs a +USB CDC 1200-bps touch, waits for the volume label and copies the result. It +has no Python or shell dependency at upload time: + +``` +uf2upload --input firmware.bin --port COM7 --volume XIAOC5BOOT \ + --address 0x08008000 --family 0x00C5C5C5 --max-size 1015808 +``` + +Use `--skip-touch` to disable the CDC touch when no bootloader volume is +currently mounted. The source is built for the host package with +`make -C src/uf2upload`. diff --git a/linux/x86_64/uf2upload b/linux/x86_64/uf2upload new file mode 100644 index 000000000..d4c1ebcfa Binary files /dev/null and b/linux/x86_64/uf2upload differ diff --git a/src/build_mac.sh b/src/build_mac.sh index 07785bb8a..d5b3ac14a 100755 --- a/src/build_mac.sh +++ b/src/build_mac.sh @@ -170,3 +170,14 @@ clang \ -Werror \ -o "${ARCH_DIR}/upload_reset" \ src/upload_reset/unix/upload_reset.c + +clang++ \ + ${CC_ARCH_ARG} \ + ${CC_MIN_OS_VERSION_ARG} \ + ${BASE_CFLAGS} \ + ${BASE_LDFLAGS} \ + -std=c++17 \ + -Wall \ + -Werror \ + -o "${ARCH_DIR}/uf2upload" \ + src/uf2upload/uf2upload.cpp diff --git a/src/linux-aarch64/Dockerfile b/src/linux-aarch64/Dockerfile index de71993ed..0638cfe71 100644 --- a/src/linux-aarch64/Dockerfile +++ b/src/linux-aarch64/Dockerfile @@ -57,10 +57,13 @@ RUN git clone https://github.com/Serasidis/STM32_HID_Bootloader.git && \ ${STRIP} hid-flash && \ cp hid-flash /build/output/bin/ -# Build upload_reset from source +# Build upload_reset and UF2 uploader from source COPY src/upload_reset/unix/upload_reset.c /build/upload_reset.c +COPY src/uf2upload/uf2upload.cpp /build/uf2upload.cpp RUN ${CC} -o /build/output/bin/upload_reset /build/upload_reset.c && \ - ${STRIP} /build/output/bin/upload_reset + ${STRIP} /build/output/bin/upload_reset && \ + ${CXX} -O2 -std=c++17 -Wall -Wextra -Werror -o /build/output/bin/uf2upload /build/uf2upload.cpp && \ + ${STRIP} /build/output/bin/uf2upload # Create output directory structure RUN mkdir -p /output @@ -70,7 +73,8 @@ RUN cp /build/output/bin/dfu-util /output/ && \ cp /build/output/bin/dfu-prefix /output/ && \ cp /build/output/bin/dfu-suffix /output/ && \ cp /build/output/bin/hid-flash /output/ && \ - cp /build/output/bin/upload_reset /output/ + cp /build/output/bin/upload_reset /output/ && \ + cp /build/output/bin/uf2upload /output/ # Verify binaries are ARM64 RUN file /output/* | grep aarch64 @@ -129,6 +133,10 @@ RUN echo "========================================" && \ file /usr/local/bin/upload_reset && \ (upload_reset --help 2>&1 | head -5 || echo "(upload_reset executed successfully)") && \ echo "" && \ + echo "=== Testing uf2upload ===" && \ + file /usr/local/bin/uf2upload && \ + uf2upload --help && \ + echo "" && \ echo "========================================" && \ echo "✓ All ARM64 binaries are working!" && \ echo "========================================" diff --git a/src/linux-aarch64/build.sh b/src/linux-aarch64/build.sh index 41c302aa0..6d198f3ef 100755 --- a/src/linux-aarch64/build.sh +++ b/src/linux-aarch64/build.sh @@ -58,6 +58,7 @@ docker cp "${CONTAINER_ID}:/dfu-prefix" "${OUTPUT_DIR}/" docker cp "${CONTAINER_ID}:/dfu-suffix" "${OUTPUT_DIR}/" docker cp "${CONTAINER_ID}:/hid-flash" "${OUTPUT_DIR}/" docker cp "${CONTAINER_ID}:/upload_reset" "${OUTPUT_DIR}/" +docker cp "${CONTAINER_ID}:/uf2upload" "${OUTPUT_DIR}/" echo "" echo "Step 5: Cleaning up container..." @@ -70,6 +71,7 @@ chmod +x "${OUTPUT_DIR}/dfu-prefix" chmod +x "${OUTPUT_DIR}/dfu-suffix" chmod +x "${OUTPUT_DIR}/hid-flash" chmod +x "${OUTPUT_DIR}/upload_reset" +chmod +x "${OUTPUT_DIR}/uf2upload" echo "" echo "Step 7: Verifying built binaries..." @@ -79,6 +81,7 @@ file "${OUTPUT_DIR}/dfu-prefix" file "${OUTPUT_DIR}/dfu-suffix" file "${OUTPUT_DIR}/hid-flash" file "${OUTPUT_DIR}/upload_reset" +file "${OUTPUT_DIR}/uf2upload" echo "----------------------------------------" echo "" @@ -92,6 +95,7 @@ echo "All required binaries have been built:" echo " - dfu-util, dfu-prefix, dfu-suffix (DFU programming)" echo " - hid-flash (HID bootloader)" echo " - upload_reset (Reset utility)" +echo " - uf2upload (CDC touch and UF2 mass-storage upload)" echo "" echo "Files in ${OUTPUT_DIR}:" ls -lh "${OUTPUT_DIR}" diff --git a/src/uf2upload/Makefile b/src/uf2upload/Makefile new file mode 100644 index 000000000..120111387 --- /dev/null +++ b/src/uf2upload/Makefile @@ -0,0 +1,25 @@ +CXX ?= g++ +CXXFLAGS ?= -O2 -std=c++17 -Wall -Wextra -Werror + +ifeq ($(OS),Windows_NT) + DEST = ../../win/uf2upload.exe + LDFLAGS ?= -static -static-libgcc -static-libstdc++ +else + LDFLAGS ?= + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + DEST = ../../macosx/uf2upload + else + DEST = ../../linux/x86_64/uf2upload + endif +endif + +.PHONY: all clean + +all: $(DEST) + +$(DEST): uf2upload.cpp + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -f ../../win/uf2upload.exe ../../macosx/uf2upload ../../linux/x86_64/uf2upload diff --git a/src/uf2upload/uf2upload.cpp b/src/uf2upload/uf2upload.cpp new file mode 100644 index 000000000..d6c51c4e6 --- /dev/null +++ b/src/uf2upload/uf2upload.cpp @@ -0,0 +1,490 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Cross-platform UF2 uploader for Arduino boards using a USB CDC touch and + * a UF2 mass-storage bootloader. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +namespace { + +constexpr uint32_t UF2_MAGIC_START0 = 0x0A324655UL; +constexpr uint32_t UF2_MAGIC_START1 = 0x9E5D5157UL; +constexpr uint32_t UF2_MAGIC_END = 0x0AB16F30UL; +constexpr uint32_t UF2_FLAG_FAMILY_ID_PRESENT = 0x00002000UL; +constexpr size_t UF2_BLOCK_SIZE = 512U; +constexpr size_t UF2_PAYLOAD_SIZE = 256U; + +struct Options { + std::string input; + std::string port; + std::string volume; + uint32_t address = 0U; + uint32_t family = 0U; + size_t max_size = 0U; + unsigned int timeout_ms = 10000U; + bool skip_touch = false; +}; + +void usage(const char *program) +{ + std::cout << "Usage: " << program << " --input [--port ]" + << " --volume