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

什么,都 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.txtMakefile 即可。

开发原理

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

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/ 下可以找到 interfacetarget 文件夹,后面使用 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 能正常监测,创建任务时需要使用 OSTaskCreateExtOSTaskNameSet

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.sSEGGER_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 驱动

暂无评论

发送评论 编辑评论


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