| 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 | //! # Bus sharing |
| 20 | //! |
| 21 | //! I2C allows sharing a single bus between many I2C devices. The SDA and SCL lines are |
| 22 | //! wired in parallel to all devices. When starting a transfer an "address" is sent |
| 23 | //! so that the addressed device can respond and all the others can ignore the transfer. |
| 24 | //! |
| 25 | #![doc = include_str!("i2c-shared-bus.svg" )] |
| 26 | //! |
| 27 | //! This bus sharing is common when having multiple I2C devices in the same board, since it uses fewer MCU |
| 28 | //! pins (`2` instead of `2*n`), and fewer MCU I2C peripherals (`1` instead of `n`). |
| 29 | //! |
| 30 | //! This API supports bus sharing natively. Types implementing [`I2c`] are allowed |
| 31 | //! to represent either exclusive or shared access to an I2C bus. HALs typically |
| 32 | //! provide exclusive access implementations. Drivers shouldn't care which |
| 33 | //! kind they receive, they just do transactions on it and let the |
| 34 | //! underlying implementation share or not. |
| 35 | //! |
| 36 | //! The [`embedded-hal-bus`](https://docs.rs/embedded-hal-bus) crate provides several |
| 37 | //! implementations for sharing I2C buses. You can use them to take an exclusive instance |
| 38 | //! you've received from a HAL and "split" it into multiple shared ones, to instantiate |
| 39 | //! several drivers on the same bus. |
| 40 | //! |
| 41 | //! # Flushing |
| 42 | //! |
| 43 | //! Implementations must flush the transfer, ensuring the bus has returned to an idle state before returning. |
| 44 | //! No pipelining is allowed. Users must be able to shut down the I2C peripheral immediately after a transfer |
| 45 | //! returns, without any risk of e.g. cutting short a stop condition. |
| 46 | //! |
| 47 | //! (Implementations must wait until the last ACK bit to report it as an error anyway. Therefore pipelining would only |
| 48 | //! yield very small time savings, not worth the complexity) |
| 49 | //! |
| 50 | //! # For driver authors |
| 51 | //! |
| 52 | //! Drivers can select the adequate address length with `I2c<SevenBitAddress>` or `I2c<TenBitAddress>` depending |
| 53 | //! on the target device. If it can use either, the driver can |
| 54 | //! be generic over the address kind as well, though this is rare. |
| 55 | //! |
| 56 | //! Drivers should take the `I2c` instance as an argument to `new()`, and store it in their |
| 57 | //! struct. They **should not** take `&mut I2c`, the trait has a blanket impl for all `&mut T` |
| 58 | //! so taking just `I2c` ensures the user can still pass a `&mut`, but is not forced to. |
| 59 | //! |
| 60 | //! Drivers **should not** try to enable bus sharing by taking `&mut I2c` at every method. |
| 61 | //! This is much less ergonomic than owning the `I2c`, which still allows the user to pass an |
| 62 | //! implementation that does sharing behind the scenes |
| 63 | //! (from [`embedded-hal-bus`](https://docs.rs/embedded-hal-bus), or others). |
| 64 | //! |
| 65 | //! ## Device driver compatible only with 7-bit addresses |
| 66 | //! |
| 67 | //! For demonstration purposes the address mode parameter has been omitted in this example. |
| 68 | //! |
| 69 | //! ``` |
| 70 | //! use embedded_hal::i2c::{I2c, Error}; |
| 71 | //! |
| 72 | //! const ADDR: u8 = 0x15; |
| 73 | //! # const TEMP_REGISTER: u8 = 0x1; |
| 74 | //! pub struct TemperatureSensorDriver<I2C> { |
| 75 | //! i2c: I2C, |
| 76 | //! } |
| 77 | //! |
| 78 | //! impl<I2C: I2c> TemperatureSensorDriver<I2C> { |
| 79 | //! pub fn new(i2c: I2C) -> Self { |
| 80 | //! Self { i2c } |
| 81 | //! } |
| 82 | //! |
| 83 | //! pub fn read_temperature(&mut self) -> Result<u8, I2C::Error> { |
| 84 | //! let mut temp = [0]; |
| 85 | //! self.i2c.write_read(ADDR, &[TEMP_REGISTER], &mut temp)?; |
| 86 | //! Ok(temp[0]) |
| 87 | //! } |
| 88 | //! } |
| 89 | //! ``` |
| 90 | //! |
| 91 | //! ## Device driver compatible only with 10-bit addresses |
| 92 | //! |
| 93 | //! ``` |
| 94 | //! use embedded_hal::i2c::{Error, TenBitAddress, I2c}; |
| 95 | //! |
| 96 | //! const ADDR: u16 = 0x158; |
| 97 | //! # const TEMP_REGISTER: u8 = 0x1; |
| 98 | //! pub struct TemperatureSensorDriver<I2C> { |
| 99 | //! i2c: I2C, |
| 100 | //! } |
| 101 | //! |
| 102 | //! impl<I2C: I2c<TenBitAddress>> TemperatureSensorDriver<I2C> { |
| 103 | //! pub fn new(i2c: I2C) -> Self { |
| 104 | //! Self { i2c } |
| 105 | //! } |
| 106 | //! |
| 107 | //! pub fn read_temperature(&mut self) -> Result<u8, I2C::Error> { |
| 108 | //! let mut temp = [0]; |
| 109 | //! self.i2c.write_read(ADDR, &[TEMP_REGISTER], &mut temp)?; |
| 110 | //! Ok(temp[0]) |
| 111 | //! } |
| 112 | //! } |
| 113 | //! ``` |
| 114 | //! |
| 115 | //! # For HAL authors |
| 116 | //! |
| 117 | //! HALs **should not** include bus sharing mechanisms. They should expose a single type representing |
| 118 | //! exclusive ownership over the bus, and let the user use [`embedded-hal-bus`](https://docs.rs/embedded-hal-bus) |
| 119 | //! if they want to share it. (One exception is if the underlying platform already |
| 120 | //! supports sharing, such as Linux or some RTOSs.) |
| 121 | //! |
| 122 | //! Here is an example of an embedded-hal implementation of the `I2C` trait |
| 123 | //! for both addressing modes. All trait methods have have default implementations in terms of `transaction`. |
| 124 | //! As such, that is the only method that requires implementation in the HAL. |
| 125 | //! |
| 126 | //! ``` |
| 127 | //! use embedded_hal::i2c::{self, SevenBitAddress, TenBitAddress, I2c, Operation}; |
| 128 | //! |
| 129 | //! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing. |
| 130 | //! pub struct I2c0; |
| 131 | //! |
| 132 | //! #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 133 | //! pub enum Error { |
| 134 | //! // ... |
| 135 | //! } |
| 136 | //! |
| 137 | //! impl i2c::Error for Error { |
| 138 | //! fn kind(&self) -> i2c::ErrorKind { |
| 139 | //! match *self { |
| 140 | //! // ... |
| 141 | //! } |
| 142 | //! } |
| 143 | //! } |
| 144 | //! |
| 145 | //! impl i2c::ErrorType for I2c0 { |
| 146 | //! type Error = Error; |
| 147 | //! } |
| 148 | //! |
| 149 | //! impl I2c<SevenBitAddress> for I2c0 { |
| 150 | //! fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { |
| 151 | //! // ... |
| 152 | //! # Ok(()) |
| 153 | //! } |
| 154 | //! } |
| 155 | //! |
| 156 | //! impl I2c<TenBitAddress> for I2c0 { |
| 157 | //! fn transaction(&mut self, address: u16, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { |
| 158 | //! // ... |
| 159 | //! # Ok(()) |
| 160 | //! } |
| 161 | //! } |
| 162 | //! ``` |
| 163 | |
| 164 | use crate::private; |
| 165 | |
| 166 | #[cfg (feature = "defmt-03" )] |
| 167 | use crate::defmt; |
| 168 | |
| 169 | /// I2C error. |
| 170 | pub trait Error: core::fmt::Debug { |
| 171 | /// Convert error to a generic I2C error kind. |
| 172 | /// |
| 173 | /// By using this method, I2C errors freely defined by HAL implementations |
| 174 | /// can be converted to a set of generic I2C errors upon which generic |
| 175 | /// code can act. |
| 176 | fn kind(&self) -> ErrorKind; |
| 177 | } |
| 178 | |
| 179 | impl Error for core::convert::Infallible { |
| 180 | #[inline ] |
| 181 | fn kind(&self) -> ErrorKind { |
| 182 | match *self {} |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | /// I2C error kind. |
| 187 | /// |
| 188 | /// This represents a common set of I2C operation errors. HAL implementations are |
| 189 | /// free to define more specific or additional error types. However, by providing |
| 190 | /// a mapping to these common I2C errors, generic code can still react to them. |
| 191 | #[derive (Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] |
| 192 | #[cfg_attr (feature = "defmt-03" , derive(defmt::Format))] |
| 193 | #[non_exhaustive ] |
| 194 | pub enum ErrorKind { |
| 195 | /// Bus error occurred. e.g. A START or a STOP condition is detected and is not |
| 196 | /// located after a multiple of 9 SCL clock pulses. |
| 197 | Bus, |
| 198 | /// The arbitration was lost, e.g. electrical problems with the clock signal. |
| 199 | ArbitrationLoss, |
| 200 | /// A bus operation was not acknowledged, e.g. due to the addressed device not |
| 201 | /// being available on the bus or the device not being ready to process requests |
| 202 | /// at the moment. |
| 203 | NoAcknowledge(NoAcknowledgeSource), |
| 204 | /// The peripheral receive buffer was overrun. |
| 205 | Overrun, |
| 206 | /// A different error occurred. The original error may contain more information. |
| 207 | Other, |
| 208 | } |
| 209 | |
| 210 | /// I2C no acknowledge error source. |
| 211 | /// |
| 212 | /// In cases where it is possible, a device should indicate if a no acknowledge |
| 213 | /// response was received to an address versus a no acknowledge to a data byte. |
| 214 | /// Where it is not possible to differentiate, `Unknown` should be indicated. |
| 215 | #[derive (Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] |
| 216 | #[cfg_attr (feature = "defmt-03" , derive(defmt::Format))] |
| 217 | pub enum NoAcknowledgeSource { |
| 218 | /// The device did not acknowledge its address. The device may be missing. |
| 219 | Address, |
| 220 | /// The device did not acknowledge the data. It may not be ready to process |
| 221 | /// requests at the moment. |
| 222 | Data, |
| 223 | /// Either the device did not acknowledge its address or the data, but it is |
| 224 | /// unknown which. |
| 225 | Unknown, |
| 226 | } |
| 227 | |
| 228 | impl Error for ErrorKind { |
| 229 | #[inline ] |
| 230 | fn kind(&self) -> ErrorKind { |
| 231 | *self |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | impl core::fmt::Display for ErrorKind { |
| 236 | #[inline ] |
| 237 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
| 238 | match self { |
| 239 | Self::Bus => write!(f, "Bus error occurred" ), |
| 240 | Self::ArbitrationLoss => write!(f, "The arbitration was lost" ), |
| 241 | Self::NoAcknowledge(s: &NoAcknowledgeSource) => s.fmt(f), |
| 242 | Self::Overrun => write!(f, "The peripheral receive buffer was overrun" ), |
| 243 | Self::Other => write!( |
| 244 | f, |
| 245 | "A different error occurred. The original error may contain more information" |
| 246 | ), |
| 247 | } |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | impl core::fmt::Display for NoAcknowledgeSource { |
| 252 | #[inline ] |
| 253 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
| 254 | match self { |
| 255 | Self::Address => write!(f, "The device did not acknowledge its address" ), |
| 256 | Self::Data => write!(f, "The device did not acknowledge the data" ), |
| 257 | Self::Unknown => write!(f, "The device did not acknowledge its address or the data" ), |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | /// I2C error type trait. |
| 263 | /// |
| 264 | /// This just defines the error type, to be used by the other traits. |
| 265 | pub trait ErrorType { |
| 266 | /// Error type |
| 267 | type Error: Error; |
| 268 | } |
| 269 | |
| 270 | impl<T: ErrorType + ?Sized> ErrorType for &mut T { |
| 271 | type Error = T::Error; |
| 272 | } |
| 273 | |
| 274 | /// Address mode (7-bit / 10-bit). |
| 275 | /// |
| 276 | /// Note: This trait is sealed and should not be implemented outside of this crate. |
| 277 | pub trait AddressMode: private::Sealed + 'static {} |
| 278 | |
| 279 | /// 7-bit address mode type. |
| 280 | /// |
| 281 | /// Note that 7-bit addresses defined by drivers should be specified in **right-aligned** form, |
| 282 | /// e.g. in the range `0x00..=0x7F`. |
| 283 | /// |
| 284 | /// For example, a device that has the seven bit address of `0b011_0010`, and therefore is addressed on the wire using: |
| 285 | /// |
| 286 | /// * `0b0110010_0` or `0x64` for *writes* |
| 287 | /// * `0b0110010_1` or `0x65` for *reads* |
| 288 | /// |
| 289 | /// Should be specified as `0b0011_0010` or `0x32`, NOT `0x64` or `0x65`. Care should be taken by both HAL and driver |
| 290 | /// crate writers to use this scheme consistently. |
| 291 | pub type SevenBitAddress = u8; |
| 292 | |
| 293 | /// 10-bit address mode type. |
| 294 | pub type TenBitAddress = u16; |
| 295 | |
| 296 | impl AddressMode for SevenBitAddress {} |
| 297 | |
| 298 | impl AddressMode for TenBitAddress {} |
| 299 | |
| 300 | /// I2C operation. |
| 301 | /// |
| 302 | /// Several operations can be combined as part of a transaction. |
| 303 | #[derive (Debug, PartialEq, Eq)] |
| 304 | #[cfg_attr (feature = "defmt-03" , derive(defmt::Format))] |
| 305 | pub enum Operation<'a> { |
| 306 | /// Read data into the provided buffer. |
| 307 | Read(&'a mut [u8]), |
| 308 | /// Write data from the provided buffer. |
| 309 | Write(&'a [u8]), |
| 310 | } |
| 311 | |
| 312 | /// Blocking I2C. |
| 313 | pub trait I2c<A: AddressMode = SevenBitAddress>: ErrorType { |
| 314 | /// Reads enough bytes from slave with `address` to fill `read`. |
| 315 | /// |
| 316 | /// # I2C Events (contract) |
| 317 | /// |
| 318 | /// ``` text |
| 319 | /// Master: ST SAD+R MAK MAK ... NMAK SP |
| 320 | /// Slave: SAK B0 B1 ... BN |
| 321 | /// ``` |
| 322 | /// |
| 323 | /// Where |
| 324 | /// |
| 325 | /// - `ST` = start condition |
| 326 | /// - `SAD+R` = slave address followed by bit 1 to indicate reading |
| 327 | /// - `SAK` = slave acknowledge |
| 328 | /// - `Bi` = ith byte of data |
| 329 | /// - `MAK` = master acknowledge |
| 330 | /// - `NMAK` = master no acknowledge |
| 331 | /// - `SP` = stop condition |
| 332 | #[inline ] |
| 333 | fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { |
| 334 | self.transaction(address, &mut [Operation::Read(read)]) |
| 335 | } |
| 336 | |
| 337 | /// Writes bytes to slave with address `address`. |
| 338 | /// |
| 339 | /// # I2C Events (contract) |
| 340 | /// |
| 341 | /// ``` text |
| 342 | /// Master: ST SAD+W B0 B1 ... BN SP |
| 343 | /// Slave: SAK SAK SAK ... SAK |
| 344 | /// ``` |
| 345 | /// |
| 346 | /// Where |
| 347 | /// |
| 348 | /// - `ST` = start condition |
| 349 | /// - `SAD+W` = slave address followed by bit 0 to indicate writing |
| 350 | /// - `SAK` = slave acknowledge |
| 351 | /// - `Bi` = ith byte of data |
| 352 | /// - `SP` = stop condition |
| 353 | #[inline ] |
| 354 | fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { |
| 355 | self.transaction(address, &mut [Operation::Write(write)]) |
| 356 | } |
| 357 | |
| 358 | /// Writes bytes to slave with address `address` and then reads enough bytes to fill `read` *in a |
| 359 | /// single transaction*. |
| 360 | /// |
| 361 | /// # I2C Events (contract) |
| 362 | /// |
| 363 | /// ``` text |
| 364 | /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP |
| 365 | /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN |
| 366 | /// ``` |
| 367 | /// |
| 368 | /// Where |
| 369 | /// |
| 370 | /// - `ST` = start condition |
| 371 | /// - `SAD+W` = slave address followed by bit 0 to indicate writing |
| 372 | /// - `SAK` = slave acknowledge |
| 373 | /// - `Oi` = ith outgoing byte of data |
| 374 | /// - `SR` = repeated start condition |
| 375 | /// - `SAD+R` = slave address followed by bit 1 to indicate reading |
| 376 | /// - `Ii` = ith incoming byte of data |
| 377 | /// - `MAK` = master acknowledge |
| 378 | /// - `NMAK` = master no acknowledge |
| 379 | /// - `SP` = stop condition |
| 380 | #[inline ] |
| 381 | fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |
| 382 | self.transaction( |
| 383 | address, |
| 384 | &mut [Operation::Write(write), Operation::Read(read)], |
| 385 | ) |
| 386 | } |
| 387 | |
| 388 | /// Execute the provided operations on the I2C bus. |
| 389 | /// |
| 390 | /// Transaction contract: |
| 391 | /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. |
| 392 | /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. |
| 393 | /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. |
| 394 | /// - After executing the last operation an SP is sent automatically. |
| 395 | /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. |
| 396 | /// |
| 397 | /// - `ST` = start condition |
| 398 | /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing |
| 399 | /// - `SR` = repeated start condition |
| 400 | /// - `SP` = stop condition |
| 401 | fn transaction( |
| 402 | &mut self, |
| 403 | address: A, |
| 404 | operations: &mut [Operation<'_>], |
| 405 | ) -> Result<(), Self::Error>; |
| 406 | } |
| 407 | |
| 408 | impl<A: AddressMode, T: I2c<A> + ?Sized> I2c<A> for &mut T { |
| 409 | #[inline ] |
| 410 | fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { |
| 411 | T::read(self, address, read) |
| 412 | } |
| 413 | |
| 414 | #[inline ] |
| 415 | fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { |
| 416 | T::write(self, address, write) |
| 417 | } |
| 418 | |
| 419 | #[inline ] |
| 420 | fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |
| 421 | T::write_read(self, address, write, read) |
| 422 | } |
| 423 | |
| 424 | #[inline ] |
| 425 | fn transaction( |
| 426 | &mut self, |
| 427 | address: A, |
| 428 | operations: &mut [Operation<'_>], |
| 429 | ) -> Result<(), Self::Error> { |
| 430 | T::transaction(self, address, operations) |
| 431 | } |
| 432 | } |
| 433 | |