主页 > 电脑硬件  > 

FreeRTOS-rust食用指南

FreeRTOS-rust食用指南
Rust 环境安装

  rustup 是 Rust 的安装程序,也是它的版本管理程序,Linux 命令行下使用如下方式安装

# 安装 rustup curl --proto '=https' --tlsv1.2 sh.rustup.rs -sSf | sh #更新 rustup rustup update # 版本检查 rustc -V cargo -V FreeRTOS-rust 框架介绍

  FreeRTOS-rust 是一个开源项目,旨在简化在嵌入式应用中使用 Rust 语言与 FreeRTOS 实时操作系统(RTOS)的集成。该项目基于 FreeRTOS 的原始 C 代码,并提供了 Rust 语言的接口。方便用户在嵌入式设备上使用 FreeRTOS 操作系统并使用 Rust 语言开发程序。

目录介绍 FreeRTOS-rust ├── .cargo # 对 cargo 本身的配置 │ └── config.toml ├── Cargo.toml # 对当前工作空间的配置 ├── freertos-cargo-build # 负责对 freertos 源码进行编译 │ ├── Cargo.toml # 对当前 package 进行配置 │ └── src │ └── lib.rs ├── freertos-rust # 负责编译 freertos 的 rust 接口层 │ ├── Cargo.toml # 对当前 package 进行配置 │ ├── build.rs # package 编译前自动调用的脚本 │ └── src # 适配层源码 │ ├── allocator.rs │ ├── base.rs │ ├── critical.rs │ ├── delays.rs │ ├── event_group.rs │ ├── freertos # freertos C 接口适配层和实现的钩子函数 │ │ ├── ports │ │ │ └── arm │ │ │ └── hooks.c │ │ └── shim.c │ ├── hooks.rs │ ├── isr.rs │ ├── lib.rs │ ├── mutex.rs │ ├── patterns │ │ ├── compute_task.rs │ │ ├── mod.rs │ │ ├── processor.rs │ │ └── pub_sub.rs │ ├── portmacro.h │ ├── prelude │ │ ├── mod.rs │ │ └── no_std.rs │ ├── queue.rs │ ├── semaphore.rs │ ├── shim.rs │ ├── task.rs │ ├── timers.rs │ ├── units.rs │ └── utils.rs ├── freertos-rust-examples # freertos 应用示例 │ ├── Cargo.toml # 对当前 package 进行配置 │ ├── FreeRTOS-Kernel # freertos 内核C源码 | ├── freertos-addons # freertos 扩展库C++源码(无需关注) │ ├── build.rs # package 编译前自动调用的脚本 │ └── examples # 各平台的rust freertos 应用开发示例 │ ├── linux │ ├── nrf9160 │ ├── stm32-cortex-m3 │ │ ├── FreeRTOSConfig.h │ │ ├── layout.ld │ │ ├── main.rs │ │ └── memory.x │ ├── stm32-cortex-m4-blackpill │ └── win └── publish-all.sh 框架介绍

  FreeRTOS-rust 的整体框架分为三大块 freertos-cargo-build、freertos-rust、freertos-rust-examples,其中 freertos-cargo-build 负责对项目中所有 C语言代码的编译,包括 FreeRTOS-Kernel 内核源码,freertos C 适配层接口以及 freertos 各种钩子函数实现,内部利用 cc crate 以及 build.rs 文件中提供的信息,将C语言代码打包为静态库。freertos-rust 中包括了 freertos 的C适配层接口和钩子函数实现,以及转换为 rust 语言的对外接口,应用开发使用的 rust freertos 接口均来自这里。freertos-rust-examples 中包括了 freertos 的C语言内核源码以及各平台的rust 应用示例。

各部分使用的语言:

FreeRTOS 内核源码:C 语言FreeRTOS 对外接口:Rust 语言APP 应用开发:Rust 语言项目编译体系:Rust 语言 FreeRTOS-rust 项目集成

注:本次项目集成是以 STM32F103ZET6 芯片平台为基础进行的,其他芯片平台实现方式类似。

项目获取

  github 开源代码仓库: github /lobaro/FreeRTOS-rust

