|
5 | 5 |
|
6 | 6 | > Generate Rust register maps (`struct`s) from SVD files |
7 | 7 |
|
8 | | -## Usage |
| 8 | +# [Documentation](https://docs.rs/svd2rust) |
9 | 9 |
|
10 | | -- Get the start address of each peripheral register block. |
11 | | - |
12 | | -``` |
13 | | -$ svd2rust -i STM32F30x.svd |
14 | | -const GPIOA: usize = 0x48000000; |
15 | | -const GPIOB: usize = 0x48000400; |
16 | | -const GPIOC: usize = 0x48000800; |
17 | | -const GPIOD: usize = 0x48000c00; |
18 | | -const GPIOE: usize = 0x48001000; |
19 | | -const GPIOF: usize = 0x48001400; |
20 | | -(..) |
21 | | -``` |
22 | | - |
23 | | -- Generate a register map for a single peripheral. |
24 | | - |
25 | | -``` |
26 | | -$ svd2rust -i STM32F30x.svd rcc | head |
27 | | -#[repr(C)] |
28 | | -/// Reset and clock control |
29 | | -pub struct Rcc { |
30 | | - /// Clock control register |
31 | | - pub cr: Cr, |
32 | | - /// Clock configuration register (RCC_CFGR) |
33 | | - pub cfgr: Cfgr, |
34 | | - /// Clock interrupt register (RCC_CIR) |
35 | | - pub cir: Cir, |
36 | | - /// APB2 peripheral reset register (RCC_APB2RSTR) |
37 | | -(..) |
38 | | -``` |
39 | | - |
40 | | -## API |
41 | | - |
42 | | -The `svd2rust` generates the following API for each peripheral: |
43 | | - |
44 | | -### Register block |
45 | | - |
46 | | -A register block "definition" as a `struct`. Example below: |
47 | | - |
48 | | -``` rust |
49 | | -/// Inter-integrated circuit |
50 | | -#[repr(C)] |
51 | | -pub struct I2c1 { |
52 | | - /// 0x00 - Control register 1 |
53 | | - pub cr1: Cr1, |
54 | | - /// 0x04 - Control register 2 |
55 | | - pub cr2: Cr2, |
56 | | - /// 0x08 - Own address register 1 |
57 | | - pub oar1: Oar1, |
58 | | - /// 0x0c - Own address register 2 |
59 | | - pub oar2: Oar2, |
60 | | - /// 0x10 - Timing register |
61 | | - pub timingr: Timingr, |
62 | | - /// 0x14 - Status register 1 |
63 | | - pub timeoutr: Timeoutr, |
64 | | - /// 0x18 - Interrupt and Status register |
65 | | - pub isr: Isr, |
66 | | - /// 0x1c - Interrupt clear register |
67 | | - pub icr: Icr, |
68 | | - /// 0x20 - PEC register |
69 | | - pub pecr: Pecr, |
70 | | - /// 0x24 - Receive data register |
71 | | - pub rxdr: Rxdr, |
72 | | - /// 0x28 - Transmit data register |
73 | | - pub txdr: Txdr, |
74 | | -} |
75 | | -``` |
76 | | - |
77 | | -The user has to "instantiate" this definition for each peripheral instance. They have several |
78 | | -choices: |
79 | | - |
80 | | -- `static`s and/or `static mut`s. Example below: |
81 | | - |
82 | | -``` rust |
83 | | -extern "C" { |
84 | | - // I2C1 can be accessed in read-write mode |
85 | | - pub static mut I2C1: I2c; |
86 | | - // whereas I2C2 can only be accessed in "read-only" mode |
87 | | - pub static I2C1: I2c; |
88 | | -} |
89 | | -``` |
90 | | - |
91 | | -Where the addresses of these register blocks must be provided by a linker script: |
92 | | - |
93 | | -``` ld |
94 | | -/* layout.ld */ |
95 | | -I2C1 = 0x40005400; |
96 | | -I2C2 = 0x40005800; |
97 | | -``` |
98 | | - |
99 | | -This has the side effect that the `I2C1` and `I2C2` symbols get "taken" so no other C/Rust symbol |
100 | | -(`static`, `function`, etc.) can have the same name. |
101 | | - |
102 | | -- "constructor" functions. Example, equivalent to the `static` one, below: |
103 | | - |
104 | | -``` rust |
105 | | -// Addresses of the register blocks. These are private. |
106 | | -const I2C1: usize = 0x40005400; |
107 | | -const I2C2: usize = 0x40005800; |
108 | | - |
109 | | -// NOTE(unsafe) can alias references to mutable memory |
110 | | -pub unsafe fn i2c1() -> &'mut static I2C { |
111 | | - unsafe { &mut *(I2C1 as *mut I2c) } |
112 | | -} |
113 | | - |
114 | | -pub fn i2c2() -> &'static I2C { |
115 | | - unsafe { &*(I2C2 as *const I2c) } |
116 | | -} |
117 | | -``` |
118 | | - |
119 | | -### `read` / `modify` / `write` |
120 | | - |
121 | | -Each register in the register block, e.g. the `cr1` field in the `I2c` struct, exposes a combination |
122 | | -of the `read`, `modify` and `write` methods. Which methods exposes each register depends on whether |
123 | | -the register is read-only, read-write or write-only: |
124 | | - |
125 | | -- read-only registers only expose the `read` method. |
126 | | -- write-only registers only expose the `write` method. |
127 | | -- read-write registers exposes all the methods: `read`, `modify` and `write`. |
128 | | - |
129 | | -This is signature of each of these methods: |
130 | | - |
131 | | -(using the `CR2` register as an example) |
132 | | - |
133 | | -``` rust |
134 | | -impl Cr2 { |
135 | | - pub fn modify<F>(&mut self, f: F) |
136 | | - where for<'w> F: FnOnce(&Cr2R, &'w mut Cr2W) -> &'w mut Cr2W |
137 | | - { |
138 | | - .. |
139 | | - } |
140 | | - |
141 | | - pub fn read(&self) -> Cr2R { .. } |
142 | | - |
143 | | - pub fn write<F>(&mut self, f: F) |
144 | | - where F: FnOnce(&mut Cr2W) -> &mut Cr2W, |
145 | | - { |
146 | | - .. |
147 | | - } |
148 | | -} |
149 | | -``` |
150 | | - |
151 | | -The `read` method performs a single, volatile `LDR` instruction and returns a proxy `Cr2R` struct |
152 | | -which allows access to only the readable bits (i.e. not to the reserved bits) of the `CR2` register: |
153 | | - |
154 | | -``` rust |
155 | | -impl Cr2R { |
156 | | - /// Bit 0 - Slave address bit 0 (master mode) |
157 | | - pub fn sadd0(&self) -> bool { .. } |
158 | | - |
159 | | - /// Bits 1:7 - Slave address bit 7:1 (master mode) |
160 | | - pub fn sadd1(&self) -> u8 { .. } |
161 | | - |
162 | | - (..) |
163 | | -} |
164 | | -``` |
165 | | - |
166 | | -Usage looks like this: |
167 | | - |
168 | | -``` rust |
169 | | -// is the SADD0 bit of the CR2 register set? |
170 | | -if i2c1.c2r.read().sadd0() { |
171 | | - // something |
172 | | -} else { |
173 | | - // something else |
174 | | -} |
175 | | -``` |
176 | | - |
177 | | -The `write` method performs a single, volatile `STR` instruction to write a value to the `CR2` |
178 | | -register. This method involves the `Cr2W` struct which only allows constructing valid states of the |
179 | | -`CR2` register. |
180 | | - |
181 | | -The only constructor that `Cr2W` provides is `reset_value` which returns the value of the `CR2` |
182 | | -register after a reset. The rest of `Cr2W` methods are "builder" like and can be used to set or |
183 | | -reset the writable bits of the `CR2` register. |
184 | | - |
185 | | -``` rust |
186 | | -impl Cr2W { |
187 | | - /// Reset value |
188 | | - pub fn reset_value() -> Self { |
189 | | - Cr2W { bits: 0 } |
190 | | - } |
191 | | - |
192 | | - /// Bits 1:7 - Slave address bit 7:1 (master mode) |
193 | | - pub fn sadd1(&mut self, value: u8) -> &mut Self { .. } |
194 | | - |
195 | | - /// Bit 0 - Slave address bit 0 (master mode) |
196 | | - pub fn sadd0(&mut self, value: bool) -> &mut Self { .. } |
197 | | -} |
198 | | -``` |
199 | | - |
200 | | -The `write` method takes a closure with signature `&mut Cr2W -> &mut Cr2W`. If passed the identity |
201 | | -closure, `|w| w`, the `write` method will set the `CR2` register to its reset value. Otherwise, the |
202 | | -closure specifies how that reset value will be modified before it's written to `CR2`. |
203 | | - |
204 | | -Usage looks like this: |
205 | | - |
206 | | -``` rust |
207 | | -// Write to CR2, its reset value but with its SADD0 and SADD1 fields set to `true` and `0b0011110` |
208 | | -i2c1.cr2.write(|w| w.sadd0(true).sadd1(0b0011110)); |
209 | | -``` |
210 | | - |
211 | | -Finally, the `modify` method performs a read-modify-write operation that involves at least one `LDR` |
212 | | -instruction, one `STR` instruction plus extra instructions to modify the fetched value of the `CR2` |
213 | | -register. This method accepts a closure that specifies how the `CR2` register will be modified. |
214 | | - |
215 | | -Usage looks like this: |
216 | | - |
217 | | -``` rust |
218 | | -// Toggle the STOP bit of the CR2 register and set the START bit |
219 | | -i2c1.cr2.modify(|r, w| w.stop(!r.stop()).start(true)); |
220 | | -``` |
| 10 | +# [API](https://docs.rs/svd2rust) |
221 | 11 |
|
222 | 12 | ## License |
223 | 13 |
|
|
0 commit comments