#register #map #generator #arm #cortex-m

bin+lib svd_codegen

从 SVD 文件生成 Rust 寄存器映射(struct

5 个版本 (3 个重大变更)

使用旧 Rust 2015

0.4.0 2016 年 11 月 20 日
0.3.0 2016 年 11 月 14 日
0.2.1 2016 年 11 月 14 日
0.1.1 2016 年 11 月 10 日

#114#register

每月 21 次下载
用于 svd_board

MIT/Apache 许可

22KB
485

crates.io docs.rs

svd_codegen

从 SVD 文件生成 Rust 寄存器映射(struct

这是 japaric/svd2rust 的一个分支,生成了一个略有不同的 API。

用法

  • 获取每个外设寄存器块的起始地址。
$ svd_codegen -i STM32F30x.svd
const GPIOA: usize = 0x48000000;
const GPIOB: usize = 0x48000400;
const GPIOC: usize = 0x48000800;
const GPIOD: usize = 0x48000c00;
const GPIOE: usize = 0x48001000;
const GPIOF: usize = 0x48001400;
(..)
  • 为单个外设生成寄存器映射。
$ svd_codegen -i STM32F30x.svd rcc | head
#[repr(C)]
/// Reset and clock control
pub struct Rcc {
    /// 0x00 - clock control register
    pub cr: ::volatile::ReadWrite<Cr>,
    /// 0x04 - PLL configuration register
    pub pllcfgr: ::volatile::ReadWrite<Pllcfgr>,
    /// 0x08 - clock configuration register
    pub cfgr: ::volatile::ReadWrite<Cfgr>,
    /// 0x0c - clock interrupt register
    pub cir: ::volatile::ReadWrite<Cir>,
    /// 0x10 - AHB1 peripheral reset register
    pub ahb1rstr: ::volatile::ReadWrite<Ahb1rstr>,
(..)

API

svd_codegen 为每个外设生成以下 API

寄存器块

寄存器块“定义”作为 struct。以下是一个示例

/// Inter-integrated circuit
#[repr(C)]
pub struct I2c1 {
    /// 0x00 - Control register 1
    pub cr1: ::volatile::ReadWrite<Cr1>,
    /// 0x04 - Control register 2
    pub cr2: ::volatile::ReadWrite<Cr2>,
    /// 0x08 - Own address register 1
    pub oar1: ::volatile::ReadWrite<Oar1>,
    /// 0x0c - Own address register 2
    pub oar2: ::volatile::ReadWrite<Oar2>,
    /// 0x10 - Timing register
    pub timingr: ::volatile::ReadWrite<Timingr>,
    /// 0x14 - Status register 1
    pub timeoutr: ::volatile::ReadWrite<Timeoutr>,
    /// 0x18 - Interrupt and Status register
    pub isr: ::volatile::ReadWrite<Isr>,
    /// 0x1c - Interrupt clear register
    pub icr: ::volatile::WriteOnly<Icr>,
    /// 0x20 - PEC register
    pub pecr: ::volatile::ReadOnly<Pecr>,
    /// 0x24 - Receive data register
    pub rxdr: ::volatile::ReadOnly<Rxdr>,
    /// 0x28 - Transmit data register
    pub txdr: ::volatile::ReadWrite<Txdr>,
}

用户必须为每个外设实例“实例化”此定义。他们有多种选择

  • static 和/或 static mut。以下是一个示例
extern "C" {
    // I2C1 can be accessed in read-write mode
    pub static mut I2C1: I2c;
    // whereas I2C2 can only be accessed in "read-only" mode
    pub static I2C1: I2c;
}

这些寄存器块的地址必须由链接脚本提供

/* layout.ld */
I2C1 = 0x40005400;
I2C2 = 0x40005800;

这会导致 I2C1I2C2 符号被“占用”,因此其他 C/Rust 符号(staticfunction 等)不能有相同的名称。

  • “构造函数”函数。例如,相当于以下 static 之一
// Addresses of the register blocks. These are private.
const I2C1: usize = 0x40005400;
const I2C2: usize = 0x40005800;

// NOTE(unsafe) can alias references to mutable memory
pub unsafe fn i2c1() -> &'mut static I2C {
    unsafe { &mut *(I2C1 as *mut I2c) }
}

pub fn i2c2() -> &'static I2C {
    unsafe { &*(I2C2 as *const I2c) }
}

read / write / update

寄存器块中的每个寄存器,例如 I2c 结构中的 cr1 字段,都封装在一个可变的包装器中,该包装器公开了一些方法

  • 只读寄存器只公开 read 方法。
  • 只写寄存器只公开 write 方法。
  • 读写寄存器公开所有方法:readwriteupdate

read 方法执行单个、可变的 LDR 指令,而 write 方法执行单个、可变的 STR 指令。更新方法接收一个闭包,该闭包修改寄存器。它执行 read,将值传递给闭包,并将修改后的值写回

pub fn update<F>(&mut self, f: F)
    where F: FnOnce(&mut T)
{
    let mut value = self.read();
    f(&mut value);
    self.write(value);
}

许可

根据您的选择,许可如下

贡献

除非您明确声明,否则您按照Apache-2.0许可证定义提交的任何有意贡献,用于包括在工作中的贡献,应如上双授权,不附加任何额外条款或条件。

依赖项

约3MB
约56K SLoC