打印
[开发工具]

使用 Rust 进行嵌入式开发之借尸还魂编写 APM32 应用

[复制链接]
48|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wangqy_ic|  楼主 | 2024-11-17 23:24 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 wangqy_ic 于 2024-11-18 00:15 编辑

#申请原创#
使用 Rust 进行嵌入式开发之借尸还魂编写 APM32 应用

开发环境搭建
本文描述的是在 Windows 系统进行开发,其他系统可参照进行。主要是两个主要步骤:
  • 安装基础环境
  • 安装 Microsoft C++ 生成工具
  • 安装 rustup
  • 安装嵌入式开发所需工具
  • 工具链
  • 其他工具
  • 调试相关工具

安装基础环境
安装好基础环境后,就可以进行 PC 的开发,过程是:
  • 安装 Microsoft C++ 生成工具
  • 安装 rustup

安装 Microsoft C++ 生成工具
从微软的网站下载Microsoft C++ 生成工具,网址:
https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/
点击紫色按钮就可以下载。

或者使用这个地址直接下载:
https://aka.ms/vs/17/release/vs_BuildTools.exe
下载完成后双击打开,在选择工作负荷请选择使用C++的桌面开发”,点击“安装”并等待安装完成。



安装 rustup
从 Rust 官方网站下载 rust-init:https://www.rust-lang.org/tools/install

如果是32位系统,请选择绿色圈的按钮,64位系统请选择红色圈的按钮。或者用下面的链接直接下载:
  • 32-bit: https://static.rust-lang.org/rustup/dist/i686-pc-windows-msvc/rustup-init.exe
  • 64-bit: https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe
下载完成后双击打开,会打开一个命令行窗口:

有3个安装选项,直接输入1并回车,选择默认配置进行安装。安装过程会从自动下载所需内容:

出现绿色的文字提示表示安装完成:

按回车键完成安装,命令行窗口会关闭。重新打开命令行窗口(或者 Powershell 窗口,或者 Windows Terminal 窗口都可以),分别输入下面两个命令进行检查已安装工具的版本:
rustup -V
cargo -V




Hello world!
基础环境安装成功,我们可以跑个 Hello world!
在命令行窗口运行命令:

cargo new hello_world
cd hello_world
cargo run


可以看看实际运行情况:



倒数第二行的 Hello, world! 就是运行的结果。上述命令具体是这样的:
  • cargo new 创建了一个名为 hello_world 的工程:创建了名为 hello_world 的文件夹,给了一个默认的代码和配置。
  • cd hello_world 切换到刚才创建的工程目录。
  • cargo run 构建和运行程序。

开发嵌入式程序的总体流程,也和这个差不多~
基础环境就这样了,下面介绍嵌入式开发需要的工具:

安装嵌入式开发所需工具
工具链
目前支持的工具链,可以通过 rustup target list 命令查看,这里不再赘述。目前 ARM 相关的有:

Cortex-M0, M0+, and M1 (ARMv6-M architecture): thumbv6m-none-eabi
Cortex-M3 (ARMv7-M architecture): thumbv7m-none-eabi
...


我们使用 rustup target add 命令安装所需的,例如想要支持 Cortex-M4 的 MCU,输入这个命令:

rustup target add thumbv7m-none-eabi


命令执行后会从网络拉取资源,且只有两句提示,请耐心等待:


其他工具
这些工具有:
  • arm-none-eabi-gdb
  • probe-rs
  • cargo-binutils
  • llvm-tools

arm-none-eabi-gdb
arm-none-eabi-gdb 是 ARM GNU 工具链的一部分,请自行安装并把对应的 bin 文件夹加入环境变量 PATH 中,这里就不再详细描述安装过程。


probe-rs
这个有点特殊,需要在 Powershell 里执行:
irm https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.ps1 | iex



如命令所示,这个是直接从 github 上拉取资源的。

如果你执行的命令有困难,可以搜索“Github 文件加速:网站,然后把下面的地址填进去,一般都可以下载的:

https://github.com/probe-rs/probe-rs/releases/download/v0.24.0/probe-rs-tools-x86_64-pc-windows-msvc.zip


把下载到的文件直接解压缩到 cargo 的对应目录,一般是:

C:\Users\<你的用户名>\.cargo\bin
确保这个文件的正确路径:C:\Users\<你的用户名>\.cargo\bin\cargo-embed.exe 。


