失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > VSCode 和 CMake 搭建嵌入式开发环境

VSCode 和 CMake 搭建嵌入式开发环境

时间:2020-05-25 05:29:43

相关推荐

VSCode 和 CMake 搭建嵌入式开发环境

CMake 与 VSCode 搭建 ARM 构建环境

1. 前言

在嵌入式领域能够选择的集成开发环境(IDE)很多,有通用型的,例如KeilIAR,给他们安装一个相应芯片的描述包即可开发相应芯片的驱动程序。

也有专用型的,例如 德州仪器 TI 的CCS,意法半导体 ST 的STM32CubeIDE,国产 RTOS 操作系统的RT-Thread Studio,以及开源 Arduino 的Arduino IDE等等。它们各自的使用方式也是五花八门,一般情况下芯片厂商的芯片在不受通用集成开发环境(IDE)的支持下都会选择向开发者提供一个自己特有的集成开发环境比如 TI 的CCS集成开发环境。

如果使用的芯片能够被通用集成开发环境例如Keil支持倒还是不错的,至少是统一的,否则你需要为每一款不同的芯片安装不同的集成开发环境,同时还需要去熟悉以使用它们,当然一般情况下通用集成开发环境(例如 Keil)是收费的,并且不支持跨平台使用。

所以为了开发环境的统一性,我们可以基于构建工具Make与编译器GCC自己动手在 Windows 上搭建一个通用并且跨平台的嵌入式开发环境。可以这么做的原因是很多芯片厂商提供的专用 IDE 也是基于GCC以及相关开源的工具链来打造的。

2. 工具链选择

前面说到我们使用MakeGCC来搭建我们通用的开发环境,估计听到这里大多数人都已经望而却步了,因为要使用Make就需要能够编写Makefile文件来制定编译规则(即Make读取并解析Makefile,根据Makefile定义的规则调用GCC执行编译工作)。

好了不用担心,先不讨论你是否具备编写Makefile的能力,即使具备编写Makefile的能力实际开发中也不建议大家自己动手编写Makefile,其中的原因有以下两点:编写Makefile需要消耗大量时间,效率较低,并且不支持跨平台。

既然使用MakeMakefile是必须的,不自己编写那怎么得到Makefile呢,这就是文章标题CMake要做的事情,为了解决跨平台问题开源的构建工具 CMake 问世了。目前大型的开源项目大多是使用 CMake 来构建的,而非直接编写Makefile,例如开源图像处理框架 openCV 就是使用 CMake 来生成 Makefile 的。

2.1 系统平台

本篇文章以 Windows 10 作为开发平台,主要原因是 Windows 端具有丰富的开发工具链供我们选择,同时相比使用虚拟机虚拟 Linux 开发是方便许多的,不需要安装虚拟机可以免去虚拟机硬盘空间占用问题,数据备份,快照备份,虚拟机崩溃的麻烦。

本片文章所用的工具链以及方法适用于 Windows 和 Linux。在 Linux 中搭建使用的工具也是相同的以及过程也是类似的。

2.2 涉及软件工具

CMakeMinGW64arm-none-eabi-gccVSCodeOpenOCD

2.3 涉及硬件工具

STM32F103RCT6,芯片这里以STM32为例。

DAP-Link,下载与仿真这里以CMSIS-DAP仿真器为例。

3. 工具链下载与安装

3.1 CMake

CMake(英文 Cross platform Make 的缩写)它不属于构建系统,而是构建系统生成器,属于一个开源跨平台构建工具,在 Linux 平台生成构建系统 Make 的Makefile文件,在 Windows 平台生成 Visual Studio 或 MSVC 的工程等。所以具体的构建工作还是需要交给例如 Make,Ninja,MSVC 等这些构建系统去执行。在这里我们主要应用它来管理C/C++源码以及生成Makefile文件。

下载: /download/

选择:cmake-3.24.1-windows-x86_64.msi(这是目前最新版,选择其他版本也可以)

安装后需要将bin文件夹添加到 Windows 系统的用户环境变量中,以便可以使用命令调用它。

添加好环境变量之后在 Windows 终端中执行cmake命令能够输出以下信息表明安装成功

Microsoft Windows [版本 10.0.19044.1889](c) Microsoft Corporation。保留所有权利。C:\Users\0615>cmakeUsagecmake [options] <path-to-source>cmake [options] <path-to-existing-build>cmake [options] -S <path-to-source> -B <path-to-build>Specify a source directory to (re-)generate a build system for it in thecurrent working directory. Specify an existing build directory tore-generate its build system.Run 'cmake --help' for more information.C:\Users\0615>

