You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
230: Make I2C compatible with multiple address sizes r=ryankurte a=eldruin
This adds I2C 7-bit and 10-bit address mode compatibility as roughly described [here](#147 (comment)).
Discussion issue: #147
I have also added the `SevenBitAddress` as the default address mode to the traits so this is not even a breaking change.
Usage broken down per use case:
* **Device driver which only supports 7-bit addressing mode:**
The driver looks exactly the same as now since the default address mode is 7-bit.
```rust
impl<I2C, E> MyDriver<I2C>
where I2C: i2c::Write<Error = E> {
pub fn do_cool_stuff(&mut self) // ...
}
```
* **Device driver which only supports 10-bit addressing mode:**
The only difference to a 7-bit-address-only driver is one additional parameter in the I2C trait bound.
```rust
impl<I2C, E> MyDriver<I2C>
where I2C: i2c::Write<TenBitAddress, Error = E> {
pub fn do_cool_stuff(&mut self) // ...
}
```
* **Driver for device supporting both addressing modes:**
Complexity can be abstracted away into additional internal traits which can handle the addressing stuff. Driver code stays clean.
**This is nothing new**. We already do this on drivers for devices compatible with both I2C and SPI. No need for duplicated code.
Here a real example: [usage](https://github.com/eldruin/bmi160-rs/blob/3af5637f1df047bb811a4885525cfbe8b44d8ede/src/device_impl.rs#L43), [traits](https://github.com/eldruin/bmi160-rs/blob/master/src/interface.rs)
```rust
impl<DI, E> MyDriver<DI>
where DI: WriteData<Error = E> {
pub fn do_cool_stuff(&mut self) {} // ...
}
pub trait WriteData {
// ...
}
// it is also possible to just leave the `SevenBitAddress` type out here,
// since it is the default.
impl<I2C, E> WriteData for I2cInterface<I2C, SevenBitAddress>
where
I2C: i2c::Write<SevenBitAddress, Error = E>,
{
// ...
}
impl<I2C, E> WriteData for I2cInterface<I2C, TenBitAddress>
where
I2C: i2c::Write<TenBitAddress, Error = E>,
{
// ...
}
```
* **Bus controller impl supporting only 7-bit addressing mode:**
Code stays almost the same, just adding one addressing mode parameter. Additionally, _if desired_:
* 10-bit addressing can be software-emulated:
Emulate by extending and copying payload in separate `TenBitAddress` implementation. Total flexibility to do whatever is necessary in this case since the code is independent.
* 10-bit addressing cannot be software-emulated:
Implementation does not offer implementation for `TenBitAddress` variant. The user gets a compilation error and everything is clear.
* **Bus controller impl supporting both addressing modes:**
No problem. Two separate implementations guarantee as much flexibility as necessary. At the same time, sharing generic code is possible.
Additional benefits:
* No runtime performance cost
* No runtime switching, duplicated code or panics for unsupported modes.
* Consistent with what we do for code paths that can be determined statically by the compiler.
* To my taste elegant, simple and very descriptive.
See [here](#147 (comment)) for a comparison to other alternatives.
I have also sealed the trait.
## Proof
* A HAL implementation of both modes: [bitbang-hal](https://github.com/eldruin/bitbang-hal/tree/i2c-multi-address-mode). [code changes](eldruin/bitbang-hal@embedded-hal-1.0.0-alpha.1...eldruin:i2c-multi-address-mode)
* Drivers supporting only 7-bit addresses need **no changes**.
For demonstration purposes, explicitly including the `SevenBitAddress` would look like this: [OPT300x](https://github.com/eldruin/opt300x-rs/tree/i2c-multi-address-mode). [code changes](https://github.com/eldruin/opt300x-rs/compare/i2c-multi-address-mode).
This would be similar to the case of a 10-bit-only device driver.
Co-authored-by: Diego Barrios Romero <[email protected]>
0 commit comments