1
+ //! Safe abstractions for an I2C bus.
2
+
1
3
use core:: iter:: TrustedLen ;
2
4
use core:: marker:: PhantomData ;
3
5
use embedded_hal;
@@ -8,17 +10,24 @@ use stm32f7::stm32f7x6::{
8
10
9
11
// TODO use &mut when svd2rust API has changed (modification should require &mut)
10
12
//pub struct I2C<'a>(&'a mut RegisterBlock);
13
+ /// Represents an I2C (Inter-Integrated Circuit) bus.
11
14
pub struct I2C < ' a > ( & ' a RegisterBlock ) ;
12
15
16
+ /// Errors that can happen while accessing the I2C bus.
13
17
#[ derive( Debug ) ]
14
18
pub enum Error {
19
+ /// A NACK flag (negative acknowledgement) was detected.
15
20
Nack ,
16
21
}
17
22
23
+ /// An I2C address.
24
+ ///
25
+ /// Currently only 7 bit addresses are supported.
18
26
#[ derive( Debug , Clone , Copy ) ]
19
27
pub struct Address ( u16 ) ;
20
28
21
29
impl Address {
30
+ /// Create a 7 bit I2C address.
22
31
pub const fn bits_7 ( addr : u8 ) -> Address {
23
32
Address ( ( addr as u16 ) << 1 )
24
33
}
@@ -37,16 +46,26 @@ fn icr_clear_all(w: &mut i2c1::icr::W) -> &mut i2c1::icr::W {
37
46
w
38
47
}
39
48
49
+ /// An active connection to a device on the I2C bus.
50
+ ///
51
+ /// Allows reading and writing the registers of the device.
40
52
pub struct I2cConnection < ' a , ' i : ' a , T : RegisterType > {
41
53
i2c : & ' a mut I2C < ' i > ,
42
54
device_address : Address ,
43
55
register_type : PhantomData < T > ,
44
56
}
45
57
58
+ /// Valid register types of I2C devices.
59
+ ///
60
+ /// This trait is implemented for the `u8` and `u16` types.
46
61
pub trait RegisterType : Sized {
62
+ /// Convert the register type into a byte slice and pass it to the specified closure.
47
63
fn write < F > ( & self , f : F ) -> Result < ( ) , Error >
48
64
where
49
65
F : FnOnce ( & [ u8 ] ) -> Result < ( ) , Error > ;
66
+
67
+ /// Call the specified closure with a mutable reference to a byte slice and then convert it
68
+ /// to the register type.
50
69
fn read < F > ( f : F ) -> Result < Self , Error >
51
70
where
52
71
F : FnOnce ( & mut [ u8 ] ) -> Result < ( ) , Error > ;
@@ -165,6 +184,7 @@ impl<'a, 'i: 'a, T: RegisterType> I2cConnection<'a, 'i, T> {
165
184
self . i2c . 0 . icr . write ( |w| icr_clear_all ( w) ) ;
166
185
}
167
186
187
+ /// Read the current value from the specified register.
168
188
pub fn read ( & mut self , register_address : T ) -> Result < T , Error > {
169
189
self . pre ( ) ;
170
190
@@ -173,6 +193,7 @@ impl<'a, 'i: 'a, T: RegisterType> I2cConnection<'a, 'i, T> {
173
193
T :: read ( |val_bytes| self . read_bytes_raw ( val_bytes. iter_mut ( ) ) )
174
194
}
175
195
196
+ /// Read bytes from the specified register into the specified buffer.
176
197
pub fn read_bytes ( & mut self , register_address : T , bytes : & mut [ u8 ] ) -> Result < ( ) , Error > {
177
198
self . pre ( ) ;
178
199
@@ -181,6 +202,7 @@ impl<'a, 'i: 'a, T: RegisterType> I2cConnection<'a, 'i, T> {
181
202
self . read_bytes_raw ( bytes. iter_mut ( ) )
182
203
}
183
204
205
+ /// Write the specified bytes into to specified register.
184
206
pub fn write ( & mut self , register_address : T , value : T ) -> Result < ( ) , Error > {
185
207
self . pre ( ) ;
186
208
register_address. write ( |addr_bytes| {
@@ -192,6 +214,10 @@ impl<'a, 'i: 'a, T: RegisterType> I2cConnection<'a, 'i, T> {
192
214
}
193
215
194
216
impl < ' a > I2C < ' a > {
217
+ /// Connects to the specified device and run the closure `f` with the connection as argument.
218
+ ///
219
+ /// This function takes an exclusive reference to the `I2C` type because it blocks the I2C
220
+ /// bus. The connection is active until the closure `f` returns.
195
221
pub fn connect < T , F > ( & mut self , device_address : Address , f : F ) -> Result < ( ) , Error >
196
222
where
197
223
T : RegisterType ,
@@ -208,6 +234,7 @@ impl<'a> I2C<'a> {
208
234
self . stop ( )
209
235
}
210
236
237
+ /// Stop the active connection by sending a stop symbol.
211
238
pub fn stop ( & mut self ) -> Result < ( ) , Error > {
212
239
self . 0 . cr2 . modify ( |_, w| w. stop ( ) . set_bit ( ) ) ;
213
240
@@ -217,6 +244,7 @@ impl<'a> I2C<'a> {
217
244
self . wait_for_stop ( )
218
245
}
219
246
247
+ /// Update a device register.
220
248
pub fn update < F > (
221
249
& mut self ,
222
250
device_address : Address ,
@@ -291,7 +319,7 @@ impl<'a> I2C<'a> {
291
319
}
292
320
}
293
321
294
- // provokes a NACK
322
+ /// Provokes a NACK and checks if the response is as expected. Panics otherwise.
295
323
pub fn test_1 ( & mut self ) {
296
324
let i2c = & mut self . 0 ;
297
325
@@ -316,7 +344,7 @@ impl<'a> I2C<'a> {
316
344
i2c. icr . write ( |w| icr_clear_all ( w) ) ;
317
345
}
318
346
319
- // try all addresses
347
+ /// Try to access all I2C addresses. Panics on test failure.
320
348
#[ allow( dead_code) ]
321
349
pub fn test_2 ( & mut self ) {
322
350
let i2c = & mut self . 0 ;
@@ -397,6 +425,12 @@ impl<'a> embedded_hal::blocking::i2c::WriteRead for I2C<'a> {
397
425
}
398
426
}
399
427
428
+ /// Initialize the I2C bus and return an `I2C` type.
429
+ ///
430
+ /// The IC2 type assumes that it has ownership of the I2C buffer. Therefore it is unsafe to access
431
+ /// the passed RegisterBlock as long as the I2C lives. (This function should take a
432
+ /// `&mut RegisterBlock`, but this is not possible due to the API that svd2rust generates. See
433
+ /// [stm32f7-discovery#72](https://github.com/embed-rs/stm32f7-discovery/issues/72) for more info.
400
434
pub fn init < ' a > ( i2c : & ' a RegisterBlock , rcc : & mut RCC ) -> I2C < ' a > {
401
435
// enable clocks
402
436
rcc. apb1enr . modify ( |_, w| w. i2c3en ( ) . enabled ( ) ) ;
0 commit comments