Windows 端的 CMake 是含有图形界面的,所以在 Windows 上既可以使用命令操作,也可以使用图形化来操作,图形界面如下图。

该软件具体如何使用这里不讲解,可以到各大博客平台搜索相关教程。

3.2 MiniGW

MinGW(即 Minimalist GNU for Windows 的缩写),它是一些头文件和端口库的集合,该集合允许人们在没有第三方动态链接库的情况下使用 GCC(GNU Compiler C)产生 Windows32 程序。

MinGW 收集了一系列免费的 Windows 平台的头文件和库文件,同时整合了GNU 的工具集,特别是 GNU 程序开发工具gccg++make等等。MinGW 是完全免费的自由软件,它在 Windows 平台上模拟了 Linux 下 GCC 的开发环境。为了那些不喜欢工作在 Linux(FreeBSD) 操作系统而留在 Windows 的人提供一套符合 GNU 的 GNU 工作环境。

下载: /projects/mingw-w64/files/

选择: mingw-w64

安装后需要将bin文件夹添加到 Windows 系统的用户环境变量中,以便可以使用命令调用它。

在 Windows 终端中执行make -v命令,能够输出以下信息表明安装成功。

C:\Users\0615>make -vGNU Make 4.2.1Built for x86_64-w64-mingw32Copyright (C) 1988- Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later </licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.C:\Users\0615>

一般情况下执行make命令 Windows 会提示make为无法识别的命令,这是因为在 MiniGW 安装目录的bin文件夹下make.exe的全称为mingw32-make.exe为了简化命令长度将其复制一份并命名为make.exe,同时可以保留原件作为备份。

3.3 gcc-arm

gcc-arm-none-eabi 是一个开源的 ARM 开发工具链,它包括了 GNU 编译器 GCC,以及 GDB 调试器,所以不要认为它只是个 GCC。可用于 Windows,Linux,MacOS 系统上的交叉编译。

下载: /downloads/-/gnu-rm

选择:gcc-arm-none-eabi-10.3-.10-win32.exe 或 gcc-arm-none-eabi-10.3-.10-win32.zip 压缩包形式的(这个是目前最新版,选择其他版本也可以)。

安装后需要将bin文件夹添加到 Windows 系统的用户环境变量中,以便可以通过命令调用它。

在在 Windows 终端中执行arm-none-eabi-gcc命令,能够输出以下信息则表明安装成功。

C:\Users\0615>arm-none-eabi-gccarm-none-eabi-gcc: fatal error: no input filescompilation terminated.C:\Users\0615>

3.4 openOCD

openOCD(即 Open On-Chip Debugger 缩写)是一个开源的片上调试器,openOCD 旨在提供针对嵌入式设备的调试,系统编程和边界扫描功能,openOCD 需要搭配调试器使用,支持的调试器有 ST-Link,DAP-Link,J-Link 等。

下载: /arm-eabi/openocd/

选择:openocd-1118.7z(这个是目前最新版,选择其他版本也可以)

安装后需要将bin文件夹添加到 Windows 系统的用户环境变量中,以便可以通过命令来调用它。

在在 Windows 终端中执行openOCD命令,能够输出以下信息则表明安装成功。

C:\Users\0615>openOCDOpen On-Chip Debugger 0.11.0 (-11-18) [/sysprogs/openocd]Licensed under GNU GPL v2libusb1 09e75e98b4d9ea7909e8837b7a3f00dda4589dc3For bug reports, read/doc/doxygen/bugs.htmlembedded:startup.tcl:26: Error: Can't find openocd.cfgin procedure 'script'at file "embedded:startup.tcl", line 26Info : Listening on port 6666 for tcl connectionsInfo : Listening on port 4444 for telnet connectionsError: Debug Adapter has to be specified, see "adapter driver" commandembedded:startup.tcl:26: Error:in procedure 'script'at file "embedded:startup.tcl", line 26C:\Users\0615>

3.5 VSCode

VSCode 是一个开源的代码编辑器,由 MicroSoft 发行,有意思的是 VSCode 自带终端,支持安装嵌入式开发插件,例如 ARM 仿真调试插件,以及支持运行自定义的任务来调用其他的软件。

下载: /

选择:Windows 版本,建议使用最新版本。

3.6 已添加的环境变量

