Skip to content

Commit 644e2bf

Browse files
authored
Merge pull request #314 from Tencent/tos_evb_g0
doc: improve documentation of examples/tos_meets_rust
2 parents 06291f5 + e69a572 commit 644e2bf

File tree

13 files changed

+754
-724
lines changed

13 files changed

+754
-724
lines changed

examples/tos_meets_rust/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ __pycache__
2929
xcuserdata
3030
user_config.h
3131
.ccls-cache
32+
tmp

examples/tos_meets_rust/README.md

Lines changed: 72 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,4 @@
1-
# TencentOS Tiny meets Rust
2-
3-
## 编译运行
4-
5-
编译前完成如下几步
6-
7-
1. 配置信息
8-
9-
`TOS_CONFIG/_user_config.h` 复制一份为 `TOS_CONFIG/user_config.h`,
10-
写入设备信息和 WiFI 信息.
11-
12-
2. 环境变量
13-
14-
新建系统环境变量 TOS_SRC_ROOT, 其值为 TencentOS Tiny 源码的绝对路径.
15-
16-
3. STLINK 连接板子和电脑
17-
18-
进入本项目根目录, 执行如下命令刷入系统
19-
20-
bash build.sh
1+
# TencentOS Tiny meets Rust (甲醛检测器)
212

223
## 目录介绍
234

@@ -42,235 +23,113 @@
4223
+-- README.md: 项目概览文档
4324
+-- tosglue.c: Rust 和 TencentOS 的胶水文件
4425

45-
板子启动后会自动执行 BSP/Src/main.c 中的 main 函数,
46-
在 main 函数中会调用用户定义的如下函数
26+
板子启动后会自动执行 BSP/Src/main.c 中的 main 函数, 在 main 函数中会调用用户定义的如下函数
4727

4828
void application_entry_rust();
4929

5030
这个函数原来是 `application_entry`, 集成 Rust 后修改为 `application_entry_rust` 了.
5131

5232
除了入口函数, 需要有底层的中断服务实现, 位于 `BSP/Src/stm32g0xx_it.c` 中.
5333