git clone github /lobaro/FreeRTOS-rust.git 环境准备 Rust 工具链安装

  设置使用 nightly 版本的 rust 工具链,能够使用更多的新功能。

# 将默认的 Rust 工具链设置为 Nightly 版本 rustup default nightly # 安装 Nightly gun 工具链 rustup toolchain install nightly-gnu # 将 nightly-gnu 设置为默认工具链 rustup default nightly-gnu 添加新的目标平台

  为工具链添加新的目标平台,添加平台后就可以使用 cargo build --target thumbv7m-none-eabi 编译进行指定平台的交叉编译了。

# 为工具链添加目标平台 rustup target add thumbv7m-none-eabi 调试工具安装

  安装 cargo 和 llvm 工具用于对交叉编译生成的文件进行转换和分析,例如 cargo strip、cargo objdump 等。

cargo install cargo-binutils rustup component add llvm-tools-preview FreeRTOS 内核源码获取

  项目在构件时会对 FreeRTOS 的源码进行交叉编译所以需要在项目根目录执行如下命令,拉取源码。

git submodule update --init --recursive 移植适配 examples Cargo.toml 配置修改

  目录:./FreeRTOS-rust/freertos-rust-examples/Cargo.toml   将 stm32l1xx 的依赖库修改为 stm32f1xx 的依赖库,并将依赖库改为最新的库版本。

[package] name = "freertos-rust-examples" version = "0.1.1" authors = ["Tobias Kaupat <tk@lobaro.de>"] edition = "2018" description = """ Create to use FreeRTOS in rust projects. It contains binaries for demos on some architecutres. """ keywords = ["FreeRTOS", "embedded", "demo", "examples"] repository = " github /lobaro/FreeRTOS-rust" [dependencies] freertos-rust = {path = "../freertos-rust"} [target.'cfg(target_arch = "arm")'.dependencies] cortex-m = {version = "0.7.7", features = ["critical-section-single-core"]} cortex-m-rt = "0.7.3" # Example: stm32-cortex-m3, [target.<triple>.dependencies] triple form cargo build --target thumbv7m-none-eabi # or form .cargo/config.toml [build] target = "thumbv7m-none-eabi" [target.thumbv7m-none-eabi.dependencies] nb = "0.1.2" embedded-hal = "0.2.3" panic-halt = "0.2.0" stm32f1xx-hal = {version = "0.10.0", features = ["rt", "stm32f103"], default-features = false} # Example: stm32-cortex-m4-blackpill [target.thumbv7em-none-eabihf.dependencies] panic-halt = "0.2.0" embedded-hal = "0.2.3" stm32f4xx-hal = {version = "0.8.3", features = ["rt", "stm32f411"]} # Example: nrf9160 [target."thumbv8m.main-none-eabihf".dependencies] nrf9160-pac = "0.2.1" # Example: win [target.x86_64-pc-windows-gnu.dependencies] # Example: linux [target.x86_64-unknown-linux-gnu.dependencies] [build-dependencies] freertos-cargo-build = {path = "../freertos-cargo-build"} stm32-cortex-m3 FreeRTOS配置修改

  目录: ./FreeRTOS-rust/freertos-rust-examples/examples/stm32-cortex-m3/FreeRTOSConfig.h

// 修改CPU主频 // #define configCPU_CLOCK_HZ ( 4200000UL ) //also systick runs at this frequency #define configCPU_CLOCK_HZ ( 72000000UL ) //also systick runs at this frequency // 禁止可视化跟踪调试 // #define configUSE_TRACE_FACILITY 1 #define configUSE_TRACE_FACILITY 0 // 禁止堆栈溢出检测功能 // #define configCHECK_FOR_STACK_OVERFLOW 2 #define configCHECK_FOR_STACK_OVERFLOW 0 // 禁用状态格式函数 // #define configUSE_STATS_FORMATTING_FUNCTIONS (1) #define configUSE_STATS_FORMATTING_FUNCTIONS (0) stm32-cortex-m3 连接脚本修改

  目录: ./FreeRTOS-rust/freertos-rust-examples/examples/stm32-cortex-m3/layout.ld ./FreeRTOS-rust/freertos-rust-examples/examples/stm32-cortex-m3/memory.x

MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K } stm32-cortex-m3 main.rs 应用修改

  目录: ./FreeRTOS-rust/freertos-rust-examples/examples/stm32-cortex-m3/main.rs

#![no_std] #![no_main] // For allocator // #![feature(lang_items)] #![feature(alloc_error_handler)] use core::fmt::Write; use core::panic::PanicInfo; use core::alloc::Layout; use nb::block; use cortex_m; use cortex_m::asm; use cortex_m_rt::exception; use cortex_m_rt::{entry, ExceptionFrame}; use embedded_hal::digital::v2::OutputPin; use freertos_rust::*; // use stm32f1xx_hal::gpio::*; use stm32f1xx_hal::gpio::IOPinSpeed; use stm32f1xx_hal::gpio::OutputSpeed; use stm32f1xx_hal::timer::Timer; use stm32f1xx_hal::serial; use stm32f1xx_hal::rcc::RccExt; use stm32f1xx_hal::time::U32Ext; use stm32f1xx_hal::prelude::_fugit_RateExtU32; use stm32f1xx_hal::prelude::_stm32_hal_afio_AfioExt; use stm32f1xx_hal::prelude::_stm32_hal_flash_FlashExt; use stm32f1xx_hal::prelude::_stm32_hal_gpio_GpioExt; use stm32f1xx_hal as hal; use crate::hal:: { stm32::{Peripherals}, }; // extern crate panic_halt; // panic handler #[global_allocator] static GLOBAL: FreeRtosAllocator = FreeRtosAllocator; fn delay() { let mut _i = 0; for _ in 0..2_00 { _i += 1; } } fn delay_n(n: i32) { for _ in 0..n { delay(); } } pub struct MyDevice<D1: OutputPin> { d1: D1, } impl<D1: OutputPin> MyDevice<D1> { pub fn from_pins(d1: D1) -> MyDevice<D1> { MyDevice { d1 } } pub fn set_led(&mut self, on:bool){ if on { let _ =self.d1.set_high(); } else { let _ =self.d1.set_low(); } } } #[entry] fn main() -> ! { // 获取对内核外设的访问权限 let cp = cortex_m::Peripherals::take().unwrap(); // 获取对特定设备外设的访问权限 let dp = Peripherals::take().unwrap(); let mut afio = dp.AFIO.constrain(); // 获得原始flash和rcc设备的所有权,并将它们转换为相应的HAL结构 let mut flash = dp.FLASH.constrain(); let rcc = dp.RCC.constrain(); // 冻结系统中所有时钟的配置,并将冻结的频率存储在时钟树中 let clocks = rcc.cfgr.freeze(&mut flash.acr); // 通过拆分 GPIOB 引脚,获取对其各引脚的互斥访问 let mut gpiob = dp.GPIOB.split(); let mut device = MyDevice::from_pins(gpiob.pb5.into_push_pull_output(&mut gpiob.crl)); device.d1.set_speed(&mut gpiob.crl, IOPinSpeed::Mhz50); let mut gpioa = dp.GPIOA.split(); // USART1 on Pins A9 and A10 let pin_tx = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh); let pin_rx = gpioa.pa10; // 设置串口USART1的参数 let serial = serial::Serial::new( dp.USART1, (pin_tx, pin_rx), &mut afio.mapr, serial::Config::default() .baudrate(115200_u32.bps()) .stopbits(serial::StopBits::STOP1) .wordlength_8bits() .parity_none(), &clocks, ); // 将串行结构拆分为接收和发送部分 let (mut tx, mut _rx) = serial.split(); let number = 103; writeln!(tx,"Hello formatted string {}", number).unwrap(); // 将系统计时器配置为每秒触发一次更新 let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz(); // 设置定时器的频率1Hz timer.start(1.Hz()).unwrap(); // 等待计时器触发更新并更改LED的状态, 每秒钟切换 LED 状态(高电平/低电平)。 for _i in 0..3 { // 等待定时器 block!(timer.wait()).unwrap(); // 设置高电平 device.set_led(true); block!(timer.wait()).unwrap(); // 设置低电平 device.set_led(false); } device.set_led(false); // 创建任务 Task::new().name("hello").stack_size(128).priority(TaskPriority(2)).start(move |_| { loop { freertos_rust::CurrentTask::delay(Duration::ms(100)); tx.bwrite_all(b"led hight").unwrap(); device.set_led(true); freertos_rust::CurrentTask::delay(Duration::ms(100)); tx.bwrite_all(b"led low").unwrap(); device.set_led(false); } }).unwrap(); // 启动系统任务调度 Task::new().name("hello").stack_size(128).priority(TaskPriority(2)).start(task_function).unwrap(); FreeRtosUtils::start_scheduler(); } #[exception] unsafe fn DefaultHandler(_irqn: i16) { // custom default handler // irqn is negative for Cortex-M exceptions // irqn is positive for device specific (line IRQ) // set_led(true);(true); // panic!("Exception: {}", irqn); } #[exception] unsafe fn HardFault(_ef: &ExceptionFrame) -> ! { loop { // 在这里添加遇到 HardFault 时希望执行的代码 } } // define what happens in an Out Of Memory (OOM) condition #[alloc_error_handler] fn alloc_error(_layout: Layout) -> ! { asm::bkpt(); loop { // 在这里添加遇到 error 时希望执行的代码 } } #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop { // 在这里添加遇到 panic 时希望执行的代码 } } 编译烧录 项目编译

  在项目根目录下执行如下指令进行进行编译并转换为 Hex 文件用于烧录