一般情况下添加环境变量添加到用户环境变量即可,当然添加到系统环境变量也是可以的(区别在于添加到系统环境变量则该变量对所有用户有效)。

必须添加环境变量的工具最终添加环境变量后的效果,如下图

4. VSCode 配置

前面的属于基础工具,安装好并添加好环境变量后就没有更多需要配置的东西了,下面我们来配置 VSCode,这才是整个开发环境搭建过程中需要重点讲解的环节。

VSCode 中需要安装两个插件,分别为 C/C++ 插件,Cortex-Debug 插件。下面我们来看看这两个插件的作用和安装以及配置方法。

4.1 安装 C/C++ 插件

C/C++ 插件是微软官方提供的,主要用于支持 VSCode 的 C/C++ 代码跳转,代码自动补全以及 C/C++ 的语法高亮,如果用于开发桌面应用的话该插件还可以实现代码编译,但是我们用于开发嵌入式软件我们就不需要用它来编译代码了,而是用我们前面自己安装的 arm-none-eabi-gcc。

启动 VSCode 在侧边的扩展选项卡,在搜索框中输入 C/C++ 即可搜索到该插件,如下图。

搜索到后直接点击安装,安装完成后的效果如下图。

安装好插件后我们可以简单的配置一下C/C++插件,按下键盘的F1按键,按下后弹出如下面板,在输入框中输入 C/C++ 搜索,得到 C/C++ 编辑配置,支持两种配置方式,UI 方式或修改 JSON 文件方式,我们点击选择 UI 方式,点击这时会在文件夹中自动生成一个.vscode文件夹,并生成一个c_cpp_properties.json文件。

选择后会弹出 C/C++ 插件的配置页面,如下图。

在页面中找到 IntelliSense 模式,将模式修改为 gcc-arm,如下图。

在页面中找到 C 标准,C++ 标准,修改为你希望的版本,这里我选择 C 语言标准使用 C17,C++ 标准使用 C++14,如下图所示。

4.2 安装 Cortex-Debug 插件

Cortex-Debug 插件以用来调试 ARM Cortex 系列芯片,所以不只可以用来调试STM32哦。前面我们安装了openOCD并添加了环境变量,那么在使用调试功能时Cortex-Debug插件就可以调用openOCD执行下载和调试任务。

搜索到后直接点击安装,安装完成后的效果如下图。

4.3 配置 VSCode 实现编译下载和调试

4.3.1 代码编译

编译程序可以在 VSCode 自带的终端中输入并执行 make 命令进行编译,执行该命令时需要进入Makefile文件所在的目录。

4.3.2 固件下载

使用 openOCD 下载程序需要使用命令操作,通过阅读 openOCD 的帮助信息可知下载程序需要使用openocd -f命令。

在命令中需要指定调试的接口的.cfg文件,比如ST-Link调试接口对应stlink-v2.cfg文件,DAP-Link调试接口对应cmsis-dap.cfg文件。这些文件可以在 openOCD 的安装目录下的interface文件夹下找到。

在命令中还需要指定目标芯片的.cfg文件,比如STM32F103对应stm32f1x.cfg文件,STM32F4对应stm32f4x.cfg文件。这些文件可以在 openOCD 安装目录下的target文件夹下找到。

在命令中还需要指定待下载的固件,固件文件支持.elf.hex格式,将编译好的固件所在路径及名称填写到命令中即可。

将上述命令组合起来,最后我们可以得到以下这样一条命令,在终端中执行该命令即可将固件下载到单片机中。

openocd -f interface/cmsis-dap.cfg -f target/stm32f1x.cfg -c "program build/Hello.elf verify reset exit"

但是每次下载需要输入上述命令,使用起来总是不够方便优雅,所以我们可以将上述的命令自定义成 VSCode 中的一个任务,由 VSCode 去执行,这样点击一下图形化菜单即可执行上述命令,将程序下载到单片机中。

可以在 VSCode 菜单栏中点击终端,在下拉菜单中选择配置任务,点击后会在.vscode文件夹下自动生成一个task.json文件和模板。如果你熟悉内容格式的前提下也可以直接一步到位在项目根目录.vscode文件夹下创建task.json文件。

task.json文件内容及格式如下,为了示例直观,使用到的文件路径直接使用绝对路径,其中用到的的.cfg路径,待下载固件路径,以你自己电脑的路径为准,可以使用相对路径的。