54-
## Rust 集成
55-
56-
目前十分粗糙的设计架构如下所示
57-
58-
------------------------------------
59-
Rust Application
60-
------------------------------------
61-
Rust Wrapper
62-
------------------------------------
63-
TencentOS API | Third C Libraries API
64-
------------------------------------
65-
TencentOS
66-
------------------------------------
67-
68-
即 TencentOS 对硬件层进行抽象, 对上层提供系统 API 以及可能的第三方 C 库 API,
69-
然后 Rust 对这些 API 通过胶水文件 (Wrapper) 进行封装, 提供给 Rust 应用程序使用.
70-
71-
这里的一个关键问题是如何将 Rust 应用程序编译后和系统源码链接起来生成一个固件.
72-
73-
其基本的解决思想是首先获取 Rust 应用程序编译后的对象文件(.obj), 其次获取系统源码编译后的对象文件,
74-
最后将所有的对象文件链接起来生成系统固件.
75-
76-
具体实践过程中遇到的细节, 会在下面提到.
77-
78-
- 安装工具链
79-
80-
这里默认你已经安装了 rust 工具链, 如果你的 rustc 版本低于 1.47.0 则切换到 nightly 版本,
81-
切换命令如下
82-
83-
rustup default nightly
84-
85-
如果版本大于等于 1.47.0, 则不用切换.
86-
87-
接着安装支持 tos_evb_g0 板子的工具链
88-
89-
rustup target add thumbv6m-none-eabi
90-
sudo apt-get install -y gcc-arm-none-eabi
91-
92-
其他可选工具
93-
94-
sudo apt-get install gdb-arm-none-eabi
95-
sudo apt-get install OpenOCD
96-
97-
- 设置 Rust 插桩文件
98-
99-
`目录介绍` 中的 libs 目录中的文件即为插桩文件, 其结构如下
100-
101-
+-- libs/
102-
+-- rustapp/
103-
+-- stub.c
104-
+-- rustcore/
105-
+-- stub.c
106-
107-
stub.c 中的内容并不重要, 插桩的意思就是占个坑, 它们的真实意图是用来生成两个库文件
108-
librustcore.a 和 librustapp.a 文件, 因此需要在 CMakeLists.txt 中添加如下两行
109-
110-
add_library(rustcore STATIC ${ROOTDIR}/libs/rustcore/stub.c)
111-
add_library(rustapp STATIC ${ROOTDIR}/libs/rustapp/stub.c)
112-
113-
librustapp.a 将会被真实的 rust 应用程序所替代, 那 librustcore.a 是干什么的?
114-
所有的 rust 程序都依赖于 Rust 的核心库即 rust core, 因此这个是必须提供,
115-
Rust Core 的介绍参见 [The Rust Core Library](https://doc.rust-lang.org/core/).
116-
117-
rust core 库和 rust 应用程序库的生成将会在接下来节介绍.
118-
119-
- rust core 库的生成
120-
121-
当添加完 rust 编译嵌入式的工具链时, rust core 库会自动被放到系统中固定的目录下,
122-
其路径的获取方式如下
123-
124-
RUST_THUMBV6M_SYSROOT=$(rustc --print sysroot --target thumbv6m-none-eabi)
125-
RUST_LIBCORE_SRC=$(ls -1 $RUST_THUMBV6M_SYSROOT/lib/rustlib/thumbv6m-none-eabi/lib/libcore-*.rlib)
126-
127-
rlib 文件实际上就是静态库文件, 可以用如下命令查看 rlib 内容
128-
129-
arm-none-eabi-ar t $RUST_LIBCORE_SRC
130-
131-
core-1ba29f225cca71e5.core.1ml6ett9-cgu.0.rcgu.o
132-
lib.rmeta
133-
134-
因此我们直接将该文件复制为 librustcore.a 即可.
135-
136-
- rust app 库的生成
137-
138-
新建的 rust 应用程序目录为 app, Rust 提供了 cargo 工具, 可以快速创建项目,
139-
进入项目根目录执行如下命令即可生成 app 目录(也可以使用 --lib 直接生成库文件目录结构)
140-
141-
cargo new app
142-
143-
- 进入 app/src 目录, 删除 main.rs, 然后新建 lib.rs
144-
- 配置 app/Cargo.toml
145-
146-
配置其内容如下所示
147-
148-
[package]
149-
name = "app"
150-
version = "0.1.0"
151-
authors = ["ikey4u <[email protected]>"]
152-
edition = "2018"
153-
154-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
155-
156-
[dependencies]
157-
cty = "0.2.0" # String utilities from cty library: https://crates.io/crates/cty
158-
cstr_core = "0.1.2" # String utilities from cstr_core library: https://crates.io/crates/cstr_core
159-
cortex-m = "0.5.8" # Arm Cortex-M utilities: https://crates.io/crates/cortex-m
160-
161-
[lib]
162-
name = "tosrs"
163-
test = false
164-
bench = false
165-
166-
# Options for `cargo build`
167-
[profile.dev]
168-
panic = "abort" # Disable stack unwinding on panic
169-
170-
# Options for `cargo build --release`
171-
[profile.release]
172-
panic = "abort" # Disable stack unwinding on panic
173-
codegen-units = 1 # Better optimizations
174-
debug = true # Symbols are nice and they don't increase the size on Flash lto = true # Better optimizations
34+
## 编译运行
17535

36+
- 配置腾讯云
37+
38+
到腾讯云物联网开发平台 https://cloud.tencent.com/product/iotexplorer 注册一个新产品.
39+
40+
新建产品后导入模板数据如下
41+
42+
{
43+
"version": "1.0",
44+
"profile": {
45+
"ProductId": "BDDSF87WEA",
46+
"CategoryId": "1"
47+
},
48+
"properties": [
49+
{
50+
"id": "ch20_ppm_value",
51+
"name": "甲醛浓度值",
52+
"desc": "",
53+
"mode": "r",
54+
"define": {
55+
"type": "float",
56+
"min": "0",
57+
"max": "2",
58+
"start": "0",
59+
"step": "0.001",
60+
"unit": "ppm(mg/m3)"
61+
},
62+
"required": false
63+
}
64+
],
65+
"events": [],
66+
"actions": []
67+
}
17668

177-
- 配置 app/.cargo/config 文件
69+
然后新建设备, 新建之后能够得到三个信息: 设备名称, 设备密钥, 产品 ID,
70+
这三个信息需要写入到 TencentOS 固件中.
17871

179-
配置其内容如下所示
72+
配置完成后, 将甲醛传感器与底板连接, 根据板子和底板的 5v 和 GND 接口对应关系, 将底板连接到板子上,
73+
然后根据传感器的 Rx 和 Tx 口将传感器和板子底板连接起来.
18074

181-
[target.thumbv6m-none-eabi]
182-
183-
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
184-
185-
rustflags = [
186-
# LLD (shipped with the Rust toolchain) is used as the default linker
187-
"-C", "link-arg=-Tlink.x",
188-
]
189-
190-
[build]
191-
target = "thumbv6m-none-eabi"
75+
- 下载源码
19276

193-
注意 tos_evb_g0 对应的 target 是 thumbv6m-none-eabi.
77+
下载 TencentOS 源码
19478

195-
项目中最终的目录如下所示
79+
git clone https://github.com/Tencent/TencentOS-tiny.git
19680

197-
+-- app/
198-
+-- src/
199-
+ bridge.rs
200-
+ lib.rs
201-
+-- Cargo.toml
202-
+-- .cargo/
203-
+-- config
204-
205-
配置完成后, 便可在 app 目录执行如下命令编译
81+
进入 `examples/tos_meets_rust` 目录, 将 `TOS_CONFIG/_user_config.h` 复制一份为 `TOS_CONFIG/user_config.h`,
82+
写入设备信息和 WiFI 信息.
20683

207-
cargo build
84+
新建系统环境变量 TOS_SRC_ROOT, 其值为 TencentOS Tiny 源码的绝对路径.
20885

209-
编译的中间产物位于 `app/target/thumbv6m-none-eabi/debug/deps` 中,
210-
这里面是一系列的 .rlib 文件(静态库文件), 这些库文件包含了应用程序代码及其依赖的库代码.
86+
- 基础依赖安装
21187

212-
我们将这些库包含的所有对象文件提取出来重新打包成一个新的库文件, 即为 librustapp.a 文件.
88+
- ST-LINK 驱动安装, 参考 [stlink](./docs/stlink.md)
21389

214-
其中 bridge.rs 声明了胶水文件中的 API 接口, 比如
90+
- CH34X 驱动安装, 参考 [CH34X](./docs/ch34x.md)
21591

216-
use cty::*;
92+
- kermit 串口工具安装, 参考 [kermit](./docs/kermit.md)
21793

218-
/// These glue functions are from tosglue.c
219-
extern {
220-
pub fn rust_print(msg: *const u8);
221-
}
94+
- 工具链安装
22295

223-
lib.rs 则是应用程序代码, 示例如下
96+
编译需要的 arm-none-eabi 工具连, eabi 的含义是 Embedded Application Binary Interface,
97+
不同发行版安装方式不一样
22498

225-
#![no_std]
99+
- ubuntu
226100

227-
extern crate cortex_m;
101+
sudo apt-get install -y gcc-arm-none-eabi
228102

229-
mod bridge;
103+
- archlinux:
230104

231-
use crate::bridge::*;
232-
use cty::*;
105+
sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib
233106

234-
#[no_mangle]
235-
pub extern "C" fn application_entry_rust() -> c_void {
236-
unsafe {
237-
rust_mqtt_daemon();
238-
}
107+
这里默认你已经安装了 rust 工具链, 如果你的 rustc 版本低于 1.47.0 则切换到 nightly 版本,
108+
切换命令如下
239109

240-
loop {
241-
unsafe {
242-
rust_print(b"[+] Welcome to the RUST-WORLD in TencentOS :)".as_ptr());
243-
}
244-
}
245-
}
110+
rustup default nightly
246111

247-
- 胶水文件
112+
如果版本大于等于 1.47.0, 则不用切换, 接着安装支持板子的 rust 工具链
248113

249-
Rust 调用系统 API 或者第三方 C 库的 API 通过胶水文件 tosglue.c 实现,
250-
这里的做法是将 tosglue.c 编译为一个库文件, 但是不参与链接, 而是提取其对象文件,
251-
合并到 librustapp.a 中, 在 CMakeLists.txt 中添加如下行
114+
rustup target add thumbv6m-none-eabi
252115

253-
add_library(tosglue STATIC ${ROOTDIR}/tosglue.c)
116+
- 刷入 WiFi 固件, 参见 [esp](./docs/flash-esp.md)
254117

255-
tosglue.c 中的一个 API 示例如下
118+
- 刷入系统
256119

257-
void rust_print(const char *msg) {
258-
printf("%s\r\n", msg);
259-
}
120+
连接 STLINK 后, 执行如下命令
260121

261-
- 一键编译生成固件
122+
bash build.sh
262123

263-
在编译之前还需要注意修改 CMakeLists.txt, 保证固件链接了 librustcore.a 和 librustapp.a
124+
刷入完成后, 登录 kermit, 然后按下板子上的 reset 按键, 程序就运行了, 串口会输出 WIFI CONNECTED 之类的,
125+
腾讯云上显示设备上线.
264126

265-
target_link_libraries(${PROJECT_NAME} ${LIBS} c nosys rustcore rustapp)
127+
## Rust 集成
266128

267-
这样设置之后, 我们再替换完 librustcore.a 和 librustapp.a 之后,
268-
就可以强制重新生成新的固件.
129+
Rust 集成原理参见 [rust](./docs/rust.md)
269130

270-
最终的编译脚本参见 build.sh.
131+
## 其他
271132

272-
## 参考
133+
1. 如果你在 mac 平台上开发, 你可以参考文档 [setup.mac.md](./docs/setup.mac.md) 来搭建开发环境.
273134

274-
- [Hosting Embedded Rust apps on Apache Mynewt with STM32 Blue Pill](https://medium.com/@ly.lee/hosting-embedded-rust-apps-on-apache-mynewt-with-stm32-blue-pill-c86b119fe5f)
275-
- [STM32L0 Rust Part 1 - Getting Started](https://craigjb.com/2019/12/31/stm32l0-rust/)
276-
- [FreeRTOS meets Rust](http://www.hashmismatch.net/freertos-meets-rust/)
135+
2. 有一份简短的关于本 demo 的介绍 PPT, 位于[这里](./docs/presentation.pdf), 有需要可以打开查看.

0 commit comments

Comments
 (0)