Skip to content

Commit 7199533

Browse files
bors[bot]burrbull
andauthored
Merge #301
301: Backport non-breaking changes from v1.0 to v0.2.x r=eldruin a=burrbull Co-authored-by: Andrey Zgarbul <[email protected]>
2 parents 7dc440c + 769b933 commit 7199533

File tree

6 files changed

+302
-19
lines changed

6 files changed

+302
-19
lines changed

CHANGELOG.md

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

1010
### Added
1111

12+
- `Transactional` SPI interface for executing groups of SPI transactions.
13+
- `Transactional` I2C interface for executing groups of I2C transactions.
14+
- 10-bit addressing mode for I2C traits.
15+
- `set_state` method for `OutputPin` using an input `PinState` value.
16+
- `IoPin` trait for pins that can change between being inputs or outputs
17+
dynamically.
1218

1319
### Changed
1420

src/blocking/i2c.rs

Lines changed: 187 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,122 @@
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+
}

src/blocking/spi.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,24 @@ pub mod write_iter {
104104
}
105105
}
106106
}
107+
108+
/// Operation for transactional SPI trait
109+
///
110+
/// This allows composition of SPI operations into a single bus transaction
111+
#[derive(Debug, PartialEq)]
112+
pub enum Operation<'a, W: 'static> {
113+
/// Write data from the provided buffer, discarding read data
114+
Write(&'a [W]),
115+
/// Write data out while reading data into the provided buffer
116+
Transfer(&'a mut [W]),
117+
}
118+
119+
/// Transactional trait allows multiple actions to be executed
120+
/// as part of a single SPI transaction
121+
pub trait Transactional<W: 'static> {
122+
/// Associated error type
123+
type Error;
124+
125+
/// Execute the provided transactions
126+
fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
127+
}

0 commit comments

Comments
 (0)