cargo-binutils
使用命令安装:
cargo install cargo-binutils

这个命令会下载需要的代码,并编译生成全部的可执行程序。下载和编译都需要花一些时间,最后的提示类似下图:



llvm-tools
使用这个命令:
rustup component add llvm-tools llvm-tools-preview


类似上面的 rustup target add ,这个命令也是两句提示,中间过程没有其他信息,需要耐心等待~


其他 Debug 相关工具
如果需要调试,还需要相关的工具,如:
  • Qemu-system-arm
  • OpenOCD

这些就不一一介绍了~

IDE 相关内容
IDE 的话,VSCode就非常不错,请配合以下插件使用:
  • rust-analyzer
  • Debugger for probe-rs

后一个也就是配合 probe-rs 使用的,具体安装方法也不再详述。


Rust 嵌入式开发初探
创建 Rust 嵌入式项目,其实蛮简单的,在某个合适的目录下执行以下命令创建工程并用 vs code 打开文件夹:
cargo new blink
cd blink
code .




前面讲过,cargo new 创建的项目就是打印 Hello, world!。我们现在基于这个模板,通过五个步骤修改为合适单片机的项目。

Step.1 创建 Embed.toml 文件:
[default.general]
chip = "STM32F411RE"


看内容大概猜测到了,这个项目使用的单片机是 STM32F411RE。

Step.2 创建 memory.x 文件:
/* Linker script for the STM32F411RE */
MEMORY
{
  FLASH : ORIGIN = 0x08000000, LENGTH = 512K
  RAM : ORIGIN = 0x20000000, LENGTH = 128K
}

这个文件的内容看起来也很熟悉,对了,就是 LD 文件指明 Flash/ RAM 地址和长度。这个内容是足够我们将要完成的项目。


Step.3 创建 .cargo 目录,并创建 .cargo\config.toml 文件:
[build]
target = "thumbv7m-none-eabi"

[target.thumbv7m-none-eabi]
rustflags = ["-C", "link-arg=-Tlink.x"]


嗯,从内容也大致猜到作用了,我们项目的目标平台是 thumbv7em-none-eabi,也定义了链接参数。我们暂时也不用具体的参数写法。


Step.4 修改 Cargo.toml:
<div data-page-id="YJxjdWt94owtVqxa0srcKEBWned" data-lark-html-role="root" data-docx-has-block-data="false"><pre class="ace-line ace-line old-record-id-WDiSdPTacoRRZVxEzC9cmCaKn8e"><code class="language-TOML" data-lark-language="TOML" data-wrap="false">[package]
name = "blink"
version = "0.1.0"
edition = "2021"

[dependencies]
embedded-hal = "1.0.0"
nb = "1"
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "1.0.0"
stm32f4xx-hal = {version = "0.22.1",features = ["stm32f407"]}</code></pre></div><span data-lark-record-data="{&quot;rootId&quot;:&quot;YJxjdWt94owtVqxa0srcKEBWned&quot;,&quot;text&quot;:{&quot;initialAttributedTexts&quot;:{&quot;text&quot;:{&quot;0&quot;:&quot;[package]\nname = \&quot;blink\&quot;\nversion = \&quot;0.1.0\&quot;\nedition = \&quot;2021\&quot;\n\n[dependencies]\nembedded-hal = \&quot;1.0.0\&quot;\nnb = \&quot;1\&quot;\ncortex-m = \&quot;0.7\&quot;\ncortex-m-rt = \&quot;0.7\&quot;\npanic-halt = \&quot;1.0.0\&quot;\nstm32f4xx-hal = {version = \&quot;0.22.1\&quot;,features = [\&quot;stm32f407\&quot;]}&quot;},&quot;attribs&quot;:{&quot;0&quot;:&quot;*0|b+4m*0+1p&quot;}},&quot;apool&quot;:{&quot;numToAttrib&quot;:{&quot;0&quot;:[&quot;author&quot;,&quot;7434168515399139331&quot;]},&quot;nextNum&quot;:1}},&quot;type&quot;:&quot;text&quot;,&quot;referenceRecordMap&quot;:{},&quot;extra&quot;:{&quot;channel&quot;:&quot;saas&quot;,&quot;pasteRandomId&quot;:&quot;4cba5a68-0cb5-44f4-aee9-147b74174055&quot;,&quot;mention_page_title&quot;:{},&quot;external_mention_url&quot;:{}},&quot;isKeepQuoteContainer&quot;:false,&quot;isFromCode&quot;:true,&quot;selection&quot;:[{&quot;id&quot;:223,&quot;type&quot;:&quot;text&quot;,&quot;selection&quot;:{&quot;start&quot;:0,&quot;end&quot;:227},&quot;recordId&quot;:&quot;WDiSdPTacoRRZVxEzC9cmCaKn8e&quot;}],&quot;payloadMap&quot;:{},&quot;isCut&quot;:false}" data-lark-record-format="docx/text" class="lark-record-clipboard"></span>


