aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2021-03-02 15:09:47 -0600
committerxoviat <[email protected]>2021-03-02 15:09:47 -0600
commit492f7aeea6c309a0a8e60fb2028278fb906164cb (patch)
tree7ac9ce0ea58932c8a090890a3b548ca622fedb1b
parent88946840d1f6fdc924a4f0a9980d17f1d2c456fa (diff)
add i2c trait
-rw-r--r--embassy-traits/src/i2c.rs409
-rw-r--r--embassy-traits/src/lib.rs2
2 files changed, 411 insertions, 0 deletions
diff --git a/embassy-traits/src/i2c.rs b/embassy-traits/src/i2c.rs
new file mode 100644
index 000000000..bd8c72ab5
--- /dev/null
+++ b/embassy-traits/src/i2c.rs
@@ -0,0 +1,409 @@
1//! Blocking I2C API
2//!
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`.
6//!
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
98use core::future::Future;
99
100mod private {
101 pub trait Sealed {}
102}
103
104/// Address mode (7-bit / 10-bit)
105///
106/// Note: This trait is sealed and should not be implemented outside of this crate.
107pub trait AddressMode: private::Sealed {}
108
109/// 7-bit address mode type
110pub type SevenBitAddress = u8;
111
112/// 10-bit address mode type
113pub type TenBitAddress = u16;
114
115impl private::Sealed for SevenBitAddress {}
116impl private::Sealed for TenBitAddress {}
117
118impl AddressMode for SevenBitAddress {}
119
120impl AddressMode for TenBitAddress {}
121
122/// Blocking read
123pub trait Read<A: AddressMode = SevenBitAddress> {
124 /// Error type
125 type Error;
126
127 type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
128
129 /// Reads enough bytes from slave with `address` to fill `buffer`
130 ///
131 /// # I2C Events (contract)
132 ///
133 /// ``` text
134 /// Master: ST SAD+R MAK MAK ... NMAK SP
135 /// Slave: SAK B0 B1 ... BN
136 /// ```
137 ///
138 /// Where
139 ///
140 /// - `ST` = start condition
141 /// - `SAD+R` = slave address followed by bit 1 to indicate reading
142 /// - `SAK` = slave acknowledge
143 /// - `Bi` = ith byte of data
144 /// - `MAK` = master acknowledge
145 /// - `NMAK` = master no acknowledge
146 /// - `SP` = stop condition
147 fn read<'a>(&mut self, address: A, buffer: &mut [u8]) -> Self::ReadFuture<'a>;
148}
149
150/// Blocking write
151pub trait Write<A: AddressMode = SevenBitAddress> {
152 /// Error type
153 type Error;
154
155 type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
156
157 /// Sends bytes to slave with address `address`
158 ///
159 /// # I2C Events (contract)
160 ///
161 /// ``` text
162 /// Master: ST SAD+W B0 B1 ... BN SP
163 /// Slave: SAK SAK SAK ... SAK
164 /// ```
165 ///
166 /// Where
167 ///
168 /// - `ST` = start condition
169 /// - `SAD+W` = slave address followed by bit 0 to indicate writing
170 /// - `SAK` = slave acknowledge
171 /// - `Bi` = ith byte of data
172 /// - `SP` = stop condition
173 fn write<'a>(&mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>;
174}
175
176/// Blocking write (iterator version)
177pub trait WriteIter<A: AddressMode = SevenBitAddress> {
178 /// Error type
179 type Error;
180
181 type WriteIterFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
182
183 /// Sends bytes to slave with address `address`
184 ///
185 /// # I2C Events (contract)
186 ///
187 /// Same as `Write`
188 fn write_iter<'a, B>(&mut self, address: A, bytes: B) -> Self::WriteIterFuture<'a>
189 where
190 B: IntoIterator<Item = u8>;
191}
192
193/// Blocking write + read
194pub trait WriteRead<A: AddressMode = SevenBitAddress> {
195 /// Error type
196 type Error;
197
198 type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
199
200 /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
201 /// single transaction*
202 ///
203 /// # I2C Events (contract)
204 ///
205 /// ``` text
206 /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP
207 /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN
208 /// ```
209 ///
210 /// Where
211 ///
212 /// - `ST` = start condition
213 /// - `SAD+W` = slave address followed by bit 0 to indicate writing
214 /// - `SAK` = slave acknowledge
215 /// - `Oi` = ith outgoing byte of data
216 /// - `SR` = repeated start condition
217 /// - `SAD+R` = slave address followed by bit 1 to indicate reading
218 /// - `Ii` = ith incoming byte of data
219 /// - `MAK` = master acknowledge
220 /// - `NMAK` = master no acknowledge
221 /// - `SP` = stop condition
222 fn write_read<'a>(
223 &mut self,
224 address: A,
225 bytes: &[u8],
226 buffer: &mut [u8],
227 ) -> Self::WriteReadFuture<'a>;
228}
229
230/// Blocking write (iterator version) + read
231pub trait WriteIterRead<A: AddressMode = SevenBitAddress> {
232 /// Error type
233 type Error;
234
235 type WriteIterReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
236
237 /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
238 /// single transaction*
239 ///
240 /// # I2C Events (contract)
241 ///
242 /// Same as the `WriteRead` trait
243 fn write_iter_read<'a, B>(
244 &mut self,
245 address: A,
246 bytes: B,
247 buffer: &mut [u8],
248 ) -> Self::WriteIterReadFuture<'a>
249 where
250 B: IntoIterator<Item = u8>;
251}
252
253/// Transactional I2C operation.
254///
255/// Several operations can be combined as part of a transaction.
256#[derive(Debug, PartialEq)]
257pub enum Operation<'a> {
258 /// Read data into the provided buffer
259 Read(&'a mut [u8]),
260 /// Write data from the provided buffer
261 Write(&'a [u8]),
262}
263
264/// Transactional I2C interface.
265///
266/// This allows combining operations within an I2C transaction.
267pub trait Transactional<A: AddressMode = SevenBitAddress> {
268 /// Error type
269 type Error;
270
271 type TransactionalFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
272
273 /// Execute the provided operations on the I2C bus.
274 ///
275 /// Transaction contract:
276 /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate.
277 /// - Data from adjacent operations of the same type are sent after each other without an SP or SR.
278 /// - Between adjacent operations of a different type an SR and SAD+R/W is sent.
279 /// - After executing the last operation an SP is sent automatically.
280 /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte.
281 ///
282 /// - `ST` = start condition
283 /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing
284 /// - `SR` = repeated start condition
285 /// - `SP` = stop condition
286 fn exec<'a>(
287 &mut self,
288 address: A,
289 operations: &mut [Operation<'a>],
290 ) -> Self::TransactionalFuture<'a>;
291}
292
293/// Transactional I2C interface (iterator version).
294///
295/// This allows combining operation within an I2C transaction.
296pub trait TransactionalIter<A: AddressMode = SevenBitAddress> {
297 /// Error type
298 type Error;
299
300 type TransactionalIterFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
301
302 /// Execute the provided operations on the I2C bus (iterator version).
303 ///
304 /// Transaction contract:
305 /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate.
306 /// - Data from adjacent operations of the same type are sent after each other without an SP or SR.
307 /// - Between adjacent operations of a different type an SR and SAD+R/W is sent.
308 /// - After executing the last operation an SP is sent automatically.
309 /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte.
310 ///
311 /// - `ST` = start condition
312 /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing
313 /// - `SR` = repeated start condition
314 /// - `SP` = stop condition
315 fn exec_iter<'a, O>(&mut self, address: A, operations: O) -> Self::TransactionalIterFuture<'a>
316 where
317 O: IntoIterator<Item = Operation<'a>>;
318}
319
320/// Default implementation of `blocking::i2c::Write`, `blocking::i2c::Read` and
321/// `blocking::i2c::WriteRead` traits for `blocking::i2c::Transactional` implementers.
322///
323/// If you implement `blocking::i2c::Transactional` for your I2C peripheral,
324/// you can use this default implementation so that you do not need to implement
325/// the `blocking::i2c::Write`, `blocking::i2c::Read` and `blocking::i2c::WriteRead`
326/// traits as well.
327/// ```
328/// use embedded_hal::blocking::i2c;
329///
330/// struct I2c1;
331///
332/// impl i2c::Transactional<i2c::SevenBitAddress> for I2c1 {
333/// # type Error = ();
334/// fn try_exec<'a>(
335/// &mut self,
336/// address: i2c::SevenBitAddress,
337/// operations: &mut [i2c::Operation<'a>],
338/// ) -> Result<(), Self::Error> {
339/// // ...
340/// # Ok(())
341/// }
342/// }
343///
344/// // This is all you need to do:
345/// impl i2c::transactional::Default<i2c::SevenBitAddress> for I2c1 {};
346///
347/// // Then you can use `Write` and so on:
348/// use i2c::Write;
349///
350/// let mut i2c1 = I2c1{};
351/// i2c1.try_write(0x01, &[0xAB, 0xCD]).unwrap();
352/// ```
353pub mod transactional {
354 use core::future::Future;
355
356 use super::{AddressMode, Operation, Read, Transactional, Write, WriteRead};
357
358 /// Default implementation of `blocking::i2c::Write`, `blocking::i2c::Read` and
359 /// `blocking::i2c::WriteRead` traits for `blocking::i2c::Transactional` implementers.
360 pub trait Default<A: AddressMode>: Transactional<A> {}
361
362 // impl<A, E, S> Write<A> for S
363 // where
364 // A: AddressMode + 'static,
365 // S: self::Default<A> + Transactional<A, Error = E> + 'static,
366 // E: 'static,
367 // {
368 // type Error = E;
369 //
370 // type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a;
371 //
372 // fn write<'a>(&mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a> {
373 // self.exec(address, &mut [Operation::Write(bytes)])
374 // }
375 // }
376 /*
377 impl<A, E, S> Read<A> for S
378 where
379 A: AddressMode,
380 S: self::Default<A> + Transactional<A, Error = E>,
381 {
382 type Error = E;
383
384 fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> {
385 self.exec(address, &mut [Operation::Read(buffer)])
386 }
387 }
388
389 impl<A, E, S> WriteRead<A> for S
390 where
391 A: AddressMode,
392 S: self::Default<A> + Transactional<A, Error = E>,
393 {
394 type Error = E;
395
396 fn write_read(
397 &mut self,
398 address: A,
399 bytes: &[u8],
400 buffer: &mut [u8],
401 ) -> Result<(), Self::Error> {
402 self.exec(
403 address,
404 &mut [Operation::Write(bytes), Operation::Read(buffer)],
405 )
406 }
407 }
408 */
409}
diff --git a/embassy-traits/src/lib.rs b/embassy-traits/src/lib.rs
index 849bbaec3..10d44d9de 100644
--- a/embassy-traits/src/lib.rs
+++ b/embassy-traits/src/lib.rs
@@ -4,8 +4,10 @@
4#![feature(const_fn_fn_ptr_basics)] 4#![feature(const_fn_fn_ptr_basics)]
5#![feature(const_option)] 5#![feature(const_option)]
6#![allow(incomplete_features)] 6#![allow(incomplete_features)]
7#![feature(type_alias_impl_trait)]
7 8
8pub mod delay; 9pub mod delay;
9pub mod flash; 10pub mod flash;
10pub mod gpio; 11pub mod gpio;
12pub mod i2c;
11pub mod uart; 13pub mod uart;