From 5723f521d709b915d906f257a93239150695cd70 Mon Sep 17 00:00:00 2001 From: hulk Date: Mon, 14 Sep 2026 17:17:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(build):=20=E5=B7=A5=E5=85=B7=E9=93=BE?= =?UTF-8?q?=E6=94=B9=E7=94=A8=20GD32=5FGCC=5FBIN=20=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E6=96=B9=E6=A1=88=E5=B9=B6=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20.vscode=20=E7=83=A7=E5=BD=95=E8=B0=83=E8=AF=95=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - .vscode/erase.jlink | 2 + .vscode/extensions.json | 8 ++ .vscode/flash.jlink | 4 + .vscode/launch.json | 58 +++++++++ .vscode/reset.jlink | 2 + .vscode/settings.json | 15 +++ .vscode/tasks.json | 229 ++++++++++++++++++++++++++++++++++ cmake/arm-none-eabi-gcc.cmake | 123 +++++++++++++----- 9 files changed, 408 insertions(+), 34 deletions(-) create mode 100644 .vscode/erase.jlink create mode 100644 .vscode/extensions.json create mode 100644 .vscode/flash.jlink create mode 100644 .vscode/launch.json create mode 100644 .vscode/reset.jlink create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json diff --git a/.gitignore b/.gitignore index 88f5f86..b1e9698 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ # 忽略构建输出目录 Build/ -.vscode/ # 忽略 Toolchain 目录下所有内容,但保留目录本身 Toolchain/* diff --git a/.vscode/erase.jlink b/.vscode/erase.jlink new file mode 100644 index 0000000..4b732c1 --- /dev/null +++ b/.vscode/erase.jlink @@ -0,0 +1,2 @@ +erase +exit diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a95b493 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "marus25.cortex-debug", + "ms-vscode.cmake-tools", + "twxs.cmake", + "ms-vscode.cpptools" + ] +} diff --git a/.vscode/flash.jlink b/.vscode/flash.jlink new file mode 100644 index 0000000..f3b0461 --- /dev/null +++ b/.vscode/flash.jlink @@ -0,0 +1,4 @@ +loadfile Application.hex +r +go +exit diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8639189 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,58 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "cwd": "${workspaceFolder}", + "executable": "${workspaceFolder}/Build/Debug/Application/Application.elf", + "name": "Debug with OpenOCD", + "request": "launch", + "type": "cortex-debug", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "gdbPath": "${env:GD32_GCC_BIN}/arm-none-eabi-gdb.exe", + "servertype": "openocd", + "serverpath": "${env:GD32_OPENOCD_BIN}/openocd.exe", + "svdFile": "${workspaceFolder}/GD32E230.svd", + "configFiles": [ + "${env:GD32_OPENOCD_SCRIPTS}/${config:gd32.openocd.targetConfig}" + ], + "serverArgs": [ + "-s", "${env:GD32_OPENOCD_SCRIPTS}" + ], + "env": { + "OPENOCD_SCRIPTS": "${env:GD32_OPENOCD_SCRIPTS}" + }, + "searchDir": [ + "${workspaceFolder}" + ], + "preLaunchTask": "Build", + "preRestartCommands": [ + "load", + "continue" + ] + }, + { + "cwd": "${workspaceFolder}", + "executable": "${workspaceFolder}/Build/Debug/Application/Application.elf", + "name": "Debug with J-Link", + "request": "launch", + "type": "cortex-debug", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "gdbPath": "${env:GD32_GCC_BIN}/arm-none-eabi-gdb.exe", + "servertype": "jlink", + "device": "${config:gd32.jlink.device}", + "interface": "${config:gd32.jlink.interface}", + "svdFile": "${workspaceFolder}/GD32E230.svd", + "liveWatch": { + "enabled": true, + "samplesPerSecond": 1 + }, + "preLaunchTask": "Build", + "preRestartCommands": [ + "load", + "continue" + ] + } + ] +} diff --git a/.vscode/reset.jlink b/.vscode/reset.jlink new file mode 100644 index 0000000..a0ddf0f --- /dev/null +++ b/.vscode/reset.jlink @@ -0,0 +1,2 @@ +r +exit diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cf89ce4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "cmake.configureOnOpen": true, + "cmake.useCMakePresets": "always", + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "cortex-debug.variableUseNaturalFormat": true, + "gd32.openocd.targetConfig": "target/openocd_gdlink_gd32e23x.cfg", + "gd32.openocd.massEraseCommand": "gd32e23x mass_erase 0", + "gd32.jlink.device": "GD32E230F8", + "gd32.jlink.interface": "SWD", + "gd32.jlink.speed": "4000", + "files.associations": { + "*.h": "c", + "*.c": "c" + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..572c001 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,229 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "cmake", + "command": "build", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + { + "base": "$gcc", + "fileLocation": [ + "relative", + "${command:cmake.buildDirectory}" + ] + } + ], + "options": { + "environment": { + "CLICOLOR_FORCE": "1", + "OPENOCD_SCRIPTS": "${env:GD32_OPENOCD_SCRIPTS}" + } + }, + "presentation": { + "clear": true + }, + "icon": { + "id": "code", + "tooltip": "Build" + } + }, + { + "label": "Build and Flash", + "dependsOn": [ + "Build", + "Flash MCU" + ], + "dependsOrder": "sequence", + "group": "build", + "icon": { + "id": "insert", + "tooltip": "Build and Flash" + } + }, + { + "label": "Flash MCU", + "type": "process", + "command": "${env:GD32_OPENOCD_BIN}/openocd.exe", + "args": [ + "-s", "${env:GD32_OPENOCD_SCRIPTS}", + "-f", "${env:GD32_OPENOCD_SCRIPTS}/${config:gd32.openocd.targetConfig}", + "-c", "init; reset halt; flash write_image erase ${command:cmake.launchTargetFilename}; reset; exit" + ], + "group": "build", + "problemMatcher": [], + "options": { + "cwd": "${command:cmake.buildDirectory}/Application", + "environment": { + "OPENOCD_SCRIPTS": "${env:GD32_OPENOCD_SCRIPTS}" + } + }, + "presentation": { + "clear": true + }, + "icon": { + "id": "gather", + "tooltip": "Flash MCU" + } + }, + { + "label": "Reset MCU", + "type": "process", + "command": "${env:GD32_OPENOCD_BIN}/openocd.exe", + "args": [ + "-s", "${env:GD32_OPENOCD_SCRIPTS}", + "-f", "${env:GD32_OPENOCD_SCRIPTS}/${config:gd32.openocd.targetConfig}", + "-c", "init; reset; exit" + ], + "group": "build", + "problemMatcher": [], + "options": { + "cwd": "${command:cmake.buildDirectory}/Application", + "environment": { + "OPENOCD_SCRIPTS": "${env:GD32_OPENOCD_SCRIPTS}" + } + }, + "presentation": { + "clear": true + }, + "icon": { + "id": "discard", + "tooltip": "Reset MCU" + } + }, + { + "label": "Mass Erase MCU", + "type": "process", + "command": "${env:GD32_OPENOCD_BIN}/openocd.exe", + "args": [ + "-s", "${env:GD32_OPENOCD_SCRIPTS}", + "-f", "${env:GD32_OPENOCD_SCRIPTS}/${config:gd32.openocd.targetConfig}", + "-c", "init; reset halt; ${config:gd32.openocd.massEraseCommand}; exit" + ], + "group": "build", + "problemMatcher": [], + "options": { + "cwd": "${command:cmake.buildDirectory}/Application", + "environment": { + "OPENOCD_SCRIPTS": "${env:GD32_OPENOCD_SCRIPTS}" + } + }, + "presentation": { + "clear": true + }, + "icon": { + "id": "clear-all", + "tooltip": "Erase MCU" + } + }, + { + "label": "OpenOCD Server", + "type": "process", + "command": "${env:GD32_OPENOCD_BIN}/openocd.exe", + "args": [ + "-s", "${env:GD32_OPENOCD_SCRIPTS}", + "-f", "${env:GD32_OPENOCD_SCRIPTS}/${config:gd32.openocd.targetConfig}" + ], + "group": "build", + "problemMatcher": [], + "options": { + "cwd": "${command:cmake.buildDirectory}/Application", + "environment": { + "OPENOCD_SCRIPTS": "${env:GD32_OPENOCD_SCRIPTS}" + } + }, + "presentation": { + "clear": true + } + }, + { + "label": "Build and Flash (Jlink)", + "dependsOn": [ + "Build", + "Flash MCU (Jlink)" + ], + "dependsOrder": "sequence", + "group": "build", + "icon": { + "id": "insert", + "tooltip": "Build and Flash (Jlink)" + } + }, + { + "label": "Flash MCU (Jlink)", + "type": "process", + "command": "JLink.exe", + "args": [ + "-device", "${config:gd32.jlink.device}", + "-if", "${config:gd32.jlink.interface}", + "-speed", "${config:gd32.jlink.speed}", + "-autoconnect", "1", + "-CommanderScript", "${workspaceFolder}/.vscode/flash.jlink" + ], + "group": "build", + "problemMatcher": [], + "options": { + "cwd": "${command:cmake.buildDirectory}/Application" + }, + "presentation": { + "clear": true + }, + "icon": { + "id": "gather", + "tooltip": "Flash MCU (Jlink)" + } + }, + { + "label": "Reset MCU (Jlink)", + "type": "process", + "command": "JLink.exe", + "args": [ + "-device", "${config:gd32.jlink.device}", + "-if", "${config:gd32.jlink.interface}", + "-speed", "${config:gd32.jlink.speed}", + "-autoconnect", "1", + "-CommanderScript", "${workspaceFolder}/.vscode/reset.jlink" + ], + "group": "build", + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "presentation": { + "clear": true + }, + "icon": { + "id": "discard", + "tooltip": "Reset MCU (Jlink)" + } + }, + { + "label": "Mass Erase MCU (Jlink)", + "type": "process", + "command": "JLink.exe", + "args": [ + "-device", "${config:gd32.jlink.device}", + "-if", "${config:gd32.jlink.interface}", + "-speed", "${config:gd32.jlink.speed}", + "-autoconnect", "1", + "-CommanderScript", "${workspaceFolder}/.vscode/erase.jlink" + ], + "group": "build", + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}" + }, + "presentation": { + "clear": true + }, + "icon": { + "id": "clear-all", + "tooltip": "Erase MCU (Jlink)" + } + } + ] +} diff --git a/cmake/arm-none-eabi-gcc.cmake b/cmake/arm-none-eabi-gcc.cmake index 52f84c2..eb7a383 100644 --- a/cmake/arm-none-eabi-gcc.cmake +++ b/cmake/arm-none-eabi-gcc.cmake @@ -1,24 +1,62 @@ -# You can change TOOLCHAIN_DIRECTORY if you want to use different toolchain. -# set(TOOLCHAIN_DIRECTORY "${CMAKE_SOURCE_DIR}/Toolchain/xpack-arm-none-eabi-gcc-11.3.1-1.1/bin") +# The project never stores a compiler package. Each machine supplies a path. +# TOOLCHAIN_DIRECTORY (CMake cache) has priority over the environment variable. +# GD32_GCC_ENV_VAR lets a workstation use a different variable name if needed. set(TOOLCHAIN_DIRECTORY "" CACHE PATH "Path to arm-none-eabi toolchain bin directory") +set(GD32_GCC_ENV_VAR "GD32_GCC_BIN" CACHE STRING "Environment variable containing the ARM GCC path") +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES TOOLCHAIN_DIRECTORY GD32_GCC_ENV_VAR) + +if(GD32_GCC_ENV_VAR AND NOT GD32_GCC_ENV_VAR MATCHES "^GD32_[A-Za-z0-9_]+$") + message(FATAL_ERROR "GD32_GCC_ENV_VAR must use the GD32_ prefix: ${GD32_GCC_ENV_VAR}") +endif() + +if(NOT TOOLCHAIN_DIRECTORY AND GD32_GCC_ENV_VAR) + if(DEFINED ENV{${GD32_GCC_ENV_VAR}} AND NOT "$ENV{${GD32_GCC_ENV_VAR}}" STREQUAL "") + file(TO_CMAKE_PATH "$ENV{${GD32_GCC_ENV_VAR}}" TOOLCHAIN_DIRECTORY) + endif() +endif() if(NOT TOOLCHAIN_DIRECTORY) - # Add extra auto-detect paths in this list when using another machine. - # Example: "C:/your/path/xpack-arm-none-eabi-gcc-11.3.1-1.1/bin" - set(_TOOLCHAIN_CANDIDATES - "D:/toolchain/xpack-arm-none-eabi-gcc-11.3.1-1.1/bin" - "C:/toolchain/xpack-arm-none-eabi-gcc-11.3.1-1.1/bin" - "${CMAKE_SOURCE_DIR}/Toolchain/xpack-arm-none-eabi-gcc-11.3.1-1.1/bin" - ) - - foreach(_candidate IN LISTS _TOOLCHAIN_CANDIDATES) - if(EXISTS "${_candidate}/arm-none-eabi-gcc.exe" OR EXISTS "${_candidate}/arm-none-eabi-gcc") - set(TOOLCHAIN_DIRECTORY "${_candidate}") - break() - endif() - endforeach() + message(FATAL_ERROR + "Cannot find ARM GCC toolchain. Set ${GD32_GCC_ENV_VAR} in the machine environment " + "or pass -DTOOLCHAIN_DIRECTORY=.") endif() +file(TO_CMAKE_PATH "${TOOLCHAIN_DIRECTORY}" TOOLCHAIN_DIRECTORY) +get_filename_component(TOOLCHAIN_DIRECTORY "${TOOLCHAIN_DIRECTORY}" ABSOLUTE) + +if(WIN32) + set(TOOLCHAIN_SUFFIX ".exe") +else() + set(TOOLCHAIN_SUFFIX "") +endif() + +# Accept either the package root or its bin directory. +if(NOT EXISTS "${TOOLCHAIN_DIRECTORY}/arm-none-eabi-gcc${TOOLCHAIN_SUFFIX}" AND + EXISTS "${TOOLCHAIN_DIRECTORY}/bin/arm-none-eabi-gcc${TOOLCHAIN_SUFFIX}") + set(TOOLCHAIN_DIRECTORY "${TOOLCHAIN_DIRECTORY}/bin") +endif() + +set(_ARM_GCC_EXECUTABLE "${TOOLCHAIN_DIRECTORY}/arm-none-eabi-gcc${TOOLCHAIN_SUFFIX}") + +set(_TOOLCHAIN_BINARIES + arm-none-eabi-gcc + arm-none-eabi-g++ + arm-none-eabi-gdb + arm-none-eabi-ar + arm-none-eabi-ranlib + arm-none-eabi-as + arm-none-eabi-ld + arm-none-eabi-objcopy + arm-none-eabi-objdump + arm-none-eabi-size +) +foreach(_binary IN LISTS _TOOLCHAIN_BINARIES) + if(NOT EXISTS "${TOOLCHAIN_DIRECTORY}/${_binary}${TOOLCHAIN_SUFFIX}") + message(FATAL_ERROR + "ARM GCC toolchain is incomplete; missing ${_binary}${TOOLCHAIN_SUFFIX} in ${TOOLCHAIN_DIRECTORY}") + endif() +endforeach() + set(CMAKE_C_FLAGS_DEBUG "") set(CMAKE_CXX_FLAGS_DEBUG "") set(CMAKE_ASM_FLAGS_DEBUG "") @@ -26,18 +64,10 @@ set(CMAKE_C_FLAGS_RELEASE "") set(CMAKE_CXX_FLAGS_RELEASE "") set(CMAKE_ASM_FLAGS_RELEASE "") -if(NOT TOOLCHAIN_DIRECTORY) - message(FATAL_ERROR "Cannot find ARM GCC toolchain. Set TOOLCHAIN_DIRECTORY cache variable or install toolchain in one of the default locations.") -endif() - set(CMAKE_COLOR_DIAGNOSTICS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") -if(WIN32) - set(TOOLCHAIN_SUFFIX ".exe") -endif() - set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR arm) @@ -50,21 +80,48 @@ set(FLAGS "-mcpu=cortex-m23 -std=gnu11 -fstack-usage - set(ASM_FLAGS "-x assembler-with-cpp") set(CPP_FLAGS "-fno-rtti -fno-exceptions -fno-threadsafe-statics") -set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc${TOOLCHAIN_SUFFIX}) -set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++${TOOLCHAIN_SUFFIX}) -set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}gcc${TOOLCHAIN_SUFFIX}) +set(_REQUESTED_C_COMPILER "${TOOLCHAIN_PREFIX}gcc${TOOLCHAIN_SUFFIX}") +if(DEFINED CMAKE_C_COMPILER AND CMAKE_C_COMPILER AND + IS_ABSOLUTE "${CMAKE_C_COMPILER}" AND + NOT CMAKE_C_COMPILER STREQUAL "${_REQUESTED_C_COMPILER}") + message(FATAL_ERROR + "The build directory is already configured for a different ARM GCC compiler:\n" + " cached: ${CMAKE_C_COMPILER}\n" + " selected: ${_REQUESTED_C_COMPILER}\n" + "Delete the build directory or run CMake Tools 'Delete Cache and Reconfigure'.") +endif() + +set(CMAKE_C_COMPILER "${_REQUESTED_C_COMPILER}") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PREFIX}g++${TOOLCHAIN_SUFFIX}") +set(CMAKE_ASM_COMPILER "${TOOLCHAIN_PREFIX}gcc${TOOLCHAIN_SUFFIX}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS} ${CPP_FLAGS}") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${FLAGS} ${ASM_FLAGS}") -set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy${TOOLCHAIN_SUFFIX}) -set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size${TOOLCHAIN_SUFFIX}) -set(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}objdump${TOOLCHAIN_SUFFIX}) -set(CMAKE_AS ${TOOLCHAIN_PREFIX}as${TOOLCHAIN_SUFFIX}) -set(CMAKE_LD ${TOOLCHAIN_PREFIX}ld${TOOLCHAIN_SUFFIX}) +set(CMAKE_AR "${TOOLCHAIN_PREFIX}ar${TOOLCHAIN_SUFFIX}") +set(CMAKE_RANLIB "${TOOLCHAIN_PREFIX}ranlib${TOOLCHAIN_SUFFIX}") +set(CMAKE_OBJCOPY "${TOOLCHAIN_PREFIX}objcopy${TOOLCHAIN_SUFFIX}") +set(CMAKE_SIZE "${TOOLCHAIN_PREFIX}size${TOOLCHAIN_SUFFIX}") +set(CMAKE_OBJDUMP "${TOOLCHAIN_PREFIX}objdump${TOOLCHAIN_SUFFIX}") +set(CMAKE_AS "${TOOLCHAIN_PREFIX}as${TOOLCHAIN_SUFFIX}") +set(CMAKE_LD "${TOOLCHAIN_PREFIX}ld${TOOLCHAIN_SUFFIX}") +set(CMAKE_LINKER "${TOOLCHAIN_PREFIX}ld${TOOLCHAIN_SUFFIX}") + +execute_process( + COMMAND "${_ARM_GCC_EXECUTABLE}" --version + OUTPUT_VARIABLE _ARM_GCC_VERSION_OUTPUT + ERROR_VARIABLE _ARM_GCC_VERSION_ERROR + RESULT_VARIABLE _ARM_GCC_VERSION_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE +) +if(NOT _ARM_GCC_VERSION_RESULT EQUAL 0) + message(FATAL_ERROR "Unable to execute ${_ARM_GCC_EXECUTABLE}: ${_ARM_GCC_VERSION_ERROR}") +endif() +string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" _ARM_GCC_VERSION "${_ARM_GCC_VERSION_OUTPUT}") +message(STATUS "Using ARM GCC ${_ARM_GCC_VERSION} from ${TOOLCHAIN_DIRECTORY}") set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf") set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf") -set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) \ No newline at end of file +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)