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