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 支持, 新项目都要手动重新配置 工具链,调试服务器

相关推荐
安庆平.Я21 分钟前
STM32——寄存器映射
c语言·stm32·单片机·嵌入式硬件·电脑
佳航张2 小时前
单片机启动流程和启动文件详解
单片机·嵌入式硬件
lixzest2 小时前
STM32中集成USB驱动
stm32·单片机·嵌入式硬件
努力做小白3 小时前
Linux驱动22 --- RV1126 环境搭建&&设备树修改
linux·驱动开发·单片机·嵌入式硬件·rv1126
阿川!3 小时前
嵌入式软件--stm32 DAY 9 定时器
stm32·单片机·嵌入式硬件
DIY机器人工房7 小时前
【科普】STM32CubeMX是配置工具,STM32CubeIDE是集成开发环境,二者互补但定位不同,前者负责初始化配置,后者专注代码开发调试。
单片机·嵌入式硬件·嵌入式·diy机器人工房
努力做小白8 小时前
Linux驱动20 --- FFMPEG视频API
linux·驱动开发·单片机·嵌入式硬件·ffmpeg·lvgl
得单片机的运16 小时前
STM32的蓝牙通讯(HAL库)
stm32·单片机·嵌入式硬件·蓝牙
国科安芯17 小时前
抗辐照芯片在低轨卫星星座CAN总线通讯及供电系统的应用探讨
运维·网络·人工智能·单片机·自动化
weixin_4526006918 小时前
GC8872刷式直流电机驱动器详解:3.6A驱动能力与PWM控制
stm32·单片机·嵌入式硬件·智能家居·音响·电动工具