@@ -38,6 +38,177 @@ pub struct Rcc {
3838(..)
3939```
4040
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+
41212## License
42213
43214Licensed under either of
0 commit comments