svd_codegen
Generate Rust register maps (
struct
s) from SVD files
This is a fork of japaric/svd2rust that generates a slightly different 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
/// Reset and clock control
pub struct Rcc {
/// 0x00 - clock control register
pub cr: ::volatile::ReadWrite
The svd_codegen
generates the following API for each peripheral:
A register block "definition" as a struct
. Example below:
``` rust /// Inter-integrated circuit
pub struct I2c1 {
/// 0x00 - Control register 1
pub cr1: ::volatile::ReadWrite
The user has to "instantiate" this definition for each peripheral instance. They have several choices:
static
s and/or static mut
s. Example below: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.
static
one, below:``` 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:
read
method.write
method.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);
}
Licensed under either of
at your option.
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.