Linux 下搭建嵌入式开发环境
本文最后更新于 1172 天前,内容如有失效请评论区留言。

什么,都 3202 年了,你还在用丑陋的 Keil 开发嵌入式?不如来试试在 Linux 下使用现代化编辑器/IDE 优雅地开发嵌入式。本文将介绍如何在 Linux 下搭建完整的嵌入式开发工具链,以WSL2 + VSCode为例进行嵌入式开发。

环境准备

  • WSL2 Ubuntu 22.04 LTS
  • VSCode
  • GNU Make 4.3, cmake 3.26.0-rc6
  • zsh 5.8.1 (x86_64-ubuntu-linux-gnu)

image-20230511164158264

项目结构

整个项目的文件组织结构如下图所示:

image-20230511172041964

以上结构仅是一种示例,大家可以根据自己的项目需求进行调整,编写对应的 CMakeLists.txt 或 Makefile 即可。

开发原理

下面是开发工具链的原理图

image-20230512114215506

img

安装 ARM GNU Toolchain

交叉编译(Cross compiling)是指在一个平台上进行编译,生成在另一个不同平台上运行的可执行程序或库文件的过程。通常,交叉编译用于开发跨平台软件或嵌入式系统。

为什么需要交叉编译?主要有 3 个原因:

  1. 嵌入式系统开发:嵌入式系统通常运行在资源有限的硬件设备上,如嵌入式处理器、微控制器或单片机。这些设备通常不具备强大的计算能力和存储容量,因此需要在更强大的计算机上进行交叉编译,以生成适合嵌入式设备的二进制文件。
  2. 跨平台开发:在开发跨平台软件时,交叉编译可以简化开发流程。例如,如果你要开发一个同时运行在 Windows、Linux 和 macOS 上的应用程序,你可以在一种平台上编译应用程序,并生成可在其他平台上运行的可执行文件。
  3. 提高编译效率:有时候,主机平台上的编译器和开发环境可能更加强大和高效,因此进行交叉编译可以提高编译效率。通过利用更强大的计算机资源,可以更快地生成目标平台上的二进制文件。

交叉编译器的命名规则通常遵循一定的约定,以便清晰地标识其适用的平台和体系结构。通常至少包括 3 部分:[目标平台]-[目标OS]-[功能后缀]

  • 目标平台:arm-, mips-, x86_64-, riscv64-
  • 目标 OS:linux, win32, android, none
  • 功能后缀:-gcc, -g++, -ld, -gdb

实际上命名也没有官方标准,也有很多命名确实没有按照这个规则。我们需要安装的 C 语言编译器应该是 arm-none-eabi-gcc,其中 EABI(Embedded Application Binary Interface,EABI) 是一种为嵌入式系统设计的二进制接口标准,用于确保在不同的嵌入式平台上可移植性和互操作性。

使用包管理器安装

sudo apt install gcc-arm-none-eabi

但是 Ubuntu 官方 APT 源似乎对 gcc-arm-none-eabi 已经停止维护了,并且安装后不含有 arm-none-eabi-gdb 。可以考虑使用 gdb-multiarch 替代。

sudo apt install gdb-multiarch

gdb-multiarch 是一个针对多种体系结构的调试器,它是 GNU 调试器(GDB)的一个变体。它的设计目的是支持交叉编译环境中多个不同体系结构的调试工作。它支持同时调试多个不同体系结构的可执行文件,无需手动更改调试器设置或使用不同的调试器实例。通过选择正确的体系结构并加载对应的调试器插件,开发人员可以在同一个 gdb-multiarch 会话中进行跨体系结构的调试操作。

使用二进制文件安装

Arm GNU Toolchain Downloads

image-20230511175829109

安装有些坑,解压后没有 Makefile 文件,需要手动安装。解压到 /opt/gcc-arm-none-eabi,然后添加环境变量,可以在 ~/.zshrc 中添加如下一行,每次启动 zsh 的时候就能够自动加入环境变量了。

export PATH=$PATH:/opt/gcc-arm-none-eabi/bin

