11//! Blocking I2C API
22//!
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`.
46//!
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 { }
7117
8118/// Blocking read
9- pub trait Read {
119+ pub trait Read < A : AddressMode = SevenBitAddress > {
10120 /// Error type
11121 type Error ;
12122
@@ -28,15 +138,15 @@ pub trait Read {
28138 /// - `MAK` = master acknowledge
29139 /// - `NMAK` = master no acknowledge
30140 /// - `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 > ;
32142}
33143
34144/// Blocking write
35- pub trait Write {
145+ pub trait Write < A : AddressMode = SevenBitAddress > {
36146 /// Error type
37147 type Error ;
38148
39- /// Sends bytes to slave with address `addr `
149+ /// Writes bytes to slave with address `address `
40150 ///
41151 /// # I2C Events (contract)
42152 ///
@@ -52,31 +162,30 @@ pub trait Write {
52162 /// - `SAK` = slave acknowledge
53163 /// - `Bi` = ith byte of data
54164 /// - `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 > ;
56166}
57167
58168/// Blocking write (iterator version)
59- #[ cfg( feature = "unproven" ) ]
60- pub trait WriteIter {
169+ pub trait WriteIter < A : AddressMode = SevenBitAddress > {
61170 /// Error type
62171 type Error ;
63172
64- /// Sends bytes to slave with address `addr `
173+ /// Writes bytes to slave with address `address `
65174 ///
66175 /// # I2C Events (contract)
67176 ///
68177 /// 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 >
70179 where
71180 B : IntoIterator < Item = u8 > ;
72181}
73182
74183/// Blocking write + read
75- pub trait WriteRead {
184+ pub trait WriteRead < A : AddressMode = SevenBitAddress > {
76185 /// Error type
77186 type Error ;
78187
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
80189 /// single transaction*
81190 ///
82191 /// # I2C Events (contract)
@@ -100,30 +209,89 @@ pub trait WriteRead {
100209 /// - `SP` = stop condition
101210 fn write_read (
102211 & mut self ,
103- address : u8 ,
212+ address : A ,
104213 bytes : & [ u8 ] ,
105214 buffer : & mut [ u8 ] ,
106215 ) -> Result < ( ) , Self :: Error > ;
107216}
108217
109218/// Blocking write (iterator version) + read
110- #[ cfg( feature = "unproven" ) ]
111- pub trait WriteIterRead {
219+ pub trait WriteIterRead < A : AddressMode = SevenBitAddress > {
112220 /// Error type
113221 type Error ;
114222
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
116224 /// single transaction*
117225 ///
118226 /// # I2C Events (contract)
119227 ///
120228 /// Same as the `WriteRead` trait
121229 fn write_iter_read < B > (
122230 & mut self ,
123- address : u8 ,
231+ address : A ,
124232 bytes : B ,
125233 buffer : & mut [ u8 ] ,
126234 ) -> Result < ( ) , Self :: Error >
127235 where
128236 B : IntoIterator < Item = u8 > ;
129237}
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