# 编译整个项目 cargo build --package freertos-rust-examples --example stm32-cortex-m3 --target thumbv7m-none-eabi --release # 删除ELF执行文件中的符号表 cargo strip --target thumbv7m-none-eabi --example stm32-cortex-m3 --release # ELF文件转Hex文件用于stm32f103烧录 cargo objcopy --example stm32-cortex-m3 --target thumbv7m-none-eabi -- -O ihex stm32-cortex-m3.hex 固件烧录

  从 Linux 环境拷贝出 stm32-cortex-m3.hex 文件到 window 环境,然后使用 Keil、STM32 ST-LINK Utility 等方式进行烧录即可,具体方法请自行百度。

总结:

  FreeRTOS-rust 项目基于 FreeRTOS 内核源码构建安全的 rust 应用开发环境,要比一些使用纯 rust 重新开发 FreeRTOS 的项目更加贴合实际,对比的优点主要有以下部分:

使用 C语言的 FreeRTOS 内核源码要比使用 rust 重新开发的内核源码至少在体积上小 3倍左右。使用 C语言的 FreeRTOS 内核源码稳定性更好,因为开源版本已经经过了无数轮的迭代和问题修复。使用 C语言的 FreeRTOS 内核源码这种方式目前在实际项目应用中更具有可行性,因为大部分嵌入式项目的底座还是 C的。   但是在获取 rust 内存安全特性的同时也会带来一些问题:应用层使用 rust 开发,FreeRTOS 内核源码依然是C语言的,这部分代码 rust 的安全机制无法进行追踪,如果出现问题,更加难以排查。目前在嵌入式领域很多优秀的开源 C 语言组件还没有实现 rust 重写,应用层如果想完全使用 rust 开发,目前还存在一些难度,当然 rust 项目也可以使用之前的 C库组件。使用 rust 开发应用程序不可避免的需要进行外设操作甚至是MCU的寄存器操作,目前嵌入式芯片的底层 rust 驱动库不够多,很多芯片没有 rust 的底层驱动库,类似与 stm32 的 ARM 系列芯片虽然已经有底层驱动库,但是版本还在迭代,使用起来不是特别方便。使用 rust 进行应用层开发,代码的体积是需要首先考虑的事情,一般来说,同样功能的实现,rust 代码体积至少比 C代码体积大2~3倍。

🌀路西法 的个人博客拥有更多美文等你来读。

标签:

FreeRTOS-rust食用指南由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“FreeRTOS-rust食用指南