正常情况下 arm-none-eabi-gcc 等工具应该能正常使用了,但可能依然无法使用 arm-none-eabi-gdb。如果你遇到如下报错:

arm-none-eabi-gdb: error while loading shared libraries: libncursesw.so.5: cannot open shared object file: No such file or directory

则,

sudo apt install -y libncursesw5

此外,ARM GNU Toolchain 还需要 Python3.8 支持,如果看到如下报错:

Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Python path configuration:
  PYTHONHOME = (not set)
  PYTHONPATH = (not set)
...
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

则,

sudo apt install -y python3.8

如果一切正常,可以看到 GDB 版本如下

image-20230511181430823

安装 usbipd

usbipd 仓库

连接 USB 设备 | Microsoft Learn

如果您是尊贵的 Linux 实体机用户,这一步请跳过。

按照微软文档操作即可,没有任何难度和坑。

usbipd 是用于将 Windows 本地连接的 USB 设备共享给其他机器的开源项目,包括 Hyper-V 虚拟机和 WSL 2。

image-20230511201801397

安装 stlink-tools

stlink-tools 仓库

该怎么把程序烧录到 STM32F401RET6 开发板上呢?一种办法是使用 stlink-tools,另一种办法是使用 OpenOCD。

stlink-tools 是一个开源的工具集,用于编程和调试 STMicroelectronics 制造的 STM32 设备和开发板。

可以直接使用包管理器安装,Github 上最后一次更新是 2021 年 4 月,包管理器安装就能获得最新版本。

sudo apt install stlink-tools

安装好后,插入 STM32F401RE 开发板,确认 stlink-tools 能识别,

st-info --probe

image-20230511204403256

烧录使用st-flash,需要指定 flash 的起始地址和二进制程序文件。

image-20230511204848855

安装 OpenOCD

OpenOCD 官网

OpenOCD(Open On-Chip Debugger)是一个开源的调试和编程工具,用于嵌入式系统开发中与芯片上调试接口(如 JTAG、SWD 等)通信并进行调试、编程和仿真操作。

OpenOCD 提供了一种通用的接口和协议,可以与多种嵌入式芯片和调试接口进行交互。它支持各种处理器架构(如 ARM、RISC-V 等)和调试接口(如 JTAG、SWD、BDM 等),可以与目标系统上的芯片进行连接,并通过调试接口与芯片进行通信。

主要功能有两个:

  • 调试功能:OpenOCD 支持寄存器读写、内存读写、断点设置、单步执行等调试操作,允许开发人员在目标系统上进行调试。它与 GDB 调试器紧密集成,提供了与 GDB 之间的通信接口。
  • 编程功能:OpenOCD 支持对芯片进行编程,包括烧录程序代码、擦除芯片、写入 Flash 存储器等操作。它能够与多种烧录器(如 J-Link、ST-Link 等)集成,实现对芯片的编程。

直接使用包管理器安装

sudo apt install openocd

安装后在 /usr/share/openocd/scripts/ 下可以找到 interface 和 target 文件夹,后面使用 OpenOCD 会用到。

VSCode 配置(基础)

安装 clangd 插件

clangd —— teach your editor C++

当项目配置好后你会发现 vsc 常用的 C/C++ IntelliSense 插件补全速度实在太慢了,键入后大概要七八秒后才显示补全,约等于没有。这时候可以尝试一下 LLVM 的 clangd 了。

What is clangd ?

clangd is a language server that can work with many editors via a plugin. clangd understands your C++ code and adds smart features to your editor: code completion, compile errors, go-to-definition and more. clangd is based on the Clang C++ compiler, and is part of the LLVM project.

换句话说,clangd 是一个语言服务器,可以通过 LSP(Language Server Protocol,语言服务协议)与 IDE 或编辑器进行交互。

clangd 需要知道项目是如何构建的才能正常解析,需要 compile_commands.json 文件,用 CMake 构建的项目可以很容易得到该文件,

# 输出 compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

至少在 clangd 的启动参数中加入以下参数以保证正常运行,

