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

相关推荐
IT阳晨。24 分钟前
【STM32】RTC的使用和实时时钟项目
stm32·单片机·嵌入式硬件
国科安芯34 分钟前
车规MCU在农业无人机电机驱动中的可靠性分析
单片机·嵌入式硬件·性能优化·无人机·安全威胁分析·安全性测试
TangDuoduo000536 分钟前
【UART控制器HAL库常用接口】
单片机·嵌入式硬件
List<String> error_P43 分钟前
STM32数据手册速查
stm32·单片机·嵌入式硬件
dlz08361 小时前
GPIO的通用初始化流程
单片机·嵌入式硬件
boneStudent2 小时前
Day18:系统滴答定时器 (SysTick)
stm32·单片机·嵌入式硬件
d111111111d2 小时前
再STM32F103C8T6中小端存储和大端存储有什么不同,STM32F103C8T6用的是那个,为什么要这么使用?
笔记·stm32·单片机·嵌入式硬件·学习
云山工作室3 小时前
基于物联网的体温心率监测系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·课程设计
猫猫的小茶馆3 小时前
【ARM】VSCode和IAR工程创建
c语言·开发语言·arm开发·ide·vscode·stm32·嵌入式硬件
zephyr_zeng3 小时前
CubeMX项目轻松导入Vscode+EIDE编译
c语言·ide·vscode·stm32·mcu·物联网·编辑器