#kernel-module #beaglebone #pru #pruss

prusst

为TI可编程实时单元提供方便的UIO内核模块接口

2 个版本 (1 个稳定版)

使用旧的Rust 2015

1.0.0 2017年11月18日
0.1.0 2016年8月8日

#273 in 操作系统

Download history 6/week @ 2024-02-19 34/week @ 2024-02-26 8/week @ 2024-03-04 5/week @ 2024-03-11

每月下载 53 次

MIT/Apache

49KB
697 代码行数(不含注释)

prusst

Build Status

为BeagleBone开发板等设备上的TI可编程实时单元协处理器提供方便的Rust接口。它提供与C prussdrv库大致相同的功能,但具有更安全、更Rust风格的API,旨在减轻与未初始化或无效寄存器状态、已释放内存的使用、内存分配冲突等相关的风险。

文档

API文档位于此处

背景

PRUs(可编程实时单元)是集成在某些TI处理器(如AM335x,为BeagleBone::{White, Black, Green}开发板供电)中的RISC核心。它们是区分BeagleBone与其他流行单板计算机的特点,允许在没有外部协处理器的复杂性的情况下进行实时过程控制。

PRUs可以直接访问一些通用I/O引脚,也可以通过互连总线间接访问内存和外围设备。它们的可预测的单周期指令执行和没有流水线或缓存使其特别适合实时处理。

由于PRU汇编语言简单,并能够完全控制执行时间,因此可以直接在PRU上用汇编语言编程关键实时任务,与主机处理器合作进行重负载操作(预处理和后处理、通信等)。

目前有两种从主机处理器与PRU通信的选项,即UIO和remoteproc内核模块。UIO内核模块提供对PRU子系统的低级访问,通常更适合基于指令周期计数的精确执行时间纯汇编PRU代码。remoteproc内核模块则更适合在C语言中进行的较高层次和稍微更便携的PRU编程,但由于消息传递机制的开销,它不太适合确定性和紧密的实时控制。

此库在UIO内核模块之上提供了一个相对简单的抽象,使得执行诸如在PRU上执行代码、在PRU和主机处理器之间传输数据或触发/等待系统事件等常见操作变得容易。

设计理念

该库的设计利用了Rust类型系统来减少自射的风险。其架构旨在提供比C语言相对较好的用户体验,同时以类似低级别的抽象程度运行,并提供等效的功能。

通过检查同一时间只有一个Pruss实例(PRU子系统的视图)正在运行来保证数据竞争安全。Rust借用规则的魔力将静态地确保,包括但不限于

  • 本地和共享PRU RAM不存在内存别名,这意味着在释放它包含的数据之前,之前分配的RAM段可能不会被重用,

  • 在代码实际加载之前无法请求在PRU核心上执行代码,

  • 无法覆盖已加载并仍在使用的PRU代码,

  • 无法同时修改中断映射。

类型安全也避免了与中断管理相关的许多陷阱。与C语言的prussdrv库不同,系统事件、主机中断、事件输出和通道都是不同的类型:它们不能被误用或意外地在函数调用中切换。相关的好处是,中断管理API非常直观。

事件处理是prusst要求用户比C语言prussdrv库更明确的一个少数地方。的确,C驱动程序的prussdrv_pru_clear_event函数在清除触发系统事件后自动重新启用事件输出,这可能会错误地暗示组合清除-启用操作是线程安全的(它不是)。相比之下,prusst强制要求在需要再次捕获事件输出时,必须调用Intc::clear_sysevtIntc::enable_host。这种行为可能不那么令人惊讶,并且可以说是与其他中断管理函数的原子性更一致。

系统先决条件

必须在您的系统上加载UIO内核模块。从2017年5月及以后发布的debian "Stretch"主分支版本可以轻松配置,通过remoteproc或UIO访问PRU。

首先,必须通过编辑/boot/uEnv.txt来选择UIO覆盖,例如

...
# uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-4-TI-00A0.dtbo
...
uboot_overlay_pru=/lib/firmware/AM335X-PRU-UIO-00A0.dtbo
...

然后,必须通过编辑或创建包含以下内容的/etc/modprobe.d/pruss-blacklist.conf来将remoteproc模块列入黑名单

blacklist pruss
blacklist pruss_intc
blacklist pru_rproc

如果一切顺利,重启后应该会看到UIO内核模块

$ lsmod | grep uio
uio_pruss               4629  0
uio_pdrv_genirq         4243  0
uio                    11100  2 uio_pruss,uio_pdrv_genirq

安装

只需将crate添加到项目的Cargo.toml

[dependencies]
prusst = "1.0"