"clangd.arguments": [
      // compelie_commands.json 文件的目录位置(相对于工作区,由于 CMake 生成的该文件默认在 build 文件夹中,故设置为 build)
      "--compile-commands-dir=build",
      // 询问编译器头文件的位置
      "--query-driver=/opt/gcc-arm-none-eabi/bin/arm-none-eabi-gcc"
]

我个人使用的完整配置如下,仅供参考,关于 clangd 运行参数,在终端输入 clangd --help-list-hidden 可查看更多

    // 禁用 C/C++ IntelliSense
    "C_Cpp.errorSquiggles": "disabled",
    "C_Cpp.intelliSenseEngineFallback": "disabled",
    "C_Cpp.intelliSenseEngine": "disabled",
    "C_Cpp.autocomplete": "disabled",

    "clangd.path": "/usr/bin/clangd",
    // clangd 运行参数(在终端/命令行输入 clangd --help-list-hidden 可查看更多)
    "clangd.arguments": [
      // 让 clangd 生成更详细的日志
      "--log=verbose",
      // 启用.clangd配置文件
      "--enable-config",
      // 输出的 JSON 文件更美观
      "--pretty",
      // 全局补全(输入时弹出的建议将会提供 CMakeLists.txt 里配置的所有文件中可能的符号,会自动补充头文件)
      "--all-scopes-completion",
      // 建议风格:打包(重载函数只会给出一个建议)。相反可以设置为detailed
      "--completion-style=bundled",
      // 跨文件重命名变量
      "--cross-file-rename",
      // 允许补充头文件
      "--header-insertion=iwyu",
      // 输入建议中,已包含头文件的项与还未包含头文件的项会以圆点加以区分
      "--header-insertion-decorators",
      // 在后台自动分析文件(基于 complie_commands,我们用CMake生成)
      "--background-index",
      // 启用 Clang-Tidy 以提供「静态检查」
      "--clang-tidy",
      // 同时开启的任务数量
      "-j=8",
      // pch优化的位置(memory 或 disk,选择memory会增加内存开销,但会提升性能) 推荐在板子上使用disk
      "--pch-storage=disk",
      // 启用这项时,补全函数时,将会给参数提供占位符,键入后按 Tab 可以切换到下一占位符,乃至函数末,我选择禁用
      "--function-arg-placeholders=false",
      // compelie_commands.json 文件的目录位置(相对于工作区,由于 CMake 生成的该文件默认在 build 文件夹中,故设置为 build)
      "--compile-commands-dir=build",
      //询问编译器头文件的位置
      "--query-driver=/opt/gcc-arm-none-eabi/bin/arm-none-eabi-gcc"
    ]

clangd 还可以配置 project configuration file,具体来说,就是配置放在项目主目录的 .clangd ,下面是一个我的配置示例:

CompileFlags:
  Add: [-Wno-format]
  Compiler: /opt/gcc-arm-none-eabi/bin/arm-none-eabi-gcc
Diagnostics:
  ClangTidy:
    Remove: [bugprone-sizeof-expression]

安装 Cortex-Debug

Cortex-Debug 仓库

Cortex-Debug Usage

Cortex-Debug is an extension to add debugging capabilities for ARM Cortex-M devices to Visual Studio Code.

img

VSCode Debug 配置

OpenOCD + ST-Link 调试配置

"configurations": [
    {
        "name": "ST-Link Cortex-M4 Debug",
        "type": "cortex-debug",
        "request": "launch",
        "servertype": "openocd",
        "cwd": "${workspaceRoot}",
        "executable": "${workspaceRoot}/build/qingluan.elf",
        "device": "STM32F401RE",
        "configFiles": [
            "interface/stlink-v2-1.cfg",
            "target/stm32f4x.cfg"
        ],
        "svdFile": "${workspaceRoot}/Script/STM32F401.svd",
        "runToEntryPoint": "main",
    }, 
]

J-Link 调试配置

