linux下用rust优雅地开发stm32
文章目录
用rust开发嵌入式的特点
优势:
- 社区驱动
- 高性能高效率
- 跨平台
劣势:
- rust难学
- 文档全英文
- 国内用rust开发嵌入式的人少,问题需要自己解决
硬件需求
- 最起码需要有st-linkv2+的下载器
- 一块stm32f1xx的最小系统开发板
搭建开发stm32开发环境
linux下(我用的Deepin 20.7):
rust工具链
下载rust 上rust语言官网,我就不多说了
添加编译目标
$rustup target add thumbv7m-none-eabi
openocd
类似一个烧写代码的开源软件
$sudo apt install openocd
arm gdb
代码调试器
Ubuntu 18.04/Debian stretch 或更高的版本.
$sudo apt install gdb-multiarch
其他版本的linux,下载gdb-arm-none-eabi
cargo-binutils
检查工具集,包括objdump, nm 和size
$cargo install cargo-binutils
$rustup component add llvm-tools-preview
基本流程
创建一个工程
$mkdir stm32f103
$cd stm32f103
$cargo init
工程中有 build.rs ,Cargo.toml,src ,没有其他的文件或者文件夹,也没有隐藏文件。
之后我们要添加一些东西在这个项目中。
在Cargo.toml中添加依赖
[dependencies]
embedded-hal = "0.2.3"
nb = "0.1.2"
cortex-m = "0.6.2"
cortex-m-rt = "0.7.1"
panic-halt = "0.2.0"
cortex-m-semihosting = "0.5.0"
[dependencies.stm32f1xx-hal]
version = "0.9.0"
features = ["stm32f100", "rt"]
添加memory.x文件在工程中
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}
查找芯片手册,将flash和ram映射的地址开头和长度添加到上面,如果你和我一样使用的是stm32f103的芯片可以不用改。
创建cargo配置.cargo/config.toml
[target.thumbv7m-none-eabi]
rustflags = [
# 如果你的闪存或ram地址没有与memory.x中的0x10000对齐,就需要这样做
# 见 https://github.com/rust-embedded/cortex-m-quickstart/pull/95
#"-C", "link-arg=--nmagic",
# LLD(随Rust工具链一起提供)被用作默认链接器
"-C", "link-arg=-Tlink.x",
# 如果你遇到LLD的问题,通过注释到GNU链接器这行
# "-C", "linker=arm-none-eabi-ld",
#如果你需要链接到C工具链提供的预编译C库
#使用GCC作为链接器,注释掉上面的两行,然后
#取消下面三行的注释
# "-C", "linker=arm-none-eabi-gcc",
# "-C", "link-arg=-Wl,-Tlink.x",
# "-C", "link-arg=-nostartfiles",
]
[build]
target = "thumbv7m-none-eabi"
修改源代码 main.rs
#![deny(unsafe_code)] #![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use stm32f1xx_hal::{pac, prelude::*};
#[entry]
fn main() -> ! {
let p = pac::Peripherals::take().unwrap();
let mut gpioc = p.GPIOC.split();
gpioc.pc13.into_push_pull_output(&mut gpioc.crh).set_low();
loop {}
}
这是文档给出点亮led灯的代码。
硬件中,将led灯正极连到vcc(3.3v)负极连接到pc13这个引脚上。
构建代码
$cargo build
产生的可执行代码在当前目录下target/thumbv7m-none-eabi/debug/stm32f103
注意这只是开发版本,如果你想要更小更快的二进制文件,配置你的profile.release
烧写代码
1.打开openocd
$sudo openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg
stlink-vX X是你下载器的版本号
出现
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
就是成功了
2.打开gdb
打开一个新的终端并进入项目中
$gdb-multiarch -q target/thumbv7m-none-eabi/debug/stm32f103
进入gdb的交互模式后输入
$(gdb) target remote:3333
连接openocd
用gdb烧录
$(gdb) load
烧写的过程就完成了
简化
是不是觉得每次写openocd命令和gdb的命令过于繁琐,我们可以用一些方法简化它。
1.不用写sudo(避免每次用root执行openocd)
创造文件/etc/udev/rules.d/70-st-link.rules
内容如下:
# STM32F3DISCOVERY rev A/B - ST-LINK/V2
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", TAG+="uaccess"
# STM32F3DISCOVERY rev C+ - ST-LINK/V2-1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", TAG+="uaccess"
然后用以下命令重新加载所有udev规则:
$sudo udevadm control --reload-rules
将开发板连接在电脑上
$lsusb
出现
(..)
Bus 001 Device 018: ID 0483:374b STMicroelectronics ST-LINK/V2.1
(..)
即可 ,2.1或者2都是你的下载器决定
这样你就可以不用写sudo
$openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg
2.简化gdb
$gdb-multiarch -q target/thumbv7m-none-eabi/debug/stm32f103
每次修改代码烧录调试,要打上面的代码和gdb命令,实在是太累了!
这就要说rust工具链的优点了。
打开.cargo/config
[target.thumbv7m-none-eabi]
rustflags = [
"-C", "link-arg=-Tlink.x",
]
runner = "gdb-multiarch -q target/thumbv7m-none-eabi/debug/stm32f103 -x gdb.cfg" #新添加一行runner
[build]
target = "thumbv7m-none-eabi"
其中gdb命令脚本
gdb.cfg
target remote :3333
monitor arm semihosting enable
# # send captured ITM to the file itm.fifo
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
# # 8000000 must match the core clock frequency
# monitor tpiu config internal itm.fifo uart off 8000000
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
# # 2000000 is the frequency of the SWO pin
# monitor tpiu config external uart off 8000000 2000000
# # enable ITM port 0
# monitor itm port 0 on
load
quit
以后运行可以直接执行
$cargo run
将二进制文件发送到openocd再烧录到开发板中
检查
主要检查的就是rust产生二进制体积大小是否超过你的mcu flash的容量
$cargo size --bin stm32f103 --release -- -A
查看release版本的二进制大小
app :
section size addr
.vector_table 1024 0x0
.text 92 0x400
.rodata 0 0x45c
.data 0 0x20000000
.bss 0 0x20000000
.debug_str 2958 0x0
.debug_loc 19 0x0
.debug_abbrev 567 0x0
.debug_info 4929 0x0
.debug_ranges 40 0x0
.debug_macinfo 1 0x0
.debug_pubnames 2035 0x0
.debug_pubtypes 1892 0x0
.ARM.attributes 46 0x0
.debug_frame 100 0x0
.debug_line 867 0x0
Total 14570
优化
在Cargo.toml中,新加官方推荐的release版本优化参数
[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
更多资料
-
关于stm32的更多例子https://github.com/stm32-rs/stm32f1xx-hal/tree/master/examples,实打实的复制粘贴改改就行
-
官方的第二本嵌入式书embedded book 我有翻译https://blog.csdn.net/qq_37813963/article/details/126209924?spm=1001.2014.3001.5502,其中有关于调试信息,中断异常等更具体的内容
-
官方第三本Embedonomicon 我看了大概是一些优化
-
其他的书都是给芯片厂商看的,有兴趣有能力的可以去学一下,给社区贡献hal库
-
更多的嵌入式系统开发库https://github.com/rust-embedded/awesome-embedded-rust#driver-crates