|
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