prusst 1.0需要rust 1.21或更高版本。

如果您不能使用rust 1.21,不用担心:只需使用prusst 0.1!我相信您会没事的。

API没有改变:版本号增加主要是为了表明原始设计经受了时间的考验。尽管1.0确实包含了一个等待rust 1.21的修复(编译器屏障支持),但这个问题非常假设,不太可能影响您。

交叉编译

如果留有足够的空闲空间,本机Rust工具链可以在BeagleBone debian发行版上完美运行。《IoT》debian镜像是一个不错的选择。

但正如预期的那样,编译会慢一些。

交叉编译可以为您节省很多麻烦,而且非常简单,归功于rustup.rs。有关使用rustup.rs安装ARM v7目标的分步指南,请参阅rust交叉编译圣经

你好世界

extern crate prusst;

use prusst::{Pruss, IntcConfig, Sysevt, Evtout};
use std::fs::File;

fn main() {
    // Configure and get a view of the PRU subsystem.
    let mut pruss = Pruss::new(&IntcConfig::new_populated()).unwrap();
    
    // Get a handle to an event out before it is triggered.
    let irq = pruss.intc.register_irq(Evtout::E0);

    // Open, load and run a PRU binary.
    let mut file = File::open("hello.bin").unwrap();
    unsafe { pruss.pru0.load_code(&mut file).unwrap().run(); }
    
    // Wait for the PRU code from hello.bin to trigger an event out.
    irq.wait();
    
    // Clear the triggering interrupt.
    pruss.intc.clear_sysevt(Sysevt::S19);

    // Do nothing: the `pruss` destructor will stop any running code and release ressources.
    println!("We are done...");
}

示例

示例中展示了库的更高级使用,例如PRU RAM分配、PRU之间的双向通信、并发管理中断等。

假设已经在本地上传了prusst软件包,运行示例前的第一步是编译PRU汇编代码。这可以通过pasm汇编器或clpru编译器来完成。前者已不再维护,但可以作为am335x-pru-package的一部分获取。
然而,今天最好的选择可能是使用clpru编译器,该编译器现在包含在主线的BeagleBone发行版中,并由TI积极维护。请注意,汇编器的语法略有不同,因此为每个PRU示例代码提供了两个版本,一个用于pasm(在pasm目录中的.pasm文件)和一个用于clpru(在asm目录中的.asm文件)。

要使用clpru构建示例PRU二进制文件,请

$ cd examples
$ make asm

同样,要使用pasm构建二进制文件,请

$ cd examples
$ make pasm

如果你启用了cape-universal(对于相对较新的发行版,这应该是默认的),PRU已经默认配置。然后你可以立即使用barebone_blinkbarebone_parallel_blink示例闪烁USR BeagleBone LED(需要在crate根目录下运行,否则PRU二进制文件将无法找到)

$ cargo run --example barebone_blink

pwm_generator示例需要更多的设置,因为它使用了PRU特权的GPIO(pr1_pru0_pru_r30_1,即BeagleBone上的P9_29引脚)。

在BeagleBone Black和其他配备HDMI的板上,所有PRU特权引脚默认保留用于HDMI,因此需要首先在/boot/uEnv.txt中禁用HDMI,取消以下行的注释(请注意,这实际上禁用了HDMI视频和音频)

disable_uboot_overlay_video=1

重启后,可以使用以下命令将引脚P9_29配置为PRU输出引脚

$ config-pin P9.29 pruout

然后PWM示例就可以启动了

$ cargo run --example pwm_generator

这将生成一个8位PWM正弦波,具有可配置的频率和振幅,使用恒定的78431Hz PWM切换频率。

如果你没有BeagleBone和/或PRU启用覆盖,你可以在examples目录中安装提供的prusst-examples覆盖。此覆盖启用PRU子系统和BeagleBone引脚P9_29作为PRU输出引脚。

覆盖的编译和安装方法如下

$ dtc -O dtb -o examples/prusst-examples-00A0.dtbo -b 0 -@ examples/prusst-examples.dts
$ sudo cp examples/prusst-examples-00A0.dtbo /lib/firmware

要激活它,编辑/boot/uEnv.txt

重要提示:如果你使用prusst-examples覆盖,请注意它与BeagleBone Black和其他配备HDMI的板上的HDMI不兼容。为了避免任何问题,在启动时不应加载任何启用HDMI的cape。

许可证

本软件根据你的选择,许可在Apache许可证,版本2.0MIT许可证下。

版权(c)2017 Serge Barral。

这个库是以法国小说家Marcel Prusst(1871-1922)的名字命名的。嗯,差不多。

依赖关系