STM32最小CLion开发环境

文章目录

    • [1 必须文件](#1 必须文件)
    • [2 工具链](#2 工具链)
    • [3 CLion 全局配置](#3 CLion 全局配置)
    • [4 CLion 新项目配置](#4 CLion 新项目配置)
      • [ST-Link 调试](#ST-Link 调试)
    • [5 点亮 LED](#5 点亮 LED)
    • [6 分析 elf 文件](#6 分析 elf 文件)
    • [7 项目模板](#7 项目模板)

1 必须文件

ST 提供的头文件支持 MDK-ARM, GCC, IAR 3种编译器, 下面采用 GCC

编译器 Arm GNU Toolchain Downloads -- Arm Developer安装包版

调试器服务端 OpenOCD

基础头文件仓库 STMicroelectronics/cmsis-core

F1头文件仓库 STMicroelectronics/cmsis-device-f1

F1头文件仓库 STMicroelectronics/stm32f1xx-hal-driver

外设 SVD 文件 stm32 svd

上述所有项目拉取/解压/解包后各自一个文件夹放在 stm32kits 中

2 工具链

新建 stm32kits/cmake/startup.bat, 内容如下

cmd 复制代码
set CMAKE_TOOLCHAIN_FILE=%~dp0arm.toolchain.cmake

新建 stm32kits/cmake/arm.toolchain.cmake, 内容如下

CMake 复制代码
set(CMAKE_SYSTEM_NAME               Generic)
set(CMAKE_SYSTEM_PROCESSOR          arm)

set(CMAKE_C_COMPILER_ID GNU)
set(CMAKE_CXX_COMPILER_ID GNU)

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)

set(STM32_KITS_DIR "${CMAKE_CURRENT_LIST_DIR}/..")
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_LIST_DIR}")

# MCU specific flags
set(TARGET_FLAGS "-mcpu=cortex-m3 ")

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS}")
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -fdata-sections -ffunction-sections -Wl,--no-warn-rwx-segments")

set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_C_FLAGS_RELEASE "-Os -g0")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_CXX_FLAGS_RELEASE "-Os -g0")

set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics")

set(CMAKE_C_LINK_FLAGS "${TARGET_FLAGS}")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} --specs=nano.specs")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lc -lm -Wl,--end-group")
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--print-memory-usage")

set(CMAKE_CXX_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group -lstdc++ -lsupc++ -Wl,--end-group")

新建 stm32kits/cmake/FindSTM32Driver.cmake, 内容如下

CMake 复制代码
function(stm32_parse_mcu_name MCU_NAME)
    string(TOUPPER "${MCU_NAME}" MCU_NAME_UPPER)
    if(NOT MCU_NAME_UPPER MATCHES "^STM32([C|F|G|H|L|M|N|U|W][A-Z0-9][A-Z0-9]?[A-Z0-9]?)([0-9][0-9])([A-Z])([0-9A-IZ])([BDG-KMPQTUVY]?)([6A7B3CD]?)$")
        set(STM32Driver_FOUND PARENT_SCOPE)
        return()
    endif()

    string(TOLOWER "${CMAKE_MATCH_1}" MATCH_1_LOWER)
    SET(MCU_SERIES_VARIANT_LOWER "${MATCH_1_LOWER}" PARENT_SCOPE)
    SET(MCU_SERIES_VARIANT "${CMAKE_MATCH_1}" PARENT_SCOPE)
    SET(MCU_VARIANT "${CMAKE_MATCH_2}" PARENT_SCOPE)
    SET(MCU_PIN_COUNT "${CMAKE_MATCH_3}" PARENT_SCOPE)
    string(TOLOWER "${CMAKE_MATCH_4}" CMAKE_MATCH_4_LOWER)
    SET(MCU_FLASH_LOWER "${CMAKE_MATCH_4_LOWER}" PARENT_SCOPE)
    SET(MCU_FLASH "${CMAKE_MATCH_4}" PARENT_SCOPE)
    SET(MCU_PACKAGE "${CMAKE_MATCH_5}" PARENT_SCOPE)
    SET(MCU_TEMP_RANGE "${CMAKE_MATCH_6}" PARENT_SCOPE)
    set(STM32Driver_FOUND TRUE PARENT_SCOPE)
endfunction()

if(NOT DEFINED MCU_NAME)
    list(POP_FRONT STM32Driver_FIND_COMPONENTS MCU_NAME)
endif()
if(NOT DEFINED MCU_NAME)
    message(FATAL_ERROR "MCU_NAME variable must be defined before calling find_package(STM32Driver)")
endif()

stm32_parse_mcu_name("${MCU_NAME}")
if(NOT STM32Driver_FOUND)
    message(WARNING "Invalid STM32 MCU name: ${MCU_NAME}")
    return()
endif()

set(STM32Driver_FOUND)
foreach(flash_fit IN ITEMS 0 1 2 3 4 5 6 7 8 9 A B Z C D E F G H I)
    if(${flash_fit} STRGREATER_EQUAL ${MCU_FLASH})
        string(TOLOWER "${flash_fit}" MCU_FLASH_FIT_LOWER)
        if(EXISTS "${STM32_KITS_DIR}/cmsis-device-${MCU_SERIES_VARIANT_LOWER}/Source/Templates/gcc/startup_stm32${MCU_SERIES_VARIANT_LOWER}${MCU_VARIANT}x${MCU_FLASH_FIT_LOWER}.s")
            set(STM32Driver_FOUND TRUE)
            set(MCU_FLASH_FIT "${flash_fit}")
            break()
        endif()
    endif()
endforeach()
if(NOT STM32Driver_FOUND)
    message(WARNING "Invalid STM32 MCU Flash: ${MCU_FLASH}")
    return()
endif()

enable_language(C ASM)
set(STM32Driver_FOUND TRUE)
add_library(STM32Driver STATIC
        "${STM32_KITS_DIR}/cmsis-device-${MCU_SERIES_VARIANT_LOWER}/Source/Templates/gcc/startup_stm32${MCU_SERIES_VARIANT_LOWER}${MCU_VARIANT}x${MCU_FLASH_FIT_LOWER}.s"
        "${STM32_KITS_DIR}/cmsis-device-${MCU_SERIES_VARIANT_LOWER}/Source/Templates/system_stm32${MCU_SERIES_VARIANT_LOWER}xx.c"
        "${STM32_KITS_DIR}/stm32${MCU_SERIES_VARIANT_LOWER}xx-hal-driver/Src/stm32${MCU_SERIES_VARIANT_LOWER}xx_hal.c"
        "${STM32_KITS_DIR}/stm32${MCU_SERIES_VARIANT_LOWER}xx-hal-driver/Src/stm32${MCU_SERIES_VARIANT_LOWER}xx_hal_cortex.c"
)
foreach(feature IN LISTS STM32Driver_FIND_COMPONENTS)
    target_sources(STM32Driver PRIVATE
            "${STM32_KITS_DIR}/stm32${MCU_SERIES_VARIANT_LOWER}xx-hal-driver/Src/stm32${MCU_SERIES_VARIANT_LOWER}xx_hal_${feature}.c"
    )
endforeach()
target_include_directories(STM32Driver PUBLIC
        "${STM32_KITS_DIR}/cmsis-core/Include"
        "${STM32_KITS_DIR}/cmsis-device-${MCU_SERIES_VARIANT_LOWER}/Include"
        "${STM32_KITS_DIR}/stm32${MCU_SERIES_VARIANT_LOWER}xx-hal-driver/Inc"
        "${STM32_KITS_DIR}/easyheader"
)
target_compile_definitions(STM32Driver PUBLIC "STM32${MCU_SERIES_VARIANT}${MCU_VARIANT}x${MCU_FLASH_FIT}")
target_link_options(STM32Driver PUBLIC
        "SHELL:-T\"${STM32_KITS_DIR}/cmsis-device-${MCU_SERIES_VARIANT_LOWER}/Source/Templates/gcc/linker/STM32${MCU_SERIES_VARIANT}${MCU_VARIANT}X${MCU_FLASH_FIT}_FLASH.ld\""
)

新建 stm32kits/easyheader/stm32f1xx_hal_conf.h, 内容如下

c 复制代码
#include <stm32f1xx_hal_conf_template.h>

至此 stm32kits 已手工创建完成

3 CLion 全局配置

设置→构建、执行、部署→工具链→"+"→系统

环境文件: stm32kits\cmake\startup.bat

C 编译器: arm-none-eabi-gcc.exe

C++ 编译器: arm-none-eabi-g++.exe

调试器: arm-none-eabi-gdb.exe

上述全局配置实际保存在 %APPDATA%\JetBrains\CLion2025.1\options\windows\toolchains.xml

xml 复制代码
      <toolchain
          name="ArmMinGW"
          toolSetKind="SYSTEM_WINDOWS_TOOLSET"
          customCCompilerPath="stm32kits\arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi\bin\arm-none-eabi-gcc.exe"
          customCXXCompilerPath="stm32kits\arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi\bin\arm-none-eabi-g++.exe"
          debuggerKind="CUSTOM_GDB"
          customGDBPath="stm32kits\arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi\bin\arm-none-eabi-gdb.exe"
          environment="stm32kits\startup.bat" />

4 CLion 新项目配置

任意创建一个 C++ 项目后, 进行如下配置

设置→构建、执行、部署→CMake→配置文件

工具链: ArmMinGW

CMakeLists.txt 添加:

CMake 复制代码
find_package(STM32Driver COMPONENTS STM32F103C8T6 gpio spi)
target_link_libraries(<项目名> PRIVATE STM32Driver)

之后程序就可编译了

下面配置嵌入式 GDB 调试服务端, 需安装 Embedded Development Support 插件

设置→构建、执行、部署→调试器→调试服务器→"+"→泛型→GDB 服务器

可执行文件: stm32kits/OpenOCD/bin/openocd.exe

实参: -f interface\stlink.cfg -f target\stm32f1x.cfg

下面配置调试客户端

设置→构建、执行、部署→调试器→调试服务器→调试器

调试器: stm32kits\arm-gnu-toolchain\bin\arm-none-eabi-gdb.exe

连接/实参: tcp:localhost:3333 (用于启动客户端后连接服务端)

上述配置将在 ${CMAKE_CURRENT_SOURCE_DIR}/.idea/debugServers 生成 OpenOCD.xml, 该文件以后可直接复制使用, 其内容如下

xml 复制代码
<component name="DebugServers">
  <generic-debug-target name="OpenOCD" uniqueID="c136ea77-b81f-463e-8e9b-ef6a84b56628" selected="true">
    <debugger version="1">
      <debugger toolchainName="ArmMinGW" />
      <env />
    </debugger>
    <gdbserver exe="C:/program/stm32kits/OpenOCD-20240916-0.12.0/bin/openocd.exe" args="-f interface\stlink.cfg -f target\stm32f1x.cfg">
      <env />
    </gdbserver>
    <console enabled="true" port="4444" />
    <target reset-before="false" />
    <connection remote-string="tcp:localhost:3333" custom-script="echo Connecting to target...\n&#10;$GDBTargetCommand$&#10;echo Connected to target!\n" warmup-ms="500" />
  </generic-debug-target>
</component>

最后再设置一下当前调试服务器, 之后可通过 ST-Link 走 SWD 接口 下载程序和调试

ST-Link 也要装好驱动, OpenOCD已内置了ST-Link的驱动, 位置在 stm32kits/OpenOCD/drivers/ST-Link/dpinst_amd64.exe

在运行被中断时, 可以用调试浮窗的内存视图直接查看 SRAM 内存

而功能寄存器需要在调试浮窗可找到外设页(需安装 Embedded Development Support 插件), 加载 svd 文件来读取

调试时会出现 info pretty-printer 执行失败的错误, 原因是 arm-none-eabi-gdb 编译时移除了 python 支持, 否则通常可以在 gdb 隔壁 ../share/gdb/python/gdb/command/pretty_printers.py 找到该命令

5 点亮 LED

以tb上常见的STM32F103C8T6最小系统板为例, 一个 LED 负极接在 PC13 的位置

下面闪烁该 LED

cpp 复制代码
#include <stm32f1xx_hal.h>
#include <stm32f1xx_hal_rcc.h>
#include <stm32f1xx_hal_gpio.h>

extern "C" void SysTick_Handler() {
    HAL_IncTick();
}

int main() {
    HAL_Init();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = GPIO_PIN_13;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
    while (true) {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
        HAL_Delay(100);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
        HAL_Delay(100);
    }
}

6 分析 elf 文件

IDA 加载 elf 文件后, Processor type 选 ARM Little-endian [ARM], Processor options→Edit ARM architecture options 选 ARMv7-M

可以看到08000000开始是向量表, 第2个是程序入口 Reset_Handler, 在0x0800021C

7 项目模板

CLion 暂不支持将项目保存为项目模板 (详见 Save project as template in CLion. How?), 只有 Idea 其他 IDE 支持, 新项目都要手动重新配置 工具链,调试服务器

相关推荐
Jcenav1 小时前
OCXO外围电路设计指南
单片机·嵌入式硬件
Nautiluss1 小时前
一起玩XVF3800麦克风阵列(八)
大数据·人工智能·嵌入式硬件·github·音频·语音识别
神圣的大喵1 小时前
平台无关的嵌入式通用按键管理器
c语言·单片机·嵌入式硬件·嵌入式·按键库
三佛科技-134163842122 小时前
FT8353系列(FT8353A/B/C/CD/DD/K/KD/PD)隔离型LED恒流驱动IC芯片 典型应用电路
单片机·物联网·智能家居·pcb工艺
无人装备硬件开发爱好者3 小时前
深度解析:STM32 MDK 工程 HEX 文件转 BIN 文件 —— 原理、方法、优缺点与实战指南(中)
stm32·嵌入式软件·hex2bin
阿拉斯攀登3 小时前
嵌入式-硬件基础:了解三极管
单片机·嵌入式硬件·三极管
逐步前行3 小时前
C51_74HC165并口转串口
单片机·51单片机
HarrySunCn3 小时前
如何使用VSCode开发Arduino项目
ide·vscode·单片机·编辑器
嵌入式的飞鱼4 小时前
SD NAND 焊接避坑指南:LGA-8 封装手工焊接技巧与常见错误
人工智能·stm32·单片机·嵌入式硬件·tf卡
三佛科技-134163842124 小时前
LN8K05A/B/C_5V非隔离AC-DC电源芯片 典型应用场景、典型电路、与阻容降压的对比分析
单片机·嵌入式硬件·物联网·智能家居·pcb工艺