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

$ 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, /// 0x04 - PLL configuration register pub pllcfgr: ::volatile::ReadWrite, /// 0x08 - clock configuration register pub cfgr: ::volatile::ReadWrite, /// 0x0c - clock interrupt register pub cir: ::volatile::ReadWrite, /// 0x10 - AHB1 peripheral reset register pub ahb1rstr: ::volatile::ReadWrite, (..) ```

API

The svd_codegen generates the following API for each peripheral:

Register block

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

``` rust /// Inter-integrated circuit

[repr(C)]

pub struct I2c1 { /// 0x00 - Control register 1 pub cr1: ::volatile::ReadWrite, /// 0x04 - Control register 2 pub cr2: ::volatile::ReadWrite, /// 0x08 - Own address register 1 pub oar1: ::volatile::ReadWrite, /// 0x0c - Own address register 2 pub oar2: ::volatile::ReadWrite, /// 0x10 - Timing register pub timingr: ::volatile::ReadWrite, /// 0x14 - Status register 1 pub timeoutr: ::volatile::ReadWrite, /// 0x18 - Interrupt and Status register pub isr: ::volatile::ReadWrite, /// 0x1c - Interrupt clear register pub icr: ::volatile::WriteOnly, /// 0x20 - PEC register pub pecr: ::volatile::ReadOnly, /// 0x24 - Receive data register pub rxdr: ::volatile::ReadOnly, /// 0x28 - Transmit data register pub txdr: ::volatile::ReadWrite, } ```

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

rust 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:

ld /* 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.

``` rust // 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:

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.