在最近的几篇文章中,我们一直在探索如何启动并运行微控制器的嵌入式应用。我们一直在使用Cortex-M QuickStart模板作为应用的基础,同时学习如何设置开发环境。我们现在遇到的问题是,没有办法将应用部署到目标并对其进行调试。
在今天的文章中,我将向您展示在嵌入式目标上启动Rust应用的几种方法。在本文结束时,您将能够使用Visual Studio Code编译和部署一个简单的测试应用。
嵌入式开发人员习惯使用集成开发环境,一些芯片供应商提供这些环境和工具来配置他们的微控制器。不过,目前这些工具都只支持C和C++,这意味着如果你想用Rust编写嵌入式软件,你就得设置你的环境。
值得庆幸的是,这并不是一项具有挑战性的任务。您可以使用Visual Studio Code或您喜欢的任何其他工具来设置环境。对于VS Code,我向您推荐一些用于Rust的扩展。
首先,我建议您安装rust-analyzer。该扩展为使用Rust提供了一些有用的功能,例如:
其次,您应该安装Cortex-Debug。它为Arm Cortex-M微控制器提供了多种调试功能,例如:
只是举几个例子。有了这两个扩展,您就可以在嵌入式目标上启动编译好的Rust应用了。
我要介绍的第一种配置方法不需要使用VS Code。如果您愿意,您可以只使用文本编辑器和简单的终端命令:
cargo run
但是,在此之前,您需要配置Cargo以了解执行运行命令时要做什么。您可以通过创建运行器来实现这一点。
您应该还记得,在之前的一篇文章中,有一个名为.cargo的隐藏文件夹。此文件夹中有一个名为config.toml的文件。如果您打开此文件,会发现用于设置微控制器架构的设置和其他几个设置。其中一个设置允许您配置运行器。
在文件顶部,您将找到几个用于定义运行器的选项。首先,您可以设置运行器,使其甚至不会部署到嵌入式目标,而是在QEMU上执行程序!为此,您需要取消注释以下运行器配置:
[target.thumbv7m-none-eabi]
# uncomment this to make `cargo run` execute programs on QEMU
# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
如果您想使用此运行器,则必须安装QEMU并更新QEMU支持的Cortex-M33机器的命令。运行以下命令会显示,除了musca-a或musca-b1之外,Cortex-M33没有太多选项:
qemu-system-arm -machine help
注意:如果您将Cortex-M Quickstart模板保留为默认的Cortex-M3,则可以轻松仿真您的Rust应用。
除了QEMU之外,还有其他几个选项可用于配置运行器。例如,config.toml中的下几个配置行是:
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# uncomment ONE of these three option to make `cargo run` start a GDB session
# which option to pick depends on your system
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
# runner = "gdb-multiarch -q -x openocd.gdb"
# runner = "gdb -q -x openocd.gdb"
如您所见,对于如何调试目标,已经有几个选项可用。有几个gdb选项可以与openocd配合使用。当我以这种方式调试时,我通常使用arm-none-eabi-gdb选项。
虽然Cargo Runner是启动调试会话的绝佳选择,但如果您使用的是VS Code,则可以利用内置的工具来简化和增强调试会话。例如,使用Runner方法,您将从终端运行GDB,并使用底层方法调试和逐步执行代码。但是,如果您使用VS Code,您将能够使用IDE中常用的许多功能。
首先查看隐藏的文件夹.VSCode。您将看到有一个launch.json文件。打开该文件,可以看到类似下面的配置:
"version": "0.2.0",
"configurations": [
{
"type": "cortex-debug",
"request": "launch",
"name": "Debug (QEMU)",
"servertype": "qemu",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Cargo Build (debug)",
"runToEntryPoint": "main",
"executable": "./target/thumbv7m-none-eabi/debug/stm32-u575-blinky",
/* Run `cargo build --example hello` and uncomment this line to run semi-hosting example */
//"executable": "./target/thumbv7m-none-eabi/debug/examples/hello",
"cpu": "cortex-m3",
"machine": "lm3s6965evb",
},
{
/* Configuration for the STM32F303 Discovery board */
"type": "cortex-debug",
"request": "launch",
"name": "Debug (OpenOCD)",
"servertype": "openocd",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Cargo Build (debug)",
"runToEntryPoint": "main",
"executable": "./target/thumbv7em-none-eabihf/debug/stm32-u575-blinky",
/* Run `cargo build --example itm` and uncomment this line to run itm example */
// "executable": "./target/thumbv7em-none-eabihf/debug/examples/itm",
"device": "STM32F303VCT6",
"configFiles": [
"interface/stlink-v2-1.cfg",
"target/stm32f3x.cfg"
],
"svdFile": "${workspaceRoot}/.vscode/STM32F303.svd",
"swoConfig": {
"enabled": true,
"cpuFrequency": 8000000,
"swoFrequency": 2000000,
"source": "probe",
"decoders": [
{ "type": "console", "label": "ITM", "port": 0 }
]
}
}
]
}
如果仔细检查此文件,您会注意到有两种配置:
我们对第二个配置更感兴趣。仔细观察,可以发现配置的一些细微变化。
首先确保你的可执行文件路径是正确的,默认情况下,可执行文件路径如下:
“executable”: “./target/thumbv7em-none-eabihf/debug/stm32-u575-blinky”,
运行cargo build并深入目录树会发现它不是正确的路径!STM32U575的正确路径应该是:
“executable”: “./target/thumbv8m.main-none-eabihf/debug/stm32-u575-blinky”,
接下来,您会发现目标处理器不正确。它当前设置为:
“device”: “STM32F303VCT6”,
对于STM32U575,设备应更新为:
“device”: “STM32U575ZIT”,
由于我们使用的处理器不同,这意味着配置也需要更新为:
"configFiles": [
"interface/stlink-v2-1.cfg",
"target/stm32u5x.cfg"
],
请注意,我们使用的是stlink。它安装在所有ST Microelectronics开发板上。您可以轻松地将其替换为J-Link或其他调试器。
最后,要更新的配置的最后一部分是SVD文件。SVD文件包含微控制器上存在的所有寄存器和设置的列表。通过它,我们可以窥视内存映射,了解其中的内容。正确的设置是:
“svdFile”: “${workspaceRoot}/.vscode/stmu575.svd”,
请注意,我指定的路径是自定义的,默认情况下,stmu575.svd文件不在那里。您需要访问芯片供应商的网站,搜索并下载与您的目标相匹配的SVD文件。
此时,Rust应用除了初始化处理器外不执行任何其他操作。但是,该测试与其他测试一样好,可确保您可以编译代码并将其部署到目标。
在VS Code中,您可以通过单击IDE左侧的“运行和调试”菜单来启动已编译的Rust应用。然后您将看到一个绿色的运行箭头。在单击它之前,请使用下拉菜单选择“调试(OpenOCD)”。然后,按下绿色的播放箭头。
如果您的启动配置正确,您将看到熟悉的调试会话启动过程,并且会发现自己位于主函数开头处!
配置Rust应用以便将其部署到嵌入式目标并不比在供应商IDE中更困难。如您所见,您需要采取一些额外的步骤来设置环境。但是,这些变化很小而且很简单。
此时,您可以按照以下几个步骤继续您的嵌入式Rust之旅:
在下一篇文章中,我们将通过研究外围访问原型以及它们如何访问微控制器上的底层设备来深入研究嵌入式Rust。
(原文刊登于EDN姊妹网站Embedded,参考链接:Embedded Rust: Creating a Launch Configuration,由Ricardo Xie编译。)