"configurations": [
    {
        "name": "J-Link Cortex-M4 Debug",
        "type": "cortex-debug",
        "request": "launch",
        "servertype": "jlink",
        "cwd": "${workspaceRoot}",
        "executable": "${workspaceRoot}/build/qingluan.elf",
        "device": "STM32F401RE",
        "interface": "swd",
        "svdFile": "${workspaceRoot}/Script/STM32F401.svd",
        "runToEntryPoint": "main",
    }
]

为了能让 Cortex-Debug 知道开发板寄存器内存映射,在 Debug 的时候能够看寄存器的值,需要开发板对应的 CMSIS-SVD 文件(即上述配置中的 STM32F401.svd),在下面的 GitHub 仓库可以找到。

The CMSIS System View Description format(CMSIS-SVD) formalizes the description of the system contained in ARM Cortex-M processor-based microcontrollers, in particular, the memory-mapped registers of peripherals. The detail contained in system view descriptions is comparable to the data in device reference manuals. The information ranges from high-level functional descriptions of a peripheral all the way down to the definition and purpose of an individual bit field in a memory-mapped register.

CMSIS-SVD 仓库

Patched SVD files for STM32 MCUs

打上断点,就可以正常单步 Debug 啦,

image-20230512003104292

汇编代码亦可打断点调试,甚至可以从 Reset_Handler 的第一行代码开始调试

image-20230512003503601

VSCode 配置(可选)

安装 RTOS Views

通过 RTOS Views 可以在单步调试的时候看到当前所有的任务状态、任务优先级、栈空间使用情况、栈空间使用峰值等信息。

为了让 RTOS Views 能正常监测,创建任务时需要使用 OSTaskCreateExt 和 OSTaskNameSet

QQ图片20230512000103

通过 RTOS Views 我发现了代码的 BUG,有任务栈空间开小了导致栈溢出了

安装 Arm Assembly

Adds syntax highlighting for the Arm Assembly language to Visual Studio Code.

汇编代码语法高亮

image-20230512000708976

安装 MemoryView

This is a memory viewer extension specially built to work with debuggers. It can be used with any debugger that supports memory reads (and optional writes). Currently cppdbg, cortex-debug and cspy are the debuggers supported. This extension is more suitable for low level programmers or embedded developers.

image-20230512002045070

安装 SystemView

Converting ST-LINK On-Board Into a J-Link

µC/OS-II User Manual Trace Recording SEGGER SystemView

移植 SystemView 参考的上面 uCOS-II 的文档,坑点只有两处:

  1. 去掉 include "os_cpu.h" 和 CPU_ERR local_err; (部分架构移植 uCOS-II 有这个文件,我们没有这个头文件)
  2. 记着添加 SEGGER_RTT_ASM_ARMv7M.s 和 SEGGER_RTT_printf.c 这两个文件,网页文档的图似乎画漏了

image-20230512120513430

下载后

sudo dpkg -i ./systemview_linux_deb64.deb

WSL2 目前是支持 GUI 的,详见 在适用于 Linux 的 Windows 子系统 上运行 Linux GUI 应用

此外,记着安装 J-Link 驱动,

sudo dpkg -i ./JLink_Linux_V788b_x86_64.deb

成功安装后运行效果如下图,Win98 风格,UI 丑了点,但是能跑

QQ图片20230512121242

References

Arm GNU Toolchain Downloads

Install Arm GNU Toolchain on Ubuntu 22.04

usbipd 仓库

连接 USB 设备 | Microsoft Learn

stlink-tools 仓库

OpenOCD 官网

clangd —— teach your editor C++

Cortex-Debug 仓库

Cortex-Debug Usage

CMSIS-SVD 仓库

Patched SVD files for STM32 MCUs

Converting ST-LINK On-Board Into a J-Link

µC/OS-II User Manual Trace Recording SEGGER SystemView

在适用于 Linux 的 Windows 子系统 上运行 Linux GUI 应用

J-Link 驱动

评论

  1. kk
    Windows Chrome 128.0.0.0
    2 年前
    2024-9-23 21:13:22

    666,谢谢大佬无私分享,准备复刻

  2. harry
    Windows Edge 130.0.0.0
    2 年前
    2024-11-19 18:12:22

    何止大佬,这是先驱啊,我整了好久都没弄好

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