diff --git a/examples/tos_meets_rust/.gitignore b/examples/tos_meets_rust/.gitignore index f8c6f120b..6f89a31c4 100644 --- a/examples/tos_meets_rust/.gitignore +++ b/examples/tos_meets_rust/.gitignore @@ -29,3 +29,4 @@ __pycache__ xcuserdata user_config.h .ccls-cache +tmp diff --git a/examples/tos_meets_rust/README.md b/examples/tos_meets_rust/README.md index a1c895fd3..6ada8ff05 100644 --- a/examples/tos_meets_rust/README.md +++ b/examples/tos_meets_rust/README.md @@ -1,23 +1,4 @@ -# 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 +# TencentOS Tiny meets Rust (甲醛检测器) ## 目录介绍 @@ -42,8 +23,7 @@ +-- README.md: 项目概览文档 +-- tosglue.c: Rust 和 TencentOS 的胶水文件 -板子启动后会自动执行 BSP/Src/main.c 中的 main 函数, -在 main 函数中会调用用户定义的如下函数 +板子启动后会自动执行 BSP/Src/main.c 中的 main 函数, 在 main 函数中会调用用户定义的如下函数 void application_entry_rust(); @@ -51,226 +31,105 @@ 除了入口函数, 需要有底层的中断服务实现, 位于 `BSP/Src/stm32g0xx_it.c` 中. -## Rust 集成 - -目前十分粗糙的设计架构如下所示 - - ------------------------------------ - Rust Application - ------------------------------------ - Rust Wrapper - ------------------------------------ - TencentOS API | Third C Libraries API - ------------------------------------ - TencentOS - ------------------------------------ - -即 TencentOS 对硬件层进行抽象, 对上层提供系统 API 以及可能的第三方 C 库 API, -然后 Rust 对这些 API 通过胶水文件 (Wrapper) 进行封装, 提供给 Rust 应用程序使用. - -这里的一个关键问题是如何将 Rust 应用程序编译后和系统源码链接起来生成一个固件. - -其基本的解决思想是首先获取 Rust 应用程序编译后的对象文件(.obj), 其次获取系统源码编译后的对象文件, -最后将所有的对象文件链接起来生成系统固件. - -具体实践过程中遇到的细节, 会在下面提到. - -- 安装工具链 - - 这里默认你已经安装了 rust 工具链, 如果你的 rustc 版本低于 1.47.0 则切换到 nightly 版本, - 切换命令如下 - - rustup default nightly - - 如果版本大于等于 1.47.0, 则不用切换. - - 接着安装支持 tos_evb_g0 板子的工具链 - - rustup target add thumbv6m-none-eabi - sudo apt-get install -y gcc-arm-none-eabi - - 其他可选工具 - - sudo apt-get install gdb-arm-none-eabi - sudo apt-get install OpenOCD - -- 设置 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 "] - 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 +## 编译运行 +- 配置腾讯云 + + 到腾讯云物联网开发平台 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": [] + } - - 配置 app/.cargo/config 文件 + 然后新建设备, 新建之后能够得到三个信息: 设备名称, 设备密钥, 产品 ID, + 这三个信息需要写入到 TencentOS 固件中. - 配置其内容如下所示 + 配置完成后, 将甲醛传感器与底板连接, 根据板子和底板的 5v 和 GND 接口对应关系, 将底板连接到板子上, + 然后根据传感器的 Rx 和 Tx 口将传感器和板子底板连接起来. - [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. + 下载 TencentOS 源码 - 项目中最终的目录如下所示 + git clone https://github.com/Tencent/TencentOS-tiny.git - +-- app/ - +-- src/ - + bridge.rs - + lib.rs - +-- Cargo.toml - +-- .cargo/ - +-- config - - 配置完成后, 便可在 app 目录执行如下命令编译 + 进入 `examples/tos_meets_rust` 目录, 将 `TOS_CONFIG/_user_config.h` 复制一份为 `TOS_CONFIG/user_config.h`, + 写入设备信息和 WiFI 信息. - cargo build + 新建系统环境变量 TOS_SRC_ROOT, 其值为 TencentOS Tiny 源码的绝对路径. - 编译的中间产物位于 `app/target/thumbv6m-none-eabi/debug/deps` 中, - 这里面是一系列的 .rlib 文件(静态库文件), 这些库文件包含了应用程序代码及其依赖的库代码. +- 基础依赖安装 - 我们将这些库包含的所有对象文件提取出来重新打包成一个新的库文件, 即为 librustapp.a 文件. + - ST-LINK 驱动安装, 参考 [stlink](./docs/stlink.md) - 其中 bridge.rs 声明了胶水文件中的 API 接口, 比如 + - CH34X 驱动安装, 参考 [CH34X](./docs/ch34x.md) - use cty::*; + - kermit 串口工具安装, 参考 [kermit](./docs/kermit.md) - /// These glue functions are from tosglue.c - extern { - pub fn rust_print(msg: *const u8); - } +- 工具链安装 - lib.rs 则是应用程序代码, 示例如下 + 编译需要的 arm-none-eabi 工具连, eabi 的含义是 Embedded Application Binary Interface, + 不同发行版安装方式不一样 - #![no_std] + - ubuntu - extern crate cortex_m; + sudo apt-get install -y gcc-arm-none-eabi - mod bridge; + - archlinux: - use crate::bridge::*; - use cty::*; + sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib - #[no_mangle] - pub extern "C" fn application_entry_rust() -> c_void { - unsafe { - rust_mqtt_daemon(); - } + 这里默认你已经安装了 rust 工具链, 如果你的 rustc 版本低于 1.47.0 则切换到 nightly 版本, + 切换命令如下 - loop { - unsafe { - rust_print(b"[+] Welcome to the RUST-WORLD in TencentOS :)".as_ptr()); - } - } - } + rustup default nightly -- 胶水文件 + 如果版本大于等于 1.47.0, 则不用切换, 接着安装支持板子的 rust 工具链 - Rust 调用系统 API 或者第三方 C 库的 API 通过胶水文件 tosglue.c 实现, - 这里的做法是将 tosglue.c 编译为一个库文件, 但是不参与链接, 而是提取其对象文件, - 合并到 librustapp.a 中, 在 CMakeLists.txt 中添加如下行 + rustup target add thumbv6m-none-eabi - add_library(tosglue STATIC ${ROOTDIR}/tosglue.c) +- 刷入 WiFi 固件, 参见 [esp](./docs/flash-esp.md) - tosglue.c 中的一个 API 示例如下 +- 刷入系统 - void rust_print(const char *msg) { - printf("%s\r\n", msg); - } + 连接 STLINK 后, 执行如下命令 -- 一键编译生成固件 + bash build.sh - 在编译之前还需要注意修改 CMakeLists.txt, 保证固件链接了 librustcore.a 和 librustapp.a + 刷入完成后, 登录 kermit, 然后按下板子上的 reset 按键, 程序就运行了, 串口会输出 WIFI CONNECTED 之类的, + 腾讯云上显示设备上线. - target_link_libraries(${PROJECT_NAME} ${LIBS} c nosys rustcore rustapp) +## Rust 集成 - 这样设置之后, 我们再替换完 librustcore.a 和 librustapp.a 之后, - 就可以强制重新生成新的固件. +Rust 集成原理参见 [rust](./docs/rust.md) - 最终的编译脚本参见 build.sh. +## 其他 -## 参考 +1. 如果你在 mac 平台上开发, 你可以参考文档 [setup.mac.md](./docs/setup.mac.md) 来搭建开发环境. -- [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/) +2. 有一份简短的关于本 demo 的介绍 PPT, 位于[这里](./docs/presentation.pdf), 有需要可以打开查看. diff --git a/examples/tos_meets_rust/docs/ch34x.md b/examples/tos_meets_rust/docs/ch34x.md new file mode 100644 index 000000000..2efee1b2c --- /dev/null +++ b/examples/tos_meets_rust/docs/ch34x.md @@ -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/ diff --git a/examples/tos_meets_rust/docs/flash-esp.md b/examples/tos_meets_rust/docs/flash-esp.md new file mode 100644 index 000000000..dc5ec0ceb --- /dev/null +++ b/examples/tos_meets_rust/docs/flash-esp.md @@ -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 配置` + + 保持不变 diff --git a/examples/tos_meets_rust/docs/imgs/serial_port_map.png b/examples/tos_meets_rust/docs/imgs/serial_port_map.png new file mode 100644 index 000000000..f3554a944 Binary files /dev/null and b/examples/tos_meets_rust/docs/imgs/serial_port_map.png differ diff --git a/examples/tos_meets_rust/docs/imgs/tos.svg b/examples/tos_meets_rust/docs/imgs/tos.svg new file mode 100644 index 000000000..662044055 --- /dev/null +++ b/examples/tos_meets_rust/docs/imgs/tos.svg @@ -0,0 +1,3 @@ + + +
Rust FFI Bindings
Rust FFI Bindings
OS API
OS API
Rust Applications
Rust Applications
Rust Language Engine
Rust Language Engine
Third C Libraries API
Third C Libraries API
TencentOS-tiny OS
TencentOS-tiny OS
Applications in Python, JavaScritpt ...
Applications in Python, JavaScritpt...
Rust Core
Rust Core
Rust App Stub
Rust App Stub
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/examples/tos_meets_rust/docs/kermit.md b/examples/tos_meets_rust/docs/kermit.md new file mode 100644 index 000000000..ee1248d34 --- /dev/null +++ b/examples/tos_meets_rust/docs/kermit.md @@ -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 即可. diff --git a/examples/tos_meets_rust/docs/presentation.pdf b/examples/tos_meets_rust/docs/presentation.pdf new file mode 100644 index 000000000..f961424c6 Binary files /dev/null and b/examples/tos_meets_rust/docs/presentation.pdf differ diff --git a/examples/tos_meets_rust/docs/rust.md b/examples/tos_meets_rust/docs/rust.md new file mode 100644 index 000000000..219da9505 --- /dev/null +++ b/examples/tos_meets_rust/docs/rust.md @@ -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 "] + 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/) diff --git a/examples/tos_meets_rust/docs/setup.linux.ubuntu.md b/examples/tos_meets_rust/docs/setup.linux.ubuntu.md deleted file mode 100644 index 7564d2d95..000000000 --- a/examples/tos_meets_rust/docs/setup.linux.ubuntu.md +++ /dev/null @@ -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 来表示串口设备名, 其中 是可变的, - 比如 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 = ; eol2 = ; swtch = ; - 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 源码, 这里假定保存路径为 ``. - - git clone https://github.com/Tencent/TencentOS-tiny.git - - 切出 tos_evb_g0 分支源码并保存到 ``. - - git clone -b 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= - 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 之类的, - 腾讯云上显示设备上线. diff --git a/examples/tos_meets_rust/docs/setup.mac.md b/examples/tos_meets_rust/docs/setup.mac.md index 1d1909858..5faaae8d0 100644 --- a/examples/tos_meets_rust/docs/setup.mac.md +++ b/examples/tos_meets_rust/docs/setup.mac.md @@ -1,8 +1,6 @@ -# 甲醛检测仪 - mac 环境下搭建 +# mac 开发环境搭建 -由于之前在 Linux 上对环境进行了配置, 板子基本上已经初始化好了, -目前在 mac 上配置需要做的工作不是太多, 下面有些步骤可能不太详细, -可以参考 [Linux](./setup.linux.ubuntu.md). +这里只列出了 mac 独有的部分, 其他部分参考 [README.md](../README.md) 中指定的文档. ## 工具准备 @@ -12,7 +10,7 @@ - [cmake](https://cmake.org/download/): 下载 tar.gz 的压缩包自行安装并添加到环境变量中 - [llvm](https://releases.llvm.org/download.html): 参考 cmake 处理 - - libusb: brew install libusb + - libusb: `brew install libusb` - 安装 @@ -82,22 +80,12 @@ 然后每次执行 kermit 命令就会自动连上串口, 能够看到调试信息输出, 要退出的话按下 Ctrl-\ 然后按下 C 即可. -## WiFi 固件安装 +- 工具链 -参考 [Linux](./setup.linux.ubuntu.md). + 编译所需要的工具链安装方法如下 -## 腾讯云帐号 + brew install armmbed/formulae/arm-none-eabi-gcc -参考 [Linux](./setup.linux.ubuntu.md). + 安装后的路径为 -## TencentOS 固件安装 - -编译所需要的工具链安装方法如下 - - brew install armmbed/formulae/arm-none-eabi-gcc - -安装后的路径为 - - /usr/local/bin/arm-none-eabi-* - -其他参考 [Linux](./setup.linux.ubuntu.md). + /usr/local/bin/arm-none-eabi-* diff --git a/examples/tos_meets_rust/docs/stlink.md b/examples/tos_meets_rust/docs/stlink.md new file mode 100644 index 000000000..509c532e0 --- /dev/null +++ b/examples/tos_meets_rust/docs/stlink.md @@ -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 + + 添加完毕后, 重启主机. diff --git a/examples/tos_meets_rust/tosglue.c b/examples/tos_meets_rust/tosglue.c index 6a97e88e1..d04c1fb44 100644 --- a/examples/tos_meets_rust/tosglue.c +++ b/examples/tos_meets_rust/tosglue.c @@ -37,7 +37,7 @@ uint8_t ch20_value_pool[5 * sizeof(ch20_data_t)]; void rust_mqtt_daemon() { - char *str = "TencentOS XXXX"; + char *str = "tos_meets_rust"; OLED_Init(); OLED_Clear();