Skip to content

Generate Rust register maps (`struct`s) from SVD files

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

f-bro/svd_codegen

This branch is up to date with embed-rs/svd_codegen:master.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

2431b09 · Nov 20, 2016

History

55 Commits
Nov 10, 2016
Nov 20, 2016
Nov 8, 2016
Nov 10, 2016
Nov 20, 2016
Nov 20, 2016
Oct 9, 2016
Oct 9, 2016
Nov 10, 2016
Nov 10, 2016
Oct 15, 2016

Repository files navigation

crates.io docs.rs

svd_codegen

Generate Rust register maps (structs) from SVD files

This is a fork of japaric/svd2rust that generates a slightly different API.

Usage

  • Get the start address of each peripheral register block.
$ 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;
(..)
  • Generate a register map for a single peripheral.
$ 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

The svd_codegen generates the following API for each peripheral:

Register block

A register block "definition" as a struct. Example below:

/// 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>,
}

The user has to "instantiate" this definition for each peripheral instance. They have several choices:

  • statics and/or static muts. Example below:
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;
}

Where the addresses of these register blocks must be provided by a linker script:

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

This has the side effect that the I2C1 and I2C2 symbols get "taken" so no other C/Rust symbol (static, function, etc.) can have the same name.

  • "constructor" functions. Example, equivalent to the static one, below:
// 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

Each register in the register block, e.g. the cr1 field in the I2c struct, is wrapped in a volatile wrapper that exposes some methods:

  • read-only registers only expose the read method.
  • write-only registers only expose the write method.
  • read-write registers exposes all the methods: read, write, and update.

The read method performs a single, volatile LDR instruction and the write method performs a single, volatile STR instruction. The update method takes a closure that modifies the register. It performs a read, passes the value to the closure and writes the modified value back:

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

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

Generate Rust register maps (`struct`s) from SVD files

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Rust 78.0%
  • Shell 15.2%
  • PowerShell 6.8%