svd2rust
Generate Rust register maps (
struct
s) from SVD files
Usage
- Get the start address of each peripheral register block.
$ svd2rust -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.
$ svd2rust -i STM32F30x.svd rcc | head
#[repr(C)]
/// Reset and clock control
pub struct Rcc {
/// Clock control register
pub cr: Cr,
/// Clock configuration register (RCC_CFGR)
pub cfgr: Cfgr,
/// Clock interrupt register (RCC_CIR)
pub cir: Cir,
/// APB2 peripheral reset register (RCC_APB2RSTR)
(..)
API
The svd2rust
generates the following API for each peripheral:
Register block
A register block "definition" as a struct
. Example below:
/// Inter-integrated circuit
The user has to "instantiate" this definition for each peripheral instance. They have several choices:
static
s and/orstatic mut
s. Example below:
extern "C"
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
read
/ modify
/ write
Each register in the register block, e.g. the cr1
field in the I2c
struct, exposes a combination
of the read
, modify
and write
methods. Which methods exposes each register depends on whether
the register is read-only, read-write or write-only:
- read-only registers only expose the
read
method. - write-only registers only expose the
write
method. - read-write registers exposes all the methods:
read
,modify
andwrite
.
This is signature of each of these methods:
(using the CR2
register as an example)
The read
method performs a single, volatile LDR
instruction and returns a proxy Cr2R
struct
which allows access to only the readable bits (i.e. not to the reserved bits) of the CR2
register:
Usage looks like this:
// is the SADD0 bit of the CR2 register set?
if i2c1.c2r.read.sadd0 else
The write
method performs a single, volatile STR
instruction to write a value to the CR2
register. This method involves the Cr2W
struct which only allows constructing valid states of the
CR2
register.
The only constructor that Cr2W
provides is reset_value
which returns the value of the CR2
register after a reset. The rest of Cr2W
methods are "builder" like and can be used to set or
reset the writable bits of the CR2
register.
The write
method takes a closure with signature &mut Cr2W -> &mut Cr2W
. If passed the identity
closure, |w| w
, the write
method will set the CR2
register to its reset value. Otherwise, the
closure specifies how that reset value will be modified before it's written to CR2
.
Usage looks like this:
// Write to CR2, its reset value but with its SADD0 and SADD1 fields set to `true` and `0b0011110`
i2c1.cr2.write;
Finally, the modify
method performs a read-modify-write operation that involves at least one LDR
instruction, one STR
instruction plus extra instructions to modify the fetched value of the CR2
register. This method accepts a closure that specifies how the CR2
register will be modified.
Usage looks like this:
// Toggle the STOP bit of the CR2 register and set the START bit
i2c1.cr2.modify;
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
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.