{"version": "2.0.0","tasks": [{"type": "shell","label": "Download","command": "openocd","args": ["-f","D:/Others/openocd-0.10.0/scripts/interface/cmsis-dap.cfg","-f","D:/Others/openocd-0.10.0/scripts/target/stm32f1x.cfg","-c","program C:/Users/0615/Desktop/Ctrl-FOC-Lite-main/2.Firmware/STM32_HAL_version/Ctrl-FOC-Lite-fw/build/Ctrl-FOC-Lite-fw.elf verify reset exit"],"problemMatcher": ["$gcc"],"group": "build",}]}

在菜单栏中点击终端,在下拉菜单中点击运行任务

点击运行任务菜单后会弹出已有的任务列表,可以看到我们自定义的Dowload任务已经显示在任务列表了,点击Download即可下载固件到单片机。

4.3.3 在线调试

在线调试就需要用到我们安装的Cortex-Debug插件了,所以我们需要将Cortex-Debug插件和openOCD对接起来,让Cortex-Debug插件能够调用openOCD

如果我们之前没有给 VSCode 配置过调试功能,那么点击 VSCode 侧边的调试按钮会提示我们需要创建launch.json文件,点击提示后会自动在.vscode文件夹下创建launch.json文件和模板。

你也可以直接在在项目根目录.vscode文件夹下创建lanuch.json文件,内容及格式如下,其中用到的的svdFile.cfg路径,待下载固件的路径,以你自己电脑的路径为准,这里为了直观我直接使用绝对路径,自己使用时可以改为相对路径。

{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: /fwlink/?linkid=830387"version": "0.2.0","configurations": [{"cwd": "${workspaceRoot}","executable": "C:/Users/0615/Desktop/Ctrl-FOC-Lite-main/2.Firmware/STM32_HAL_version/Ctrl-FOC-Lite-fw/build/Ctrl-FOC-Lite-fw.elf","name": "Debug with OpenOCD","request": "launch","type": "cortex-debug","servertype": "openocd","configFiles": ["D:/Others/OpenOCD-1118-0.11.0/share/openocd/scripts/interface/cmsis-dap.cfg","D:/Others/OpenOCD-1118-0.11.0/share/openocd/scripts/target/stm32f1x.cfg",],"svdFile": "C:/Users/0615/Desktop/MiniBot/build/STM32F103xx.svd",}]}

编写好launch.json文件后可以在这里看到 VSCode 出现了一个运行按钮并且已经识别出了 openOCD,并且还显示了下拉菜单用于选择不同的 GDB 调试服务(注意 openOCD 实际上就是一个 GDB 调试服务,GDB 在线调试是需要基于它的),如下图。

点击上图的按钮后开始进入在线调试模式,进入调试模式过程中输出信息,如下。

进入在线调试模式后代码中出现了运行位置指针,以及顶部存在一个用于执行和控制调试的菜单栏,如下图。

了解 SVD 文件

svd 文件指的是仿真寄存器描述文件,根据实际测试svdFile仿真寄存器描述文件对于调试功能不是必须的,但是如果提供该文件则可以在调试的过程中查看每个外设所包含的所有寄存器的值。例如使用了 STM32 的SVD文件后调试的过程中我们可以看到 STM32 的 GPIO 外设BSRR寄存器的参数值,如下图。

SVD 文件下载: /posborne/cmsis-svd

5. 如何搭建工程

最终到这里你可能会有一个疑问,使用这样的工具链后,那该怎么搭建工程?比如说如何搭建大家都熟悉的 STM32 的工程。

搭建工程实际上和使用Keil是类似的方法,首先就是将用到的 STM32 固件库中的文件以及我们编写的源码文件按照我们喜欢的规则组织好,然后编写 CMake 的CMakeLists.txt文件去描述这个文件组织规则,比如说要包含哪些头文件,要编译哪些文件,指定编译后的固件名称,等等。

所以对于使用了 CMake 之后CMakeLists.txt就是所谓的工程,工程的本质就是管理一些编译的参数,项目编译的选项,包含的文件等,这些CMakeLists.txt都能够做到。

所以使用 CMake 之后不要求具备编写Makefile文件的能力,但是需要会编写

CMakeLists.txt文件,具体如何编写CMakeLists.txt这里不讲解,可以到各大博客平台搜索相关教程。

注意:由于我们现在使用 ARM 版本gcc来编译工程了,所以在搭建工程(比如 STM32 的工程)时.s启动文件的选择上因该选择gcc版本,而不能再继续选择Keil版本。

