1
1
//! Blocking I2C API
2
2
//!
3
- //! Slave addresses used by this API are 7-bit I2C addresses ranging from 0 to 127.
3
+ //! This API supports 7-bit and 10-bit addresses. Traits feature an `AddressMode`
4
+ //! marker type parameter. Two implementation of the `AddressMode` exist:
5
+ //! `SevenBitAddress` and `TenBitAddress`.
4
6
//!
5
- //! Operations on 10-bit slave addresses are not supported by the API yet (but applications might
6
- //! be able to emulate some operations).
7
+ //! Through this marker types it is possible to implement each address mode for
8
+ //! the traits independently in `embedded-hal` implementations and device drivers
9
+ //! can depend only on the mode that they support.
10
+ //!
11
+ //! Additionally, the I2C 10-bit address mode has been developed to be fully
12
+ //! backwards compatible with the 7-bit address mode. This allows for a
13
+ //! software-emulated 10-bit addressing implementation if the address mode
14
+ //! is not supported by the hardware.
15
+ //!
16
+ //! Since 7-bit addressing is the mode of the majority of I2C devices,
17
+ //! `SevenBitAddress` has been set as default mode and thus can be omitted if desired.
18
+ //!
19
+ //! ## Examples
20
+ //!
21
+ //! ### `embedded-hal` implementation for an MCU
22
+ //! Here is an example of an embedded-hal implementation of the `Write` trait
23
+ //! for both modes:
24
+ //! ```
25
+ //! # use embedded_hal::blocking::i2c::{SevenBitAddress, TenBitAddress, Write};
26
+ //! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing.
27
+ //! pub struct I2c0;
28
+ //!
29
+ //! impl Write<SevenBitAddress> for I2c0
30
+ //! {
31
+ //! # type Error = ();
32
+ //! #
33
+ //! fn write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> {
34
+ //! // ...
35
+ //! # Ok(())
36
+ //! }
37
+ //! }
38
+ //!
39
+ //! impl Write<TenBitAddress> for I2c0
40
+ //! {
41
+ //! # type Error = ();
42
+ //! #
43
+ //! fn write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> {
44
+ //! // ...
45
+ //! # Ok(())
46
+ //! }
47
+ //! }
48
+ //! ```
49
+ //!
50
+ //! ### Device driver compatible only with 7-bit addresses
51
+ //!
52
+ //! For demonstration purposes the address mode parameter has been omitted in this example.
53
+ //!
54
+ //! ```
55
+ //! # use embedded_hal::blocking::i2c::WriteRead;
56
+ //! const ADDR: u8 = 0x15;
57
+ //! # const TEMP_REGISTER: u8 = 0x1;
58
+ //! pub struct TemperatureSensorDriver<I2C> {
59
+ //! i2c: I2C,
60
+ //! }
61
+ //!
62
+ //! impl<I2C, E> TemperatureSensorDriver<I2C>
63
+ //! where
64
+ //! I2C: WriteRead<Error = E>,
65
+ //! {
66
+ //! pub fn read_temperature(&mut self) -> Result<u8, E> {
67
+ //! let mut temp = [0];
68
+ //! self.i2c
69
+ //! .write_read(ADDR, &[TEMP_REGISTER], &mut temp)
70
+ //! .and(Ok(temp[0]))
71
+ //! }
72
+ //! }
73
+ //! ```
74
+ //!
75
+ //! ### Device driver compatible only with 10-bit addresses
76
+ //!
77
+ //! ```
78
+ //! # use embedded_hal::blocking::i2c::{TenBitAddress, WriteRead};
79
+ //! const ADDR: u16 = 0x158;
80
+ //! # const TEMP_REGISTER: u8 = 0x1;
81
+ //! pub struct TemperatureSensorDriver<I2C> {
82
+ //! i2c: I2C,
83
+ //! }
84
+ //!
85
+ //! impl<I2C, E> TemperatureSensorDriver<I2C>
86
+ //! where
87
+ //! I2C: WriteRead<TenBitAddress, Error = E>,
88
+ //! {
89
+ //! pub fn read_temperature(&mut self) -> Result<u8, E> {
90
+ //! let mut temp = [0];
91
+ //! self.i2c
92
+ //! .write_read(ADDR, &[TEMP_REGISTER], &mut temp)
93
+ //! .and(Ok(temp[0]))
94
+ //! }
95
+ //! }
96
+ //! ```
97
+
98
+ use crate :: private;
99
+
100
+ impl private:: Sealed for SevenBitAddress { }
101
+ impl private:: Sealed for TenBitAddress { }
102
+
103
+ /// Address mode (7-bit / 10-bit)
104
+ ///
105
+ /// Note: This trait is sealed and should not be implemented outside of this crate.
106
+ pub trait AddressMode : private:: Sealed { }
107
+
108
+ /// 7-bit address mode type
109
+ pub type SevenBitAddress = u8 ;
110
+
111
+ /// 10-bit address mode type
112
+ pub type TenBitAddress = u16 ;
113
+
114
+ impl AddressMode for SevenBitAddress { }
115
+
116
+ impl AddressMode for TenBitAddress { }
7
117
8
118
/// Blocking read
9
- pub trait Read {
119
+ pub trait Read < A : AddressMode = SevenBitAddress > {
10
120
/// Error type
11
121
type Error ;
12
122
@@ -28,15 +138,15 @@ pub trait Read {
28
138
/// - `MAK` = master acknowledge
29
139
/// - `NMAK` = master no acknowledge
30
140
/// - `SP` = stop condition
31
- fn read ( & mut self , address : u8 , buffer : & mut [ u8 ] ) -> Result < ( ) , Self :: Error > ;
141
+ fn read ( & mut self , address : A , buffer : & mut [ u8 ] ) -> Result < ( ) , Self :: Error > ;
32
142
}
33
143
34
144
/// Blocking write
35
- pub trait Write {
145
+ pub trait Write < A : AddressMode = SevenBitAddress > {
36
146
/// Error type
37
147
type Error ;
38
148
39
- /// Sends bytes to slave with address `addr `
149
+ /// Writes bytes to slave with address `address `
40
150
///
41
151
/// # I2C Events (contract)
42
152
///
@@ -52,31 +162,30 @@ pub trait Write {
52
162
/// - `SAK` = slave acknowledge
53
163
/// - `Bi` = ith byte of data
54
164
/// - `SP` = stop condition
55
- fn write ( & mut self , addr : u8 , bytes : & [ u8 ] ) -> Result < ( ) , Self :: Error > ;
165
+ fn write ( & mut self , address : A , bytes : & [ u8 ] ) -> Result < ( ) , Self :: Error > ;
56
166
}
57
167
58
168
/// Blocking write (iterator version)
59
- #[ cfg( feature = "unproven" ) ]
60
- pub trait WriteIter {
169
+ pub trait WriteIter < A : AddressMode = SevenBitAddress > {
61
170
/// Error type
62
171
type Error ;
63
172
64
- /// Sends bytes to slave with address `addr `
173
+ /// Writes bytes to slave with address `address `
65
174
///
66
175
/// # I2C Events (contract)
67
176
///
68
177
/// Same as `Write`
69
- fn write < B > ( & mut self , addr : u8 , bytes : B ) -> Result < ( ) , Self :: Error >
178
+ fn write < B > ( & mut self , address : A , bytes : B ) -> Result < ( ) , Self :: Error >
70
179
where
71
180
B : IntoIterator < Item = u8 > ;
72
181
}
73
182
74
183
/// Blocking write + read
75
- pub trait WriteRead {
184
+ pub trait WriteRead < A : AddressMode = SevenBitAddress > {
76
185
/// Error type
77
186
type Error ;
78
187
79
- /// Sends bytes to slave with address `addr ` and then reads enough bytes to fill `buffer` *in a
188
+ /// Writes bytes to slave with address `address ` and then reads enough bytes to fill `buffer` *in a
80
189
/// single transaction*
81
190
///
82
191
/// # I2C Events (contract)
@@ -100,30 +209,89 @@ pub trait WriteRead {
100
209
/// - `SP` = stop condition
101
210
fn write_read (
102
211
& mut self ,
103
- address : u8 ,
212
+ address : A ,
104
213
bytes : & [ u8 ] ,
105
214
buffer : & mut [ u8 ] ,
106
215
) -> Result < ( ) , Self :: Error > ;
107
216
}
108
217
109
218
/// Blocking write (iterator version) + read
110
- #[ cfg( feature = "unproven" ) ]
111
- pub trait WriteIterRead {
219
+ pub trait WriteIterRead < A : AddressMode = SevenBitAddress > {
112
220
/// Error type
113
221
type Error ;
114
222
115
- /// Sends bytes to slave with address `addr ` and then reads enough bytes to fill `buffer` *in a
223
+ /// Writes bytes to slave with address `address ` and then reads enough bytes to fill `buffer` *in a
116
224
/// single transaction*
117
225
///
118
226
/// # I2C Events (contract)
119
227
///
120
228
/// Same as the `WriteRead` trait
121
229
fn write_iter_read < B > (
122
230
& mut self ,
123
- address : u8 ,
231
+ address : A ,
124
232
bytes : B ,
125
233
buffer : & mut [ u8 ] ,
126
234
) -> Result < ( ) , Self :: Error >
127
235
where
128
236
B : IntoIterator < Item = u8 > ;
129
237
}
238
+
239
+ /// Transactional I2C operation.
240
+ ///
241
+ /// Several operations can be combined as part of a transaction.
242
+ #[ derive( Debug , PartialEq ) ]
243
+ pub enum Operation < ' a > {
244
+ /// Read data into the provided buffer
245
+ Read ( & ' a mut [ u8 ] ) ,
246
+ /// Write data from the provided buffer
247
+ Write ( & ' a [ u8 ] ) ,
248
+ }
249
+
250
+ /// Transactional I2C interface.
251
+ ///
252
+ /// This allows combining operations within an I2C transaction.
253
+ pub trait Transactional < A : AddressMode = SevenBitAddress > {
254
+ /// Error type
255
+ type Error ;
256
+
257
+ /// Execute the provided operations on the I2C bus.
258
+ ///
259
+ /// Transaction contract:
260
+ /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate.
261
+ /// - Data from adjacent operations of the same type are sent after each other without an SP or SR.
262
+ /// - Between adjacent operations of a different type an SR and SAD+R/W is sent.
263
+ /// - After executing the last operation an SP is sent automatically.
264
+ /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte.
265
+ ///
266
+ /// - `ST` = start condition
267
+ /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing
268
+ /// - `SR` = repeated start condition
269
+ /// - `SP` = stop condition
270
+ fn exec < ' a > ( & mut self , address : A , operations : & mut [ Operation < ' a > ] )
271
+ -> Result < ( ) , Self :: Error > ;
272
+ }
273
+
274
+ /// Transactional I2C interface (iterator version).
275
+ ///
276
+ /// This allows combining operation within an I2C transaction.
277
+ pub trait TransactionalIter < A : AddressMode = SevenBitAddress > {
278
+ /// Error type
279
+ type Error ;
280
+
281
+ /// Execute the provided operations on the I2C bus (iterator version).
282
+ ///
283
+ /// Transaction contract:
284
+ /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate.
285
+ /// - Data from adjacent operations of the same type are sent after each other without an SP or SR.
286
+ /// - Between adjacent operations of a different type an SR and SAD+R/W is sent.
287
+ /// - After executing the last operation an SP is sent automatically.
288
+ /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte.
289
+ ///
290
+ /// - `ST` = start condition
291
+ /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing
292
+ /// - `SR` = repeated start condition
293
+ /// - `SP` = stop condition
294
+ fn exec_iter < ' a , O > ( & mut self , address : A , operations : O ) -> Result < ( ) , Self :: Error >
295
+ where
296
+ O : IntoIterator < Item = Operation < ' a > > ;
297
+ }
0 commit comments