Skip to content

Commit 7b88d29

Browse files
committed
Support 7-bit and 10-bit I2C address modes
1 parent c2f15c6 commit 7b88d29

File tree

3 files changed

+142
-13
lines changed

3 files changed

+142
-13
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88

99
## [Unreleased]
1010

11+
### Added
12+
- 10-bit addressing mode for I2C traits.
13+
1114
### Changed
15+
- I2C addressing modes are now selected via an `AddressMode` type parameter.
16+
The trait features implementations for marker types `SevenBitAddress` and
17+
`TenBitAddress`. `SevenBitAddress` is the default mode so this is not a
18+
breaking change.
1219
- The method `try_write` from the trait `blocking::i2c::WriteIter` trait
1320
has been renamed `try_write_iter` for consistency.
1421

src/blocking/i2c.rs

Lines changed: 127 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,126 @@
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 try_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 try_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+
//! .try_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+
//! .try_write_read(ADDR, &[TEMP_REGISTER], &mut temp)
93+
//! .and(Ok(temp[0]))
94+
//! }
95+
//! }
96+
//! ```
97+
98+
use crate::private;
99+
100+
/// Address mode (7-bit / 10-bit)
101+
///
102+
/// Note: This trait is sealed and should not be implemented outside of this crate.
103+
pub trait AddressMode: private::Sealed {
104+
/// Address value type
105+
type Address;
106+
}
107+
108+
/// 7-bit address mode type
109+
pub struct SevenBitAddress;
110+
111+
/// 10-bit address mode type
112+
pub struct TenBitAddress;
113+
114+
impl AddressMode for SevenBitAddress {
115+
type Address = u8;
116+
}
117+
118+
impl AddressMode for TenBitAddress {
119+
type Address = u16;
120+
}
7121

8122
/// Blocking read
9-
pub trait Read {
123+
pub trait Read<A: AddressMode = SevenBitAddress> {
10124
/// Error type
11125
type Error;
12126

@@ -28,11 +142,11 @@ pub trait Read {
28142
/// - `MAK` = master acknowledge
29143
/// - `NMAK` = master no acknowledge
30144
/// - `SP` = stop condition
31-
fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error>;
145+
fn try_read(&mut self, address: A::Address, buffer: &mut [u8]) -> Result<(), Self::Error>;
32146
}
33147

34148
/// Blocking write
35-
pub trait Write {
149+
pub trait Write<A: AddressMode = SevenBitAddress> {
36150
/// Error type
37151
type Error;
38152

@@ -52,11 +166,11 @@ pub trait Write {
52166
/// - `SAK` = slave acknowledge
53167
/// - `Bi` = ith byte of data
54168
/// - `SP` = stop condition
55-
fn try_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error>;
169+
fn try_write(&mut self, address: A::Address, bytes: &[u8]) -> Result<(), Self::Error>;
56170
}
57171

58172
/// Blocking write (iterator version)
59-
pub trait WriteIter {
173+
pub trait WriteIter<A: AddressMode = SevenBitAddress> {
60174
/// Error type
61175
type Error;
62176

@@ -65,13 +179,13 @@ pub trait WriteIter {
65179
/// # I2C Events (contract)
66180
///
67181
/// Same as `Write`
68-
fn try_write_iter<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error>
182+
fn try_write_iter<B>(&mut self, address: A::Address, bytes: B) -> Result<(), Self::Error>
69183
where
70184
B: IntoIterator<Item = u8>;
71185
}
72186

73187
/// Blocking write + read
74-
pub trait WriteRead {
188+
pub trait WriteRead<A: AddressMode = SevenBitAddress> {
75189
/// Error type
76190
type Error;
77191

@@ -99,14 +213,14 @@ pub trait WriteRead {
99213
/// - `SP` = stop condition
100214
fn try_write_read(
101215
&mut self,
102-
address: u8,
216+
address: A::Address,
103217
bytes: &[u8],
104218
buffer: &mut [u8],
105219
) -> Result<(), Self::Error>;
106220
}
107221

108222
/// Blocking write (iterator version) + read
109-
pub trait WriteIterRead {
223+
pub trait WriteIterRead<A: AddressMode = SevenBitAddress> {
110224
/// Error type
111225
type Error;
112226

@@ -118,7 +232,7 @@ pub trait WriteIterRead {
118232
/// Same as the `WriteRead` trait
119233
fn try_write_iter_read<B>(
120234
&mut self,
121-
address: u8,
235+
address: A::Address,
122236
bytes: B,
123237
buffer: &mut [u8],
124238
) -> Result<(), Self::Error>

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,3 +700,11 @@ pub mod serial;
700700
pub mod spi;
701701
pub mod timer;
702702
pub mod watchdog;
703+
704+
mod private {
705+
use crate::blocking::i2c::{SevenBitAddress, TenBitAddress};
706+
pub trait Sealed {}
707+
708+
impl Sealed for SevenBitAddress {}
709+
impl Sealed for TenBitAddress {}
710+
}

0 commit comments

Comments
 (0)