CLion 教程 | 使用开源调试工具 OpenOCD 实现树莓派对 MCU 的远程调试
嵌入式开发者如何设置进行编程所需的一切呢?典型的有线设置包括放在开发者桌上的设备,以及将其连接到调试探头的带状线缆,调试探头又通过 USB 线缆连接到开发者的计算机上的探头专用软件和 IDE。
在许多情况下,这种设置可以正常工作。但嵌入式设备在现实世界的运用可没这么简单。有时,我们会使用基于 MCU 的控制板管理高压或危险设备。有时,这些设备安装在户外。设备可能会在轮子上移动,也可能漂浮在水面上,甚至还可能安装在某个远程位置。在这些情况下,使用有线设置不仅不方便,而且可能造成危险。
当我开始开发户外设备时,我很快遇到了这个问题。我检查了自己手头上的资源,发现了一块树莓派(Raspberry Pi)开发板。我花了几个小时将它设置为无线调试探头,现在它完美运行。在这篇教程中,我们就来看看这一切是如何实现的。
最简单的无线设置原则
每个基于 ARM 的 MCU 都有一个双线调试接口 (SWD) 和一条复位线。这三条线都应该连接到调试探头。在我的无线设置中,我使用 Raspberry Pi GPIO 排针直接连接到设备。在软件方面,我的树莓派运行开源的片上刷写和调试实用工具 OpenOCD 作为远程 GDB 服务器,并通过 Wi-Fi 将一个与 CLion IDE 捆绑的调试器与其相连。开放网络通信可能不安全,因此我将 GDB 与 OpenOCD 之间的 TCP 通道包装为 SSH 隧道。下面的示意图展示了两种设置之间的差异。
常规设置:
无线设置:
哪种开发板更合适?
在我的设置中,我使用了 Raspberry Pi Zero W,我认为这是一个非常好的选择。它很小巧。附带板载 Wi-Fi 模组。功耗相对较低。无需风扇冷却。购买方便。而且,运行速度够快。但是,与 RPi 2+ 相比,这块开发板有几个缺点。它的 CPU 速度较慢,从头开始设置可能需要更长的时间。此外,RPi Zero W 仅支持 2.4GHz Wi-Fi 网络,不支持 5GHz。
您可以使用任何您喜欢的树莓派开发板。唯一的主要区别是需要调整的网络设置和 OpenOCD 配置参数:bcm2835gpio_peripheral_base 和 bcm2835gpio_speed_coeffs。
树莓派操作系统和连接
首先,我们需要启动和运行树莓派,并连接到 Wi-Fi 网络。这需要一张空的 SD 卡,4 GB 应该足够了。
第一步是将操作系统镜像复制到 SD 卡。最好选择 Raspberry Pi OS (32-bit) Lite。您可以在这里找到 Windows、Linux 和 macOS 的官方安装说明。
将镜像写入 SD 卡后,下一步是确保将开发板连接到 Wi-Fi 网络。弹出 SD 卡并将其插入读卡器,然后按照以下说明设置 Wi-Fi。(请注意,RPi Zero W 仅支持 2.4GHz Wi-Fi。)
接下来,将名为 ssh 的文件写入 SD 卡的根文件夹。文件的内容并不重要,即使是空文件也可以。这将激活 ssh 服务器,以便在启动 Raspberry 后进行远程访问。 更多详细信息。
现在,我们可以将卡插入树莓派并将其打开。如果一切正常,几分钟后,开发板将显示为网络中的一个新 Wi-Fi 设备。可以在 Wi-Fi 路由器的 DHCP 状态页面查看其 IP 地址。建议在该页面为开发板设置一个永久 IP 地址。在我的示例中,地址为 192.168.0.110。
为了控制开发板,我们需要一个 SSH 客户端。在 Linux 和 macOS 上使用 ssh 工具,在 Windows 上使用 putty 工具:
putty.exe [email protected]
默认密码为 raspberry。我们强烈建议您登录开发板后立即更改密码。可以使用 passwd 命令更改密码。
下一步是更新 Raspberry OS。这很耗时,但我还是建议您进行更新。最好让所有 Linux 软件保持最新。可以使用命令:
sudo apt update; sudo apt -y full-upgrade; sudo apt -y autoremove --purge
进行更新。重启开发板 (sudo reboot),然后使用新密码重新登录。
OpenOCD 安装
由于没有为 Raspberry 预构建的 OpenOCD 二进制软件包,我们需要自己构建。此过程可能需要一些时间,请耐心等待。
首先,必须使用以下命令安装 Git、构建工具和库:
sudo apt install -y git gcc binutils make libtool pkg-config autoconf automake texinfo libgpiod-dev libusb-1.0
接下来,我们需要下载 OpenOCD 源。对于我们的目的,我们只需要最新修订,对 Git 仓库进行浅克隆就足够了。以下命令将在 openocd-git 文件夹中创建该克隆:
git clone --depth 1 git://git.code.sf.net/p/openocd/code openocd-git
我们来配置、构建并安装实际的实用工具。应逐个调用以下序列中的命令:
cd openocd-git
./bootstrap
./configure --enable-linuxgpiod --enable-bcm2835gpio --enable-sysfsgpio
make
sudo make install
等这些命令运行完毕后,OpenOCD 就准备就绪了。
最终 Raspberry 设置
OpenOCD 是一个用于系统内编程和片上调试的实用工具。它支持多种不同的微控制器核心以及不同的刷写接口和不同的协议。OpenOCD 使用三种类型的配置文件:
探头接口配置。
目标设备核心配置。
开发板配置,通常包括对探头接口的引用、对核心配置的引用以及可选的调整。
我们不会触及核心,但我们确实需要探头接口配置。以下命令会在 pi 用户主目录下创建一个名为 rpi1-gpio.cfg 的配置。
cat <<EOF > ~/rpi1-gpio.cfg
#
# Config for using Raspberry Pi's expansion header
#
# This is best used with a fast enough buffer but also
# is suitable for direct connection if the target voltage
# matches RPi's 3.3V and the cable is short enough.
#
# Do not forget the GND connection, pin 6 of the expansion header.
#adapter driver bcm2835gpio
bcm2835gpio_peripheral_base 0x20000000
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
# These depend on system clock, calibrated for stock 700MHz
# bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET
bcm2835gpio_speed_coeffs 113714 28
# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 22 18
bcm2835gpio_swd_nums 25 24
# If you define trst or srst, use appropriate reset_config
# Header pin number: 26
# bcm2835gpio_trst_num 7
# reset_config trst_only
# Header pin number: 12
bcm2835gpio_srst_num 18
reset_config srst_only srst_push_pull
# If you have both connected,
# reset_config trst_and_srst srst_push_pull
transport select swd
EOF
从上面的配置文件中,我们可以看到 GPIO 排针引脚分配:
Pin 6 -> GND
Pin 12 -> !RESET
Pin 18 -> SWDIO
Pin 22 -> SWCLK
还有最后一个可选步骤。 无线探头的引脚分配可能很容易忘记,但我们可以进行方便的提醒。 以下命令会添加一个带有引脚分配的登录横幅。
cat <<EOF1 >>~/.profile
cat <<EOF
RPi GPIO Header Pinout
+--------+
| 1 2 | +5V
| 3 4 |
| 5 6 | GND
| 7 8 |
| 9 10 |
| 11 12 | RESET
| 13 14 |
| 15 16 | TMS
| 17 18 | SWDIO/TDI
| 19 20 |
| 21 22 | SWCLK/TCK
| 23 24 | TDO
| 25 26 |
| 27 28 |
| 29 30 |
| 31 32 |
| 33 34 |
| 35 36 |
| 37 38 |
| 39 40 |
+--------+
EOF
EOF1
下次我们忘记引脚分配时,只需重新登录 Raspberry,它就会显示在横幅上。
现在,我们已经完成了 Raspberry 软件的设置。接下来,我们将继续介绍硬件和固件示例项目。但在此之前,我们需要考虑最后一点。
设置示例项目
尝试此示例需要 CLion IDE 和 ARM 嵌入式工具链。设置它们的说明分别可以在这里和这里找到。
对于示例项目,我将使用焊接到 STM32F3-Discovery 开发板上的 MCU,但使用 RPi 而非板载 ST-LINK 接口。示例项目可以从 GitHub 仓库克隆。该项目用 C 和 C++17 编写。
硬件接线
首先,将两根跳线从 ST-LINK 连接器上拆下。板载刷写探头现在已经与 MCU 断开。
本演示的目标 MCU 使用 GPIO 排针的引脚 2,由树莓派本身供电。
注意!如果您自行制作设备,请确保您的目标设备支持 5 V 电源电压,且功耗不超过 200 mA。否则,请使用其他电源方案。
因此,接线应如下所示:
Rpi Pin 6 -> GND -> DISCO GND
Rpi Pin 12 -> RESET -> DISCO nRST
Rpi Pin 18 -> SWDIO -> DISCO PA13
Rpi Pin 22 -> SWCLK -> DISCO PA14
Rpi Pin 2 -> PWR -> DISCO 5V
如您所见,不涉及任何额外组件 – 只涉及目标设备、电源、RPi 和一些电线。
启动
演示项目应该运行本地安装的 OpenOCD,并使用常规的有线设置。
我们使用以下参数创建一个 Embedded GDB Server(嵌入式 GDB 服务器)类型的备用运行配置。
Target(目标)– 从列表中选择一个;默认情况下应该只有一个。
Executable(可执行文件)– 从列表中选择一个;默认情况下应该只有一个。
Debugger(调试器)– 捆绑的或来自 ARM 工具链的均可。
Target remote args(目标远程实参)– tcp::3333。GDB 服务器将尝试连接到本地主机,端口为 3333。
GDB server(GDB 服务器)– 指向您的 plink(Windows + putty) 或 ssh(Linux、macOS)实用工具的路径
GDB server args(GDB 服务器实参)– -t -pw somepassword-L 3333:127.0.0.1:3333 pi@your_rpi_ip_address openocd -f rpi1-gpio.cfg -f target/stm32f3x.cfg
请注意,您必须使用自己的 RPi IP 地址和密码。此外,您可以使用非 target/stm32f3x.cfg 的目标配置文件。
GDB 服务器实参是这些参数中最麻烦的。我们来逐一介绍一下它们的各个元素。
-t 会为在 RPi (OpenOCD) 启动的实用工具保留一个伪终端。
-pw somepassword 会提供一个 ssh 密码。请使用您自己的密码。
pi@your_rpi_ip_address 会提供 RPi 开发板的用户名和 IP 地址。请使用您自己的地址。
-L 3333:127.0.0.1:3333 会组织加密的 SSH 隧道。RPi 开发板上的本地端口 3333 会被透明地转发到开发者计算机的端口 3333。
openocd -f rpi1-gpio.cfg -f target/stm32f3x.cfg 会使用我们的接口配置和 STM32F3 系列内核在 RPi 上启动 OpenOCD。
现在,我们还剩最后一项需要设置:
Advanced GDB Server Options -> Startup Delay – 1000 ms(高级 GDB 服务器选项 -> 启动延迟 – 1000 毫秒)
完成!只需点击 Debug(调试)按钮 – MCU 固件将被编译和刷写,调试器会话将启动。
附加内容 – JTAG 和 RISC-V
您有没有注意到,在引脚分配提示上,一些额外的引脚上标有典型的 JTAG 信号?这是有意为之,因为也支持 JTAG 接口。我们来使用 JTAG 接口。
以下脚本会生成一个 JTAG 配置文件:
cat <<EOF >~/rpi1-gpio-jtag.cfg
#
# Config for using Raspberry Pi's expansion header
#
# This is best used with a fast enough buffer but also
# is suitable for direct connection if the target voltage
# matches RPi's 3.3V and the cable is short enough.
#
# Do not forget the GND connection, pin 6 of the expansion header.
#adapter driver bcm2835gpio
bcm2835gpio_peripheral_base 0x20000000
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
# These depend on system clock, calibrated for stock 700MHz
# bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET
bcm2835gpio_speed_coeffs 113714 28
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
# Header pin numbers: 22 16 18 24
bcm2835gpio_jtag_nums 25 23 24 8
# If you define trst or srst, use appropriate reset_config
# Header pin number: 26
# bcm2835gpio_trst_num 7
# reset_config trst_only
# Header pin number: 12
bcm2835gpio_srst_num 18
reset_config srst_only srst_push_pull
# If you have both connected,
# reset_config trst_and_srst srst_push_pull
adapter speed 600
EOF
在本例中,我连接了由 GD32VF103 芯片驱动的 Longan Nano 开发板,该芯片是 RISC-V 内核,因此没有 SWD 接口。
Rpi Pin 1 -> 3.3V -> Longan 3V3 <strong>Be careful! Pin 2 5V might damage your board</strong>
Rpi Pin 6 -> GND -> Longan GND
Rpi Pin 16 -> TMS -> Longan TMS
Rpi Pin 18 -> TDI -> Longan TDI
Rpi Pin 22 -> TCK -> Longan TCK
Rpi Pin 24 -> TDO -> Longan TDO
我使用了从 xPack 仓库下载的 Risc-V 工具链。捆绑的调试器不支持 Risc-V,因此我们必须使用工具链调试器。
不要忘记切换 CMake 设置页面上的工具链
在撰写这篇博文时(2021 年 3 月),OpenOCD master 分支对 RISC-V 芯片的支持还不是特别好,因此 OpenOCD 应该从特定的 Risc-V 复刻克隆,并如上所示进行构建。
示例项目位于 GitHub 上,并且已经在其中创建运行配置。RISC-V MCU 的此运行配置与上面提到的 STM32F3 的配置非常相似,但它使用的 GDB 服务器实参略有不同,这些实参引用不同的传输和不同的 MCU:
-t -pw raspberry -L 3333:127.0.0.1:3333 [email protected] openocd -f ~/rpi1-gpio-jtag.cfg -f target/gd32vf103.cfg
现在,您需要做的就是设置自己的密码和 RPi 网络地址。
结论
树莓派是一款非常流行且易用的单板 Linux 计算机。它通常用于 DIY 项目。OpenOCD 是一个开源程序,用于刷写、调试和测试微控制器,包括 ARM 和 RISC-V 内核以及许多其他内核。与 CLion 一起使用时,这些资源会使嵌入式开发更容易、更愉悦,在某些情况下甚至更安全。这篇博文中介绍的无线设置既适用于业余爱好项目,也适用于专业项目。
本博文英文原作者:Ilia Motornyi
CLion 相关阅读
关于 CLion
CLion 是用于 Windows、Linux 和 macOS 上 C 或 C++开发的智能 IDE。CLion 了解现代 C++ 标准并提供预处理程序支持。它还集成了 GDB/LDB 和一套单元测试框架。
进一步了解 CLion
⏬ 戳「阅读原文」了解更多