使用 gcc 编译需要使用链接文件,所以需要准备好链接文件,链接文件可以从官方的固件库中找到,例如 STM32F103RC 的链接文件可以选择STM32F103XB_FLASH.ld根据你的型号以及 Flash 的容量选择对应的链接文件,否则会出现系统时钟初始化不了的问题。

6. 可能遇到的问题

(1)CMake 构建过程中 ABI 编译器状态检测无法通过问题,这是因为在编写CMakeLists.txt文件时没有指定 ARM 的交叉编译链,导致 CMake 调用了默认的标准 gcc 进行编译。

(2)程序固件无法下载问题,这可能是openOCD版本太低,或与下载器不兼容导致的问题,可以安装最新版本的openOCD以解决问题。

(3)提示gdb版本太低无法进入调试问题,这是arm-none-eabi-gcc版本太低导致的问题,安装一个新的版本即可。

7. CMakeLists 模板

在此附上一份完整的基于 STM32F103 HAL 库的 CMake 模板,注意 CMakeLists 文件用到的编译选项,以及 HAL 库或标准库的宏定义,例如USE_HAL_DRIVER__MICROLIBSTM32F1STM32F1xxSTM32F103xB

# No operating systemset(CMAKE_SYSTEM_NAME Generic)set(CMAKE_SYSTEM_VERSION 1)cmake_minimum_required(VERSION 3.21)# specify cross compilers and toolsset(CMAKE_C_COMPILER arm-none-eabi-gcc)set(CMAKE_CXX_COMPILER arm-none-eabi-g++)set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)set(CMAKE_AR arm-none-eabi-ar)set(CMAKE_OBJCOPY arm-none-eabi-objcopy)set(CMAKE_OBJDUMP arm-none-eabi-objdump)set(SIZE arm-none-eabi-size)# skip compiler checksset(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)project(MiniBot C CXX ASM)set(CMAKE_CXX_STANDARD 17)set(CMAKE_C_STANDARD 11)add_compile_options(-mcpu=cortex-m3 -mthumb -mthumb-interwork)add_compile_options(-ffunction-sections -fdata-sections -fno-common -fmessage-length=0)# uncomment to mitigate c++17 absolute addresses warnings#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-register")# Enable assembler files preprocessingadd_compile_options($<$<COMPILE_LANGUAGE:ASM>:-x$<SEMICOLON>assembler-with-cpp>)if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")message(STATUS "Maximum optimization for speed")add_compile_options(-Ofast)elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")message(STATUS "Maximum optimization for speed, debug info included")add_compile_options(-Ofast -g)elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")message(STATUS "Maximum optimization for size")add_compile_options(-Os)else ()message(STATUS "Minimal optimization, debug info included")add_compile_options(-Og -g)endif ()include_directories(./${CMAKE_SOURCE_DIR}/drivers/CMSIS/Include${CMAKE_SOURCE_DIR}/drivers/CMSIS/Device/ST/STM32F1xx/Include${CMAKE_SOURCE_DIR}/drivers/STM32F1xx_HAL_Driver/Inc${CMAKE_SOURCE_DIR}/drivers/STM32F1xx_HAL_Driver/Inc/Legacy${CMAKE_SOURCE_DIR}/main)add_definitions(-DUSE_HAL_DRIVER -D__MICROLIB -DSTM32F1 -DSTM32F1xx -DSTM32F103xB)aux_source_directory(${CMAKE_SOURCE_DIR}/drivers/STM32F1xx_HAL_Driver/Src HAL_DRIVER)aux_source_directory(${CMAKE_SOURCE_DIR}/drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates SYSTEM)aux_source_directory(${CMAKE_SOURCE_DIR}/main MAIN)set(STARTUP ${CMAKE_SOURCE_DIR}/drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/startup_stm32f103xb.s)set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/linker/STM32F103XB_FLASH.ld)add_link_options(-Wl,-gc-sections,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)add_link_options(-mcpu=cortex-m3 -mthumb -mthumb-interwork)add_link_options(-T ${LINKER_SCRIPT})add_executable(${PROJECT_NAME}.elf ${HAL_DRIVER} ${SYSTEM} ${MAIN} ${STARTUP} ${LINKER_SCRIPT})set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin)add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILDCOMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}COMMENT "Building ${HEX_FILE}Building ${BIN_FILE}")

该模板对应得目录组织如下

如果觉得《VSCode 和 CMake 搭建嵌入式开发环境》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。