14 个版本 (3 个稳定版)
| 1.0.2 | 2021 年 1 月 1 日 |
|---|---|
| 1.0.1 | 2020 年 11 月 27 日 |
| 0.5.1 | 2020 年 5 月 31 日 |
| 0.5.0 | 2020 年 1 月 16 日 |
| 0.1.1 | 2018 年 7 月 16 日 |
#13 in #mmio
每月 105 次下载
用于 2 crates
12KB
90 行
register-rs
Rust 中类型安全的 MMIO 和 CPU 寄存器访问的统一接口。
概述
用法
此 crate 使用 tock-register-interface,请参阅他们的 README 了解完整的 API。请确保查看 register_structs! 的说明,特别是您必须 显式注释间隙 的实际情况。
定义 MMIO 寄存器
use register::{mmio::*, register_bitfields, register_structs};
register_bitfields! {
u32,
GPFSEL1 [
FSEL14 OFFSET(12) NUMBITS(3) [
Input = 0b000,
Output = 0b001,
TXD0 = 0b100
],
FSEL15 OFFSET(15) NUMBITS(3) [
Input = 0b000,
Output = 0b001,
RXD0 = 0b100
]
]
}
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
(0x000 => GPFSEL1: ReadWrite<u32, GPFSEL1::Register>),
(0x004 => SYSTMR_HI: ReadOnly<u32>),
(0x008 => @END),
}
}
fn main() {
let regs = 0x1337_0000 as *const RegisterBlock;
unsafe { (*regs).SYSTMR_HI.get() };
}
驱动程序的 Deref 模式
此 crate 的 MMIO 部分,通常用于实现设备驱动程序。在这种情况下,您可能会发现 Deref 模式 对于引用您的寄存器很有用。它让您不必在每次进行寄存器访问时手动解引用,同时也封装了 unsafe 关键字。
以下是一个示例(扩展上面的代码片段)
register_bitfields! {
u32,
// omitted
}
register_structs! {
#[allow(non_snake_case)]
pub RegisterBlock {
// omitted
}
}
pub struct DeviceDriver {
base_addr: usize,
}
impl ops::Deref for DeviceDriver {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl DeviceDriver {
pub fn new(base_addr: usize) -> Self {
DeviceDriver { base_addr }
}
/// Returns a pointer to the register block
fn ptr(&self) -> *const RegisterBlock {
self.base_addr as *const _
}
fn do_something(&self) -> u32 {
self.GPFSEL1.set(0x1337);
self.SYSTMR_HI.get()
}
}
定义 CPU 寄存器
对于 CPU 寄存器,您只需实现相应的读写特质。所有其他方法默认提供。
#![feature(llvm_asm)]
use register::{cpu::RegisterReadWrite, register_bitfields};
register_bitfields! {u32,
pub CNTP_CTL_EL0 [
/// Enables the timer.
ENABLE OFFSET(0) NUMBITS(1) [],
/// Timer interrupt mask bit.
IMASK OFFSET(1) NUMBITS(1) [],
/// The status of the timer.
ISTATUS OFFSET(2) NUMBITS(1) []
]
}
struct Reg;
impl RegisterReadWrite<u32, CNTP_CTL_EL0::Register> for Reg {
/// Reads the raw bits of the CPU register.
#[inline(always)]
fn get(&self) -> u32 {
let reg;
unsafe {
llvm_asm!("mrs $0, CNTP_CTL_EL0" : "=r"(reg) ::: "volatile");
}
reg
}
/// Writes raw bits to the CPU register.
#[inline(always)]
fn set(&self, value: u32) {
unsafe {
llvm_asm!("msr CNTP_CTL_EL0, $0" :: "r"(value) :: "volatile");
}
}
}
static CNTP_CTL_EL0: Reg = Reg {};
fn main() {
CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET);
}
测试
为了在 custom_test_frameworks 环境中使用此 crate,请在您的依赖部分设置 no_std_unit_tests 特性标志。
否则,您可能会遇到以下错误
error[E0463]: can't find crate for `test`
--> src/bsp/driver/bcm/bcm2xxx_gpio.rs:52:1
|
52 | / register_structs! {
53 | | #[allow(non_snake_case)]
54 | | RegisterBlock {
55 | | (0x00 => GPFSEL0: ReadWrite<u32>),
... |
66 | | }
67 | | }
| |_^ can't find crate
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: aborting due to previous error
许可
许可协议为以下之一
- Apache 许可协议 2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可协议 (LICENSE-MIT 或 https://open-source.org.cn/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则您有意提交的任何贡献,根据 Apache-2.0 许可协议定义,均应双许可,没有额外的条款或条件。
依赖项
~90KB