This commit is contained in:
Arthur
2021-08-03 15:26:28 +08:00
14 changed files with 763 additions and 731 deletions

View File

@@ -29,3 +29,4 @@ __pycache__
xcuserdata xcuserdata
user_config.h user_config.h
.ccls-cache .ccls-cache
tmp

View File

@@ -1,23 +1,4 @@
# TencentOS Tiny meets Rust # TencentOS Tiny meets Rust (甲醛检测器)
## 编译运行
编译前完成如下几步
1. 配置信息
`TOS_CONFIG/_user_config.h` 复制一份为 `TOS_CONFIG/user_config.h`,
写入设备信息和 WiFI 信息.
2. 环境变量
新建系统环境变量 TOS_SRC_ROOT, 其值为 TencentOS Tiny 源码的绝对路径.
3. STLINK 连接板子和电脑
进入本项目根目录, 执行如下命令刷入系统
bash build.sh
## 目录介绍 ## 目录介绍
@@ -42,8 +23,7 @@
+-- README.md: 项目概览文档 +-- README.md: 项目概览文档
+-- tosglue.c: Rust 和 TencentOS 的胶水文件 +-- tosglue.c: Rust 和 TencentOS 的胶水文件
板子启动后会自动执行 BSP/Src/main.c 中的 main 函数, 板子启动后会自动执行 BSP/Src/main.c 中的 main 函数, 在 main 函数中会调用用户定义的如下函数
在 main 函数中会调用用户定义的如下函数
void application_entry_rust(); void application_entry_rust();
@@ -51,226 +31,105 @@
除了入口函数, 需要有底层的中断服务实现, 位于 `BSP/Src/stm32g0xx_it.c` 中. 除了入口函数, 需要有底层的中断服务实现, 位于 `BSP/Src/stm32g0xx_it.c` 中.
## Rust 集成 ## 编译运行
目前十分粗糙的设计架构如下所示 - 配置腾讯云
------------------------------------ 到腾讯云物联网开发平台 https://cloud.tencent.com/product/iotexplorer 注册一个新产品.
Rust Application
------------------------------------
Rust Wrapper
------------------------------------
TencentOS API | Third C Libraries API
------------------------------------
TencentOS
------------------------------------
即 TencentOS 对硬件层进行抽象, 对上层提供系统 API 以及可能的第三方 C 库 API, 新建产品后导入模板数据如下
然后 Rust 对这些 API 通过胶水文件 (Wrapper) 进行封装, 提供给 Rust 应用程序使用.
这里的一个关键问题是如何将 Rust 应用程序编译后和系统源码链接起来生成一个固件. {
"version": "1.0",
"profile": {
"ProductId": "BDDSF87WEA",
"CategoryId": "1"
},
"properties": [
{
"id": "ch20_ppm_value",
"name": "甲醛浓度值",
"desc": "",
"mode": "r",
"define": {
"type": "float",
"min": "0",
"max": "2",
"start": "0",
"step": "0.001",
"unit": "ppm(mg/m3)"
},
"required": false
}
],
"events": [],
"actions": []
}
其基本的解决思想是首先获取 Rust 应用程序编译后的对象文件(.obj), 其次获取系统源码编译后的对象文件, 然后新建设备, 新建之后能够得到三个信息: 设备名称, 设备密钥, 产品 ID,
最后将所有的对象文件链接起来生成系统固件. 这三个信息需要写入到 TencentOS 固件.
具体实践过程中遇到的细节, 会在下面提到. 配置完成后, 将甲醛传感器与底板连接, 根据板子和底板的 5v 和 GND 接口对应关系, 将底板连接到板子上,
然后根据传感器的 Rx 和 Tx 口将传感器和板子底板连接起来.
- 安装工具链 - 下载源码
下载 TencentOS 源码
git clone https://github.com/Tencent/TencentOS-tiny.git
进入 `examples/tos_meets_rust` 目录, 将 `TOS_CONFIG/_user_config.h` 复制一份为 `TOS_CONFIG/user_config.h`,
写入设备信息和 WiFI 信息.
新建系统环境变量 TOS_SRC_ROOT, 其值为 TencentOS Tiny 源码的绝对路径.
- 基础依赖安装
- ST-LINK 驱动安装, 参考 [stlink](./docs/stlink.md)
- CH34X 驱动安装, 参考 [CH34X](./docs/ch34x.md)
- kermit 串口工具安装, 参考 [kermit](./docs/kermit.md)
- 工具链安装
编译需要的 arm-none-eabi 工具连, eabi 的含义是 Embedded Application Binary Interface,
不同发行版安装方式不一样
- ubuntu
sudo apt-get install -y gcc-arm-none-eabi
- archlinux:
sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib
这里默认你已经安装了 rust 工具链, 如果你的 rustc 版本低于 1.47.0 则切换到 nightly 版本, 这里默认你已经安装了 rust 工具链, 如果你的 rustc 版本低于 1.47.0 则切换到 nightly 版本,
切换命令如下 切换命令如下
rustup default nightly rustup default nightly
如果版本大于等于 1.47.0, 则不用切换. 如果版本大于等于 1.47.0, 则不用切换, 接着安装支持板子的 rust 工具链
接着安装支持 tos_evb_g0 板子的工具链
rustup target add thumbv6m-none-eabi rustup target add thumbv6m-none-eabi
sudo apt-get install -y gcc-arm-none-eabi
其他可选工具 - 刷入 WiFi 固件, 参见 [esp](./docs/flash-esp.md)
sudo apt-get install gdb-arm-none-eabi - 刷入系统
sudo apt-get install OpenOCD
- 设置 Rust 插桩文件 连接 STLINK 后, 执行如下命令
`目录介绍` 中的 libs 目录中的文件即为插桩文件, 其结构如下 bash build.sh
+-- libs/ 刷入完成后, 登录 kermit, 然后按下板子上的 reset 按键, 程序就运行了, 串口会输出 WIFI CONNECTED 之类的,
+-- rustapp/ 腾讯云上显示设备上线.
+-- stub.c
+-- rustcore/
+-- stub.c
stub.c 中的内容并不重要, 插桩的意思就是占个坑, 它们的真实意图是用来生成两个库文件 ## Rust 集成
librustcore.a 和 librustapp.a 文件, 因此需要在 CMakeLists.txt 中添加如下两行
add_library(rustcore STATIC ${ROOTDIR}/libs/rustcore/stub.c) Rust 集成原理参见 [rust](./docs/rust.md)
add_library(rustapp STATIC ${ROOTDIR}/libs/rustapp/stub.c)
librustapp.a 将会被真实的 rust 应用程序所替代, 那 librustcore.a 是干什么的? ## 其他
所有的 rust 程序都依赖于 Rust 的核心库即 rust core, 因此这个是必须提供,
Rust Core 的介绍参见 [The Rust Core Library](https://doc.rust-lang.org/core/).
rust core 库和 rust 应用程序库的生成将会在接下来节介绍. 1. 如果你在 mac 平台上开发, 你可以参考文档 [setup.mac.md](./docs/setup.mac.md) 来搭建开发环境.
- rust core 库的生成 2. 有一份简短的关于本 demo 的介绍 PPT, 位于[这里](./docs/presentation.pdf), 有需要可以打开查看.
当添加完 rust 编译嵌入式的工具链时, rust core 库会自动被放到系统中固定的目录下,
其路径的获取方式如下
RUST_THUMBV6M_SYSROOT=$(rustc --print sysroot --target thumbv6m-none-eabi)
RUST_LIBCORE_SRC=$(ls -1 $RUST_THUMBV6M_SYSROOT/lib/rustlib/thumbv6m-none-eabi/lib/libcore-*.rlib)
rlib 文件实际上就是静态库文件, 可以用如下命令查看 rlib 内容
arm-none-eabi-ar t $RUST_LIBCORE_SRC
core-1ba29f225cca71e5.core.1ml6ett9-cgu.0.rcgu.o
lib.rmeta
因此我们直接将该文件复制为 librustcore.a 即可.
- rust app 库的生成
新建的 rust 应用程序目录为 app, Rust 提供了 cargo 工具, 可以快速创建项目,
进入项目根目录执行如下命令即可生成 app 目录(也可以使用 --lib 直接生成库文件目录结构)
cargo new app
- 进入 app/src 目录, 删除 main.rs, 然后新建 lib.rs
- 配置 app/Cargo.toml
配置其内容如下所示
[package]
name = "app"
version = "0.1.0"
authors = ["ikey4u <pwnkeeper@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cty = "0.2.0" # String utilities from cty library: https://crates.io/crates/cty
cstr_core = "0.1.2" # String utilities from cstr_core library: https://crates.io/crates/cstr_core
cortex-m = "0.5.8" # Arm Cortex-M utilities: https://crates.io/crates/cortex-m
[lib]
name = "tosrs"
test = false
bench = false
# Options for `cargo build`
[profile.dev]
panic = "abort" # Disable stack unwinding on panic
# Options for `cargo build --release`
[profile.release]
panic = "abort" # Disable stack unwinding on panic
codegen-units = 1 # Better optimizations
debug = true # Symbols are nice and they don't increase the size on Flash lto = true # Better optimizations
- 配置 app/.cargo/config 文件
配置其内容如下所示
[target.thumbv6m-none-eabi]
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = [
# LLD (shipped with the Rust toolchain) is used as the default linker
"-C", "link-arg=-Tlink.x",
]
[build]
target = "thumbv6m-none-eabi"
注意 tos_evb_g0 对应的 target 是 thumbv6m-none-eabi.
项目中最终的目录如下所示
+-- app/
+-- src/
+ bridge.rs
+ lib.rs
+-- Cargo.toml
+-- .cargo/
+-- config
配置完成后, 便可在 app 目录执行如下命令编译
cargo build
编译的中间产物位于 `app/target/thumbv6m-none-eabi/debug/deps` 中,
这里面是一系列的 .rlib 文件(静态库文件), 这些库文件包含了应用程序代码及其依赖的库代码.
我们将这些库包含的所有对象文件提取出来重新打包成一个新的库文件, 即为 librustapp.a 文件.
其中 bridge.rs 声明了胶水文件中的 API 接口, 比如
use cty::*;
/// These glue functions are from tosglue.c
extern {
pub fn rust_print(msg: *const u8);
}
lib.rs 则是应用程序代码, 示例如下
#![no_std]
extern crate cortex_m;
mod bridge;
use crate::bridge::*;
use cty::*;
#[no_mangle]
pub extern "C" fn application_entry_rust() -> c_void {
unsafe {
rust_mqtt_daemon();
}
loop {
unsafe {
rust_print(b"[+] Welcome to the RUST-WORLD in TencentOS :)".as_ptr());
}
}
}
- 胶水文件
Rust 调用系统 API 或者第三方 C 库的 API 通过胶水文件 tosglue.c 实现,
这里的做法是将 tosglue.c 编译为一个库文件, 但是不参与链接, 而是提取其对象文件,
合并到 librustapp.a 中, 在 CMakeLists.txt 中添加如下行
add_library(tosglue STATIC ${ROOTDIR}/tosglue.c)
tosglue.c 中的一个 API 示例如下
void rust_print(const char *msg) {
printf("%s\r\n", msg);
}
- 一键编译生成固件
在编译之前还需要注意修改 CMakeLists.txt, 保证固件链接了 librustcore.a 和 librustapp.a
target_link_libraries(${PROJECT_NAME} ${LIBS} c nosys rustcore rustapp)
这样设置之后, 我们再替换完 librustcore.a 和 librustapp.a 之后,
就可以强制重新生成新的固件.
最终的编译脚本参见 build.sh.
## 参考
- [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)
- [STM32L0 Rust Part 1 - Getting Started](https://craigjb.com/2019/12/31/stm32l0-rust/)
- [FreeRTOS meets Rust](http://www.hashmismatch.net/freertos-meets-rust/)

View File

@@ -0,0 +1,100 @@
# CH34x 串口驱动
- 基本原理
在板子上有一个写有 CH340C 的电子元件, 这个就是电子元件的作用就是将 USB 协议转换为串口协议,
要让这个这个电子元件正常工作, 需要安装 CH340 驱动.
在 USB 接口里有 4 根线, 外侧的两根长金手指负责供电, 即电源线, 内侧的两根金手指比较短,
用于数据传输, 即数据线.
当我们在电脑上通过串口向板子传输数据时, 电脑端采用 USB 数据传输协议通过数据线传到板子上,
然后 CH340 驱动解析 USB 数据将其转换为串口数据传输给板子上的其他元器件.
串口除了传输数据的功能之外, 还有调试功能, 板子上程序的输出一般都是被重定向到串口中,
然后打印出数据供调试用.
- 驱动安装
- 使用默认系统驱动
默认情况下, linux 内核已经带了 ch34x 的驱动, 可以使用如下命令搜索
ls -R /lib/modules/$(uname -r) | grep ch34
输出类似如下
ch341.h
ch341.ko.xz
然后挂载 ch341 模块
sudo modprobe ch341
查看是否挂载成功
lsmod | grep ch34
- 手动编译驱动
下载地址位于[这里](http://www.wch.cn/downloads/CH341SER_LINUX_ZIP.html), 下载之后解压, 其内容如下所示
CH341SER_LINUX/
+-- ch34x.c
+-- Makefile
+-- readme.txt
我们需要将 ch34x.c 替换为内核中对应的代码, 可以使用 uname -r 查看内核, 假设内核版本为 5.11,
则下载地址如下
curl -LO https://raw.githubusercontent.com/torvalds/linux/v5.11/drivers/usb/serial/ch341.c
mv ch341.c ch34x.c
然后编译该模块
make clean
make
sudo make load
sudo rmmod ch341
- 使用方法
当驱动 ch34x 加载之后, 使用如下命令监听外设连接情况
sudo dmesg -w
然后将串口插到电脑上, 其输出如下所示
[ 3897.948205] usb 3-1: new full-speed USB device number 5 using xhci_hcd
[ 3898.101841] usb 3-1: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.64
[ 3898.101846] usb 3-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 3898.101848] usb 3-1: Product: USB Serial
[ 3898.108866] ch341 3-1:1.0: ch341-uart converter detected
[ 3898.122905] usb 3-1: ch341-uart converter now attached to ttyUSB0
可以看到串口已经被绑定到 /dev/ttyUSB0 上了.
- 虚拟机映射
查看 ttyUSB0 所属组
ls -l /dev/ttyUSB0
crw-rw---- 1 root uucp 188, 0 Mar 28 17:49 /dev/ttyUSB0
将其添加到该组
sudo usermod -a -G uucp $USER
添加完毕后, 务必重启电脑.
然后打开 virtualbox, 关闭 ubuntu, 打开其设置, 定位到 serial port 项, 选择 Port 1,
Port Number 为 COM1, Port Mode 为 Host Device, Path/Address 为 /dev/ttyUSB0,
如下所示:
![serial](./imgs/serial_port_map.png "serial port map")
启动 ubuntu 虚拟机, ubuntu 虚拟机中的 /dev/ttyS0 就对应于 COM1, 也就是主机的 /dev/ttyUSB0.
# 参考
- https://jjmilburn.github.io/2016/04/04/ttyUSB-to-vagrant-virtualbox/

View File

@@ -0,0 +1,154 @@
# WiFi 模块
由于是通过串口刷 WiFi 固件, 因此需要断开其他的串口连接, 同时也要断开 stlink 的连接.
- 让串口链路连接到 WiFi 电子元件上, 其具体做法为
1. 定位到 `串口切换`
串口切换一共两排, 每排四个 Pin, 示意图如下
* * * *
* * * *
将短路帽(黄色塑料套)按如下连接
* + + *
* - - *
加号的连接到一起, 减号的连接到一起.
2. 定位到 `ESP 固件下载配置`
这个配置一共有 3 个, 依次如下
3v3 IO0 GND
用短路帽把 IO0 和 GND 连接.
3. 定位到 `BOOT 配置`
这个配置一共有 3 个, 依次如下
0 BOOT 1
将短路帽把 0 和 BOOT 连接.
- 安装 esptool 工具
需要用到工具 esptool, 地址为 https://github.com/espressif/esptool, 安装命令如下
pip3 install esptool
更新 zsh/bash 配置文件
export PATH=$HOME/.local/bin:${PATH}
安装完成后刷新系统环境变量, 会得到一个命令 esptool.py, 我们就是通过这个命令将 WiFi 固件刷入到板子中.
以上准备完成后, 测试一下 esp 是否正常工作, 命令如下
sudo -E env "PATH=$PATH" esptool.py --port /dev/ttyUSB0 read_mac
输出类似如下
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 40:f5:20:08:6f:b1
Uploading stub...
Running stub...
Stub running...
MAC: 40:f5:20:08:6f:b1
Hard resetting via RTS pin...
如果连接不上, 考虑如下几种情形
1. reset 板子
如果之前你执行过 esptool.py, 你必须手动按一下板子上的 reset 按键,
如果你不按 reset 继续执行 esptool.py 命令, 那么这个命令会一直挂起, 输出类似于下面这种
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting........_____....
2. 串口被占用
如果提示下面的错误表示你的串口被占用了, 看看你的串口工具是不是连上了.
serial.serialutil.SerialException: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
3. STLINK 和串口同时连上了
把 STLINK 和串口线都拔下来, 只插串口线.
- 刷入固件
确定 esp 正常工作后, 下载固件
git clone https://github.com/tencentyun/qcloud-iot-esp-wifi.git
然后解压固件
cd qcloud-iot-esp-wifi
unzip qcloud-iot-at-esp8266/QCloud_IoT_AT_ESP8266_FW/QCloud_IoT_AT_ESP8266_v2.1.1_20200903.zip
腾讯云 IoT 定制 AT 串口使用 UART0, Tx 为 GPIO1, Rx 为 GPIO3, UART_1_3 的固件
采用的 Tx 和 Rx 和 AT 的一致, 因此我们使用 UART_1_3 固件, 其路径为
QCloud_IoT_AT_ESP8266_v2.1.1_20200903/QCloud_IoT_AT_ESP8266_v2.1.1_20200903_UART_1_3.bin
配置一下串口速度
sudo stty -F /dev/ttyUSB0 ispeed 115200 ospeed 115200 cs8
执行如下命令刷入固件 (虚拟机需要将 --baud 修改为 115200)
sudo -E env "PATH=$PATH" esptool.py --port /dev/ttyUSB0 --chip esp8266 --baud 1500000 --after hard_reset write_flash 0x0 QCloud_IoT_AT_ESP8266_v2.1.1_20200903/QCloud_IoT_AT_ESP8266_v2.1.1_20200903_UART_1_3.bin
成功执行后的输出示例如下
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting...
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 40:f5:20:08:6f:b1
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 1500000
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0040
Compressed 2039808 bytes to 485108...
Wrote 2039808 bytes (485108 compressed) at 0x00000000 in 7.0 seconds (effective 2326.6 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
- 恢复串口连接
1. `串口切换`
连接示意图
1 1 2 2
3 3 4 4
数值相同的连接到一起
2. `ESP 固件下载配置`
连接 3v3 和 IO0
3. `BOOT 配置`
保持不变

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -0,0 +1,38 @@
# 串口工具 - kermit
- 安装
- linux
wget http://www.kermitproject.org/ftp/kermit/test/tar/x.zip
unzip x.zip -d c-kermit && cd c-kermit
make linux
make DESTDIR=$HOME/.usr/kermit BINDIR=$DESTDIR MANDIR=$DESTDIR install
然后导出环境变量
KERMIT=$HOME/.usr/kermit
export PATH=${KERMIT}:${PATH}
- 使用
配置串口
sudo stty -F /dev/ttyUSB0 ispeed 115200 ospeed 115200 cs8
打开 ~/.kermrc, 配置 kermit 启动参数
set line /dev/ttyUSB0
set speed 115200
set carrier-watch off
connect
执行 sudo -E env "PATH=$PATH" kermit 启动串口工具, 出现如下输出表示连接成功
Connecting to /dev/ttyUSB0, speed 115200
Escape character: Ctrl-\ (ASCII 28, FS): enabled
Type the escape character followed by C to get back,
or followed by ? to see other options.
----------------------------------------------------
如果想回到 kermit, 按下 Ctrl-\, 再按下 C 即可, 如果想再连接到串口, 输入 c 即可.

Binary file not shown.

View File

@@ -0,0 +1,195 @@
# Rust 集成
目前十分粗糙的设计架构如下所示
![rust集成架构](./imgs/tos.svg "rust集成架构")
即 TencentOS 对硬件层进行抽象, 对上层提供系统 API 以及可能的第三方 C 库 API,
然后 Rust 对这些 API 通过胶水文件 (Wrapper) 进行封装, 提供给 Rust 应用程序使用.
这里的一个关键问题是如何将 Rust 应用程序编译后和系统源码链接起来生成一个固件.
其基本的解决思想是首先获取 Rust 应用程序编译后的对象文件(.obj), 其次获取系统源码编译后的对象文件,
最后将所有的对象文件链接起来生成系统固件.
具体实践过程中遇到的细节, 会在下面提到.
- 设置 Rust 插桩文件
`目录介绍` 中的 libs 目录中的文件即为插桩文件, 其结构如下
+-- libs/
+-- rustapp/
+-- stub.c
+-- rustcore/
+-- stub.c
stub.c 中的内容并不重要, 插桩的意思就是占个坑, 它们的真实意图是用来生成两个库文件
librustcore.a 和 librustapp.a 文件, 因此需要在 CMakeLists.txt 中添加如下两行
add_library(rustcore STATIC ${ROOTDIR}/libs/rustcore/stub.c)
add_library(rustapp STATIC ${ROOTDIR}/libs/rustapp/stub.c)
librustapp.a 将会被真实的 rust 应用程序所替代, 那 librustcore.a 是干什么的?
所有的 rust 程序都依赖于 Rust 的核心库即 rust core, 因此这个是必须提供,
Rust Core 的介绍参见 [The Rust Core Library](https://doc.rust-lang.org/core/).
rust core 库和 rust 应用程序库的生成将会在接下来节介绍.
- rust core 库的生成
当添加完 rust 编译嵌入式的工具链时, rust core 库会自动被放到系统中固定的目录下,
其路径的获取方式如下
RUST_THUMBV6M_SYSROOT=$(rustc --print sysroot --target thumbv6m-none-eabi)
RUST_LIBCORE_SRC=$(ls -1 $RUST_THUMBV6M_SYSROOT/lib/rustlib/thumbv6m-none-eabi/lib/libcore-*.rlib)
rlib 文件实际上就是静态库文件, 可以用如下命令查看 rlib 内容
arm-none-eabi-ar t $RUST_LIBCORE_SRC
core-1ba29f225cca71e5.core.1ml6ett9-cgu.0.rcgu.o
lib.rmeta
因此我们直接将该文件复制为 librustcore.a 即可.
- rust app 库的生成
新建的 rust 应用程序目录为 app, Rust 提供了 cargo 工具, 可以快速创建项目,
进入项目根目录执行如下命令即可生成 app 目录(也可以使用 --lib 直接生成库文件目录结构)
cargo new app
- 进入 app/src 目录, 删除 main.rs, 然后新建 lib.rs
- 配置 app/Cargo.toml
配置其内容如下所示
[package]
name = "app"
version = "0.1.0"
authors = ["ikey4u <pwnkeeper@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cty = "0.2.0" # String utilities from cty library: https://crates.io/crates/cty
cstr_core = "0.1.2" # String utilities from cstr_core library: https://crates.io/crates/cstr_core
cortex-m = "0.5.8" # Arm Cortex-M utilities: https://crates.io/crates/cortex-m
[lib]
name = "tosrs"
test = false
bench = false
# Options for `cargo build`
[profile.dev]
panic = "abort" # Disable stack unwinding on panic
# Options for `cargo build --release`
[profile.release]
panic = "abort" # Disable stack unwinding on panic
codegen-units = 1 # Better optimizations
debug = true # Symbols are nice and they don't increase the size on Flash lto = true # Better optimizations
- 配置 app/.cargo/config 文件
配置其内容如下所示
[target.thumbv6m-none-eabi]
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = [
# LLD (shipped with the Rust toolchain) is used as the default linker
"-C", "link-arg=-Tlink.x",
]
[build]
target = "thumbv6m-none-eabi"
注意 tos_evb_g0 对应的 target 是 thumbv6m-none-eabi.
项目中最终的目录如下所示
+-- app/
+-- src/
+ bridge.rs
+ lib.rs
+-- Cargo.toml
+-- .cargo/
+-- config
配置完成后, 便可在 app 目录执行如下命令编译
cargo build
编译的中间产物位于 `app/target/thumbv6m-none-eabi/debug/deps` 中,
这里面是一系列的 .rlib 文件(静态库文件), 这些库文件包含了应用程序代码及其依赖的库代码.
我们将这些库包含的所有对象文件提取出来重新打包成一个新的库文件, 即为 librustapp.a 文件.
其中 `bridge.rs` 声明了胶水文件中的 API 接口, 比如
use cty::*;
/// These glue functions are from tosglue.c
extern {
pub fn rust_print(msg: *const u8);
}
`lib.rs` 则是应用程序代码, 示例如下
#![no_std]
extern crate cortex_m;
mod bridge;
use crate::bridge::*;
use cty::*;
#[no_mangle]
pub extern "C" fn application_entry_rust() -> c_void {
unsafe {
rust_mqtt_daemon();
}
loop {
unsafe {
rust_print(b"[+] Welcome to the RUST-WORLD in TencentOS :)".as_ptr());
}
}
}
- 胶水文件
Rust 调用系统 API 或者第三方 C 库的 API 通过胶水文件 tosglue.c 实现,
这里的做法是将 tosglue.c 编译为一个库文件, 但是不参与链接, 而是提取其对象文件,
合并到 librustapp.a 中, 在 CMakeLists.txt 中添加如下行
add_library(tosglue STATIC ${ROOTDIR}/tosglue.c)
tosglue.c 中的一个 API 示例如下
void rust_print(const char *msg) {
printf("%s\r\n", msg);
}
- 一键编译生成固件
在编译之前还需要注意修改 CMakeLists.txt, 保证固件链接了 librustcore.a 和 librustapp.a
target_link_libraries(${PROJECT_NAME} ${LIBS} c nosys rustcore rustapp)
这样设置之后, 我们再替换完 librustcore.a 和 librustapp.a 之后,
就可以强制重新生成新的固件.
最终的编译脚本参见 [build.sh](../build.sh)
# 参考
- [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)
- [STM32L0 Rust Part 1 - Getting Started](https://craigjb.com/2019/12/31/stm32l0-rust/)
- [FreeRTOS meets Rust](http://www.hashmismatch.net/freertos-meets-rust/)

View File

@@ -1,490 +0,0 @@
# STM32 甲醛检测器安装教程
本文所用系统为 Ubuntu 20.04.1, 以下教程所用到的系统固件源码以本仓库 template 中的模板代码为准,
有任何疑问欢迎提 issues.
## 教程
- 连接 ST-LINK (STv2) 和开发板
STv2 上有一个示意图标有各个 Pin 的含义, Pin 周围有一个缺口,
缺口对应的一排 Pin 对应与示意图外侧的一列, STv2 和开发板接口连接对应关系如下表所示.
|STv2 接口 |开发板接口 |
| ------------- |-------------|
| 3.3v | 3v3 |
| SWDIO | DIO |
| SWCLK | CLK |
| GND | GND |
- 安装 STv2 驱动
ST-LINK 的驱动源码地址为 https://github.com/stlink-org/stlink.
安装编译依赖
sudo apt install clang build-essential cmake libusb-1.0-0 libusb-1.0-0-dev
下载源码并编译
git clone https://github.com/stlink-org/stlink
cd stlink
make release
安装到 $HOME/.usr/stlink 目录中
cd build/Release && make install DESTDIR=$HOME/.usr/stlink
安装后 $HOME/.usr/stlink 结构如下
➜ Release git:(develop) tree ~/.usr/stlink/
/home/m9/.usr/stlink/
├── etc
│   └── modprobe.d
│   └── stlink_v1.conf
├── lib
│   └── udev
│   └── rules.d
│   ├── 49-stlinkv1.rules
│   ├── 49-stlinkv2-1.rules
│   ├── 49-stlinkv2.rules
│   └── 49-stlinkv3.rules
└── usr
└── local
├── bin
│   ├── st-flash
│   ├── st-info
│   └── st-util
├── include
│   └── stlink
│   ├── backend.h
│   ├── chipid.h
│   ├── commands.h
│   ├── flash_loader.h
│   ├── libusb_settings.h
│   ├── logging.h
│   ├── md5.h
│   ├── reg.h
│   ├── sg.h
│   ├── stlink.h
│   ├── stm32.h
│   ├── usb.h
│   └── version.h
├── lib
│   ├── libstlink.a
│   ├── libstlink.so -> libstlink.so.1
│   ├── libstlink.so.1 -> libstlink.so.1.6.1
│   └── libstlink.so.1.6.1
└── share
└── man
└── man1
├── st-flash.1
├── st-info.1
└── st-util.1
现在需要通过 udev 设置 USB 访问权限, 进入到 stlink 源码根目录执行如下操作
sudo cp -a config/udev/rules.d/* /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger
现在给电脑插上电路板, 使用 lsusb 查看 USB 设备, 能看到如下输出说明安装成功
➜ stlink git:(develop) lsusb
...
Bus 002 Device 013: ID 0483:3748 STMicroelectronics ST-LINK/V2
...
在 shell 配置文件如 $HOME/.zshrc 中添加如下环境变量
STLINK=$HOME/.usr/stlink
export PATH=${STLINK}/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${STLINK}/usr/local/lib
更新库缓存
sudo ldconfig
刷新环境变量
exec $SHELL
然后查看板子信息
➜ ~ st-info --probe
Found 1 stlink programmers
serial: 2c5a15000b14324d434d4e00
hla-serial: "\x2c\x5a\x15\x00\x0b\x14\x32\x4d\x43\x4d\x4e\x00"
flash: 131072 (pagesize: 2048)
sram: 36864
chipid: 0x0460
descr: G070/G071/G081
测试文件读取
➜ ~ st-flash --debug read dummy.file 0 256
st-flash 1.6.1-96-gbf41f14
2020-09-22T23:56:45 DEBUG common.c: *** looking up stlink version
2020-09-22T23:56:45 DEBUG common.c: st vid = 0x0483 (expect 0x0483)
2020-09-22T23:56:45 DEBUG common.c: stlink pid = 0x3748
2020-09-22T23:56:45 DEBUG common.c: stlink version = 0x2
2020-09-22T23:56:45 DEBUG common.c: jtag version = 0x23
2020-09-22T23:56:45 DEBUG common.c: swim version = 0x7
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG usb.c: JTAG/SWD freq set to 0
2020-09-22T23:56:45 DEBUG common.c: *** set_swdclk ***
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG common.c: *** stlink_jtag_reset ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_reset ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_write_debug32 0x05fa0004 to 0xe000ed0c
2020-09-22T23:56:45 DEBUG common.c: Loading device parameters....
2020-09-22T23:56:45 DEBUG common.c: *** stlink_core_id ***
2020-09-22T23:56:45 DEBUG common.c: core_id = 0x0bc11477
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_debug32 0000000000 at 0xe0042000
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_debug32 0x20006460 at 0x40015800
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_debug32 0xffff0080 at 0x1fff75e0
2020-09-22T23:56:45 INFO common.c: G070/G071/G081: 36 KiB SRAM, 128 KiB flash in at least 2 KiB pages.
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG common.c: *** stlink_force_debug_mode ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_status ***
2020-09-22T23:56:45 DEBUG usb.c: core status: 00030003
2020-09-22T23:56:45 DEBUG common.c: core status: halted
2020-09-22T23:56:45 INFO common.c: read from address 0000000000 size 256
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_mem32 ***
2020-09-22T23:56:45 DEBUG common.c: data_len = 256 0x100
68 5c 00 20 cd 00 00 08 c1 2d 00 08 c7 29 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b7 2f 00 08 00 00 00 00 00 00 00 00 25 01 00 08 b9 2f 00 08 df 00 00 08 00 00 00 00 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 00 00 00 00 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 00 00 00 00 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 9d 37 00 08 ad 37 00 08 bd 37 00 08 03 48 85 46 00 f0 56 fd 00 48 00 47 39 58 00 08 68 5c 00 20 04 48 80 47 04 48 00 47 fe e7 fe e7 fe e7 fe e7 fe e7 fe e7 4d 30 00 08 b9 00 00 08 72 b6 70 47 62 b6 70 47 ef f3 10 80 72 b6 70 47 80 f3 10 88 70 47 1b 48
2020-09-22T23:56:45 DEBUG common.c: *** stlink_exit_debug_mode ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_write_debug32 0xa05f0000 to 0xe000edf0
2020-09-22T23:56:45 DEBUG common.c: *** stlink_close ***
- CH340 串口驱动
在板子上有一个写有 CH340C 的电子元件, 这个就是电子元件的作用就是将 USB 协议转换为串口协议,
要让这个这个电子元件正常工作, 需要安装 CH340 驱动.
Ubuntu 20.04 系统的 Linux 内核已经自带了这个驱动, 可以使用如下命令查看
➜ lsmod | grep ch34
ch341 20480 0
usbserial 53248 1 ch341
如果不成功, 对驱动打补丁参考如下链接:
https://learn.sparkfun.com/tutorials/how-to-install-ch340-drivers/all#linux
当串口驱动成功安装后, 数据是如何从电脑传输到板子上呢?
在 USB 接口里有 4 根线, 外侧的两根长金手指负责供电, 即电源线, 内侧的两根金手指比较短,
用于数据传输, 即数据线.
当我们再电脑上通过串口向板子传输数据时, 电脑端采用 USB 数据传输协议通过数据线传到板子上,
然后 CH340 驱动解析 USB 数据将其转换为串口数据传输给板子上的其他元器件.
串口除了传输数据的功能之外, 还有调试功能, 板子上程序的输出一般都是被重定向到串口中,
然后打印出数据供调试用.
- 串口工具
通过串口工具, 我们可以观察到窗口上传输的数据, 这里使用的串口工具是 kermit,
其首页为 http://www.kermitproject.org/ck90.html
编译安装 c-kermit 的命令如下
wget http://www.kermitproject.org/ftp/kermit/test/tar/x.zip
unzip x.zip -d c-kermit && cd c-kermit
make linux
会生成一个 wermit 二进制文件, 将其保存到某个路径比如 $HOME/.usr/bin,
建议将其重命名为 kermit, 然后将该路径加入环境变量, 然后运行即可.
- 连接串口设备
首先查看串口设备, Linux 中使用 ttyS<x> 来表示串口设备名, 其中 <x> 是可变的,
比如 ttyS0, ttyS1, 对应到 Windows 中就分别表示 COM1, COM2. 特别地,
基于 USB 的串口设备名称一般类似于 ttyUSB0, ttyUSB1 等, 这些设备对应的文件路径位于 /dev 下面,
比如 ttyUSB0 的位置就是 /dev/ttyUSB0.
使用如下命令查看连接的串口设备
➜ dmesg | grep tty
[ 0.352821] printk: console [tty0] enabled
[ 1.179333] tty tty50: hash matches
[193518.041877] usb 3-2: ch341-uart converter now attached to ttyUSB0
查看串口参数
sudo stty -F /dev/ttyUSB0 -a
设置串口参数(波特率设置为 115200, 8 位数据模式, 其实这步是不必要的, 可以值接在 kermit 中设置)
sudo stty -F /dev/ttyUSB0 ispeed 115200 ospeed 115200 cs8
查看设置后的串口属性信息
➜ sudo stty -F /dev/ttyUSB0 -a
speed 115200 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel
-iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc
现在执行 wermit 进入串口工具, 然后执行如下命令
set line /dev/ttyUSB0
set carrier-watch off
connect
出现如下输出表示连接成功
Connecting to /dev/ttyUSB0, speed 115200
Escape character: Ctrl-\ (ASCII 28, FS): enabled
Type the escape character followed by C to get back,
or followed by ? to see other options.
----------------------------------------------------
如果想回到 kermit, 按下 Ctrl-\, 再按下 C 即可, 如果想再连接到串口, 输入 c 即可.
- 刷入 WiFi 固件
由于是通过串口刷 WiFi 固件, 因此需要断开其他的串口连接.
- 让串口链路连接到 WiFi 电子元件上, 其具体做法为
1. 定位到 `串口切换`
串口切换一共两排, 每排四个 Pin, 示意图如下
* * * *
* * * *
将短路帽(黄色塑料套)按如下连接
* + + *
* - - *
加号的连接到一起, 减号的连接到一起.
2. 定位到 `ESP 固件下载配置`
这个配置一共有 3 个, 依次如下
3v3 IO0 GND
用短路帽把 IO0 和 GND 连接.
3. 定位到 `BOOT 配置`
这个配置一共有 3 个, 依次如下
0 BOOT 1
将短路帽把 0 和 BOOT 连接.
- 安装 esptool 工具
需要用到工具 esptool, 地址为 https://github.com/espressif/esptool, 安装命令如下
pip3 install esptool
安装完成后刷新系统环境变量, 会得到一个命令 esptool.py, 我们就是通过这个命令将 WiFi 固件刷入到板子中.
以上准备完成后, 测试一下 esp 是否正常工作, 命令如下
sudo -E env "PATH=$PATH" esptool.py --port /dev/ttyUSB0 read_mac
输出类似如下
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 40:f5:20:08:6f:b1
Uploading stub...
Running stub...
Stub running...
MAC: 40:f5:20:08:6f:b1
Hard resetting via RTS pin...
如果连接不上, 考虑如下几种情形
1. reset 板子
如果之前你执行过 esptool.py, 你必须手动按一下板子上的 reset 按键,
如果你不按 reset 继续执行 esptool.py 命令, 那么这个命令会一直挂起, 输出类似于下面这种
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting........_____....
2. 串口被占用
如果提示下面的错误表示你的串口被占用了, 看看你的串口工具是不是连上了.
serial.serialutil.SerialException: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
3. STLINK 和串口同时连上了
把 STLINK 和串口线都拔下来, 只插串口线.
- 刷入固件
确定 esp 正常工作后, 下载固件
git clone https://github.com/tencentyun/qcloud-iot-esp-wifi.git
然后解压固件
cd qcloud-iot-esp-wifi
unzip qcloud-iot-at-esp8266/QCloud_IoT_AT_ESP8266_FW/QCloud_IoT_AT_ESP8266_v2.1.1_20200903.zip
腾讯云 IoT 定制 AT 串口使用 UART0, Tx 为 GPIO1, Rx 为 GPIO3, UART_1_3 的固件
采用的 Tx 和 Rx 和 AT 的一致, 因此我们使用 UART_1_3 固件, 其路径为
QCloud_IoT_AT_ESP8266_v2.1.1_20200903/QCloud_IoT_AT_ESP8266_v2.1.1_20200903_UART_1_3.bin
执行如下命令刷入固件
sudo -E env "PATH=$PATH" esptool.py --port /dev/ttyUSB0 --chip esp8266 --baud 1500000 --after hard_reset write_flash 0x0 QCloud_IoT_AT_ESP8266_v2.1.1_20200903/QCloud_IoT_AT_ESP8266_v2.1.1_20200903_UART_1_3.bin
成功执行后的输出示例如下
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting...
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 40:f5:20:08:6f:b1
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 1500000
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0040
Compressed 2039808 bytes to 485108...
Wrote 2039808 bytes (485108 compressed) at 0x00000000 in 7.0 seconds (effective 2326.6 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
- 恢复串口连接
1. `串口切换`
连接示意图
1 1 2 2
3 3 4 4
数值相同的连接到一起
2. `ESP 固件下载配置`
连接 3v3 和 IO0
3. `BOOT 配置`
保持不变
- 腾讯云
到腾讯云物联网开发平台 https://cloud.tencent.com/product/iotexplorer 注册一个新产品.
新建产品后导入模板数据如下
{
"version": "1.0",
"profile": {
"ProductId": "BDDSF87WEA",
"CategoryId": "1"
},
"properties": [
{
"id": "ch20_ppm_value",
"name": "甲醛浓度值",
"desc": "",
"mode": "r",
"define": {
"type": "float",
"min": "0",
"max": "2",
"start": "0",
"step": "0.001",
"unit": "ppm(mg/m3)"
},
"required": false
}
],
"events": [],
"actions": []
}
然后新建设备, 新建之后能够得到三个信息: 设备名称, 设备密钥, 产品 ID,
这三个信息需要写入到 TencentOS 固件中.
- 甲醛传感器底板连接
根据板子和底板的 5v 和 GND 接口对应关系, 将底板连接到板子上,
然后根据传感器的 Rx 和 Tx 口将传感器和板子底板连接起来.
- 刷入 TencentOS 系统
- 下载源码
下载 TencentOS 源码, 这里假定保存路径为 `<path/to/tos>`.
git clone https://github.com/Tencent/TencentOS-tiny.git <path/to/tos>
切出 tos_evb_g0 分支源码并保存到 `<path/to/tos_evb_g0>`.
git clone -b tos_evb_g0 <path/to/tos> <path/to/tos_evb_g0>
进入 `<path/to/tos_evb_g0>` 目录, 将 TOS_CONFIG/_user_config.h 复制一份保存为 TOS_CONFIG/user_config.h,
然后修改 user_config.h 中的宏定义.
- 编译
使用如下命令安装工具链
sudo apt-get install -y gcc-arm-none-eabi
进入 tos_evb 目录下执行如下命令编译固件
export TOS_SRC_ROOT=<path/to/tos>
mkdir build && cmake .. && make
执行成功后会生成文件 mqtt_iot_explorer_tc_ch20_oled.bin
- 连接 STLINK 并刷入固件
将 STLINK 连接到板子上, 然后执行如下命令刷入
make flash
- 测试
串口工具连接板子
set line /dev/ttyUSB0
set speed 115200
set carrier-watch off
connect
按下板子上的 reset 按键, 程序就运行了, 串口会输出 WIFI CONNECTED 之类的,
腾讯云上显示设备上线.

View File

@@ -1,8 +1,6 @@
# 甲醛检测仪 - mac 环境搭建 # mac 开发环境搭建
由于之前在 Linux 上对环境进行了配置, 板子基本上已经初始化好了, 这里只列出了 mac 独有的部分, 其他部分参考 [README.md](../README.md) 中指定的文档.
目前在 mac 上配置需要做的工作不是太多, 下面有些步骤可能不太详细,
可以参考 [Linux](./setup.linux.ubuntu.md).
## 工具准备 ## 工具准备
@@ -12,7 +10,7 @@
- [cmake](https://cmake.org/download/): 下载 tar.gz 的压缩包自行安装并添加到环境变量中 - [cmake](https://cmake.org/download/): 下载 tar.gz 的压缩包自行安装并添加到环境变量中
- [llvm](https://releases.llvm.org/download.html): 参考 cmake 处理 - [llvm](https://releases.llvm.org/download.html): 参考 cmake 处理
- libusb: brew install libusb - libusb: `brew install libusb`
- 安装 - 安装
@@ -82,22 +80,12 @@
然后每次执行 kermit 命令就会自动连上串口, 能够看到调试信息输出, 要退出的话按下 Ctrl-\ 然后按下 C 即可. 然后每次执行 kermit 命令就会自动连上串口, 能够看到调试信息输出, 要退出的话按下 Ctrl-\ 然后按下 C 即可.
## WiFi 固件安装 - 工具链
参考 [Linux](./setup.linux.ubuntu.md). 编译所需要的工具链安装方法如下
## 腾讯云帐号 brew install armmbed/formulae/arm-none-eabi-gcc
参考 [Linux](./setup.linux.ubuntu.md). 安装后的路径为
## TencentOS 固件安装 /usr/local/bin/arm-none-eabi-*
编译所需要的工具链安装方法如下
brew install armmbed/formulae/arm-none-eabi-gcc
安装后的路径为
/usr/local/bin/arm-none-eabi-*
其他参考 [Linux](./setup.linux.ubuntu.md).

View File

@@ -0,0 +1,182 @@
# ST-LINK 驱动安装
- 连接 ST-LINK (STv2) 和开发板
STv2 上有一个示意图标有各个 Pin 的含义, Pin 周围有一个缺口,
缺口对应的一排 Pin 对应与示意图外侧的一列, STv2 和开发板接口连接对应关系如下表所示.
|STv2 接口 |开发板接口 |
| ------------- |-------------|
| 3.3v | 3v3 |
| SWDIO | DIO |
| SWCLK | CLK |
| GND | GND |
- 安装 STv2 驱动
ST-LINK 的驱动源码地址为 https://github.com/stlink-org/stlink
安装编译依赖
- ubuntu
sudo apt install clang build-essential cmake libusb-1.0-0 libusb-1.0-0-dev
- archlinux
sudo pacman -S cmake libusb clang
下载源码并编译, 注意 st-link 默认分支是 develop, 这个分支上的功能是不稳定的
git clone https://github.com/stlink-org/stlink
cd stlink
git checkout v1.6.1
安装到 $HOME/.usr/stlink 目录中
make release
cd build/Release && make install DESTDIR=$HOME/.usr/stlink
安装后 $HOME/.usr/stlink 结构如下
➜ Release git:(develop) tree ~/.usr/stlink/
/home/m9/.usr/stlink/
├── etc
│   └── modprobe.d
│   └── stlink_v1.conf
├── lib
│   └── udev
│   └── rules.d
│   ├── 49-stlinkv1.rules
│   ├── 49-stlinkv2-1.rules
│   ├── 49-stlinkv2.rules
│   └── 49-stlinkv3.rules
└── usr
└── local
├── bin
│   ├── st-flash
│   ├── st-info
│   └── st-util
├── include
│   └── stlink
│   ├── backend.h
│   ├── chipid.h
│   ├── commands.h
│   ├── flash_loader.h
│   ├── libusb_settings.h
│   ├── logging.h
│   ├── md5.h
│   ├── reg.h
│   ├── sg.h
│   ├── stlink.h
│   ├── stm32.h
│   ├── usb.h
│   └── version.h
├── lib
│   ├── libstlink.a
│   ├── libstlink.so -> libstlink.so.1
│   ├── libstlink.so.1 -> libstlink.so.1.6.1
│   └── libstlink.so.1.6.1
└── share
└── man
└── man1
├── st-flash.1
├── st-info.1
└── st-util.1
现在需要通过 udev 设置 USB 访问权限, 进入到 stlink 源码根目录执行如下操作
sudo cp -a config/udev/rules.d/* /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger
现在给电脑插上电路板, 使用 lsusb 查看 USB 设备, 能看到如下输出说明安装成功
➜ stlink git:(develop) lsusb
...
Bus 002 Device 013: ID 0483:3748 STMicroelectronics ST-LINK/V2
...
在 shell 配置文件如 $HOME/.zshrc 中添加如下环境变量
STLINK=$HOME/.usr/stlink
export PATH=${STLINK}/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${STLINK}/usr/local/lib
刷新环境变量
exec $SHELL
更新库缓存
sudo ldconfig
然后查看板子信息
➜ ~ st-info --probe
Found 1 stlink programmers
serial: 2c5a15000b14324d434d4e00
hla-serial: "\x2c\x5a\x15\x00\x0b\x14\x32\x4d\x43\x4d\x4e\x00"
flash: 131072 (pagesize: 2048)
sram: 36864
chipid: 0x0460
descr: G070/G071/G081
如果上述命令输出如下
Found 1 stlink programmers
version: V2J35S7
serial: 2C5A15000B14324D434D4E00
flash: 0 (pagesize: 0)
sram: 0
chipid: 0x0000
descr: unknown device
这表示无法识别 st-link 设备, 检查是否使用了 develop 分支的代码, 这个分支上的代码无法正确识别 st-link,
切换到 v1.6.1 tag 解决问题.
测试文件读取
➜ ~ st-flash --debug read dummy.file 0 256
st-flash 1.6.1-96-gbf41f14
2020-09-22T23:56:45 DEBUG common.c: *** looking up stlink version
2020-09-22T23:56:45 DEBUG common.c: st vid = 0x0483 (expect 0x0483)
2020-09-22T23:56:45 DEBUG common.c: stlink pid = 0x3748
2020-09-22T23:56:45 DEBUG common.c: stlink version = 0x2
2020-09-22T23:56:45 DEBUG common.c: jtag version = 0x23
2020-09-22T23:56:45 DEBUG common.c: swim version = 0x7
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG usb.c: JTAG/SWD freq set to 0
2020-09-22T23:56:45 DEBUG common.c: *** set_swdclk ***
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG common.c: *** stlink_jtag_reset ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_reset ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_write_debug32 0x05fa0004 to 0xe000ed0c
2020-09-22T23:56:45 DEBUG common.c: Loading device parameters....
2020-09-22T23:56:45 DEBUG common.c: *** stlink_core_id ***
2020-09-22T23:56:45 DEBUG common.c: core_id = 0x0bc11477
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_debug32 0000000000 at 0xe0042000
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_debug32 0x20006460 at 0x40015800
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_debug32 0xffff0080 at 0x1fff75e0
2020-09-22T23:56:45 INFO common.c: G070/G071/G081: 36 KiB SRAM, 128 KiB flash in at least 2 KiB pages.
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG common.c: stlink current mode: debug (jtag or swd)
2020-09-22T23:56:45 DEBUG common.c: *** stlink_force_debug_mode ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_status ***
2020-09-22T23:56:45 DEBUG usb.c: core status: 00030003
2020-09-22T23:56:45 DEBUG common.c: core status: halted
2020-09-22T23:56:45 INFO common.c: read from address 0000000000 size 256
2020-09-22T23:56:45 DEBUG common.c: *** stlink_read_mem32 ***
2020-09-22T23:56:45 DEBUG common.c: data_len = 256 0x100
68 5c 00 20 cd 00 00 08 c1 2d 00 08 c7 29 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b7 2f 00 08 00 00 00 00 00 00 00 00 25 01 00 08 b9 2f 00 08 df 00 00 08 00 00 00 00 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 00 00 00 00 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 00 00 00 00 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 df 00 00 08 9d 37 00 08 ad 37 00 08 bd 37 00 08 03 48 85 46 00 f0 56 fd 00 48 00 47 39 58 00 08 68 5c 00 20 04 48 80 47 04 48 00 47 fe e7 fe e7 fe e7 fe e7 fe e7 fe e7 4d 30 00 08 b9 00 00 08 72 b6 70 47 62 b6 70 47 ef f3 10 80 72 b6 70 47 80 f3 10 88 70 47 1b 48
2020-09-22T23:56:45 DEBUG common.c: *** stlink_exit_debug_mode ***
2020-09-22T23:56:45 DEBUG common.c: *** stlink_write_debug32 0xa05f0000 to 0xe000edf0
2020-09-22T23:56:45 DEBUG common.c: *** stlink_close ***
- 虚拟机映射
VirtualBox 虚拟机需要将用户添加到 vboxusers 用户组
sudo usermod -aG vboxusers $USER
添加完毕后, 重启主机.

View File

@@ -37,7 +37,7 @@ uint8_t ch20_value_pool[5 * sizeof(ch20_data_t)];
void rust_mqtt_daemon() void rust_mqtt_daemon()
{ {
char *str = "TencentOS XXXX"; char *str = "tos_meets_rust";
OLED_Init(); OLED_Init();
OLED_Clear(); OLED_Clear();

View File

@@ -32,6 +32,8 @@ __API__ k_err_t tos_sem_create_max(k_sem_t *sem, k_sem_cnt_t init_count, k_sem_c
pend_object_init(&sem->pend_obj); pend_object_init(&sem->pend_obj);
TOS_OBJ_INIT(sem, KNL_OBJ_TYPE_SEMAPHORE); TOS_OBJ_INIT(sem, KNL_OBJ_TYPE_SEMAPHORE);
knl_object_alloc_set_static(&sem->knl_obj);
return K_ERR_NONE; return K_ERR_NONE;
} }