相对于工程创建时的内容,是增加了 7 ~ 12 行。也就是定义了项目的依赖~

Step.5 最后一步,修改代码 src\main.rs:
//! Blinks an LED

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_halt as _;

use stm32f4xx_hal as hal;

use crate::hal::{pac, prelude::*};
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
    let p = pac::Peripherals::take().unwrap();
    let gpioa = p.GPIOA.split();
    let mut led = gpioa.pa5.into_push_pull_output();
   

至此,工程已经能编译出 STM32F411RE MCU 下的固件,功能是让 PA5 这个 IO 口定时翻转~可以用 qemu 进行测试:
qemu-system-gnuarmeclipse.exe --board NUCLEO-F411RE --image D:\rust\blink\target\thumbv7m-none-eabi\debug\blink 

哦吼~ LED 灯闪起来了~
我不会在文章中贴视频,请移步bilibili:
【Rust Embedded 运行在 qemu】 https://www.bilibili.com/video/BV1ZMU7Y3E19/

借尸还魂编写 APM32 应用
惊悚的环节来了~~~

这个坛子里的大家都应该知道 APM32 系列 MCU 对 STM32 MCU 的兼容性,所以~我们也用 APM32F411VC TinyBoard 进行了测试,只需3步:

Step.1 当然是需要修改 APP 代码:

修改 main.rs 中关于 LED 的管脚,我们使用 APM32F411VC TinyBoard 上的 LED2,也就是 PE6:
//! Blinks an LED

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_halt as _;

use stm32f4xx_hal as hal;

use crate::hal::{pac, prelude::*};
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
    let p = pac::Peripherals::take().unwrap();

    // let gpioa = p.GPIOA.split();
    // let mut led = gpioa.pa5.into_push_pull_output();
    // APM32F411VC TinyBoard: PE6 --> LED2
    let gpioe = p.GPIOE.split();
    let mut led = gpioe.pe6.into_push_pull_output();

    loop {
        for _ in 0..1_000_000 {


Step.2 生成烧录固件并烧录
编译无误后,通过下面的命令生成 Hex 文件:
cargo-objcopy --bin blink --release -- -O ihex target\thumbv7m-none-eabi\release\blink.hex

Step.3 烧录
最后就可以把开发板连接到 PC 上,用你熟悉的工具烧录,我这里用了 PyOCD:
pyocd load -t apm32f411ve target\thumbv7m-none-eabi\release\blink.hex

激动人心的结果:
众所周知,视频是不可以p的

所以,请移步 bilibili 观看视频:【Rust 运行在 APM32F411 Tiny Board】 https://www.bilibili.com/video/BV1cwU7YjEe4/

不是结论的结论
Rust 从最开始的个人项目,逐渐变成已经被工业界接纳的一个编程语言,并以极快的速度扩展着。从 Linux 内核到驱动开发都得到展现。嵌入式领域,特别的 MCU,也得到 Rust 官方的直接支持,相信各种生态工具会慢慢得到支持从而发展。目前国产 MCU 中,GD  的 MCU 是得到了社区的支持,多个型号的 MCU 都匹配了驱动,希望极海和更对的国产半导体厂商也积极争取上游和社区的支持,完善 Rust 的开发工具及生态~~~

------

【相关连接】
Rust 官方:https://www.rust-lang.org/
Rust 官方 Embedded:https://www.rust-lang.org/what/embedded
B站 软件工艺师 的《Rust 编程语言教程》:https://www.bilibili.com/video/BV1m1sreSEoh/
B站 爆米花胡了 的 《Rust嵌入式开发入门》:https://www.bilibili.com/video/BV16u411d7Fv/

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:感恩的心对人。

17

主题

97

帖子

4

粉丝