embassy_embedded_hal/shared_bus/asynch/
i2c.rs

1//! Asynchronous shared I2C bus
2//!
3//! # Example (nrf52)
4//!
5//! ```rust,ignore
6//! use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
7//! use embassy_sync::mutex::Mutex;
8//! use embassy_sync::blocking_mutex::raw::NoopRawMutex;
9//!
10//! static I2C_BUS: StaticCell<Mutex<NoopRawMutex, Twim<TWISPI0>>> = StaticCell::new();
11//! let config = twim::Config::default();
12//! let i2c = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
13//! let i2c_bus = Mutex::new(i2c);
14//! let i2c_bus = I2C_BUS.init(i2c_bus);
15//!
16//! // Device 1, using embedded-hal-async compatible driver for QMC5883L compass
17//! let i2c_dev1 = I2cDevice::new(i2c_bus);
18//! let compass = QMC5883L::new(i2c_dev1).await.unwrap();
19//!
20//! // Device 2, using embedded-hal-async compatible driver for Mpu6050 accelerometer
21//! let i2c_dev2 = I2cDevice::new(i2c_bus);
22//! let mpu = Mpu6050::new(i2c_dev2);
23//! ```
24
25use embassy_sync::blocking_mutex::raw::RawMutex;
26use embassy_sync::mutex::Mutex;
27use embedded_hal_async::i2c;
28
29use crate::shared_bus::I2cDeviceError;
30use crate::SetConfig;
31
32/// I2C device on a shared bus.
33pub struct I2cDevice<'a, M: RawMutex, BUS> {
34    bus: &'a Mutex<M, BUS>,
35}
36
37impl<'a, M: RawMutex, BUS> I2cDevice<'a, M, BUS> {
38    /// Create a new `I2cDevice`.
39    pub fn new(bus: &'a Mutex<M, BUS>) -> Self {
40        Self { bus }
41    }
42}
43
44impl<'a, M: RawMutex, BUS> i2c::ErrorType for I2cDevice<'a, M, BUS>
45where
46    BUS: i2c::ErrorType,
47{
48    type Error = I2cDeviceError<BUS::Error>;
49}
50
51impl<M, BUS> i2c::I2c for I2cDevice<'_, M, BUS>
52where
53    M: RawMutex + 'static,
54    BUS: i2c::I2c + 'static,
55{
56    async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
57        let mut bus = self.bus.lock().await;
58        bus.read(address, read).await.map_err(I2cDeviceError::I2c)?;
59        Ok(())
60    }
61
62    async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
63        let mut bus = self.bus.lock().await;
64        bus.write(address, write).await.map_err(I2cDeviceError::I2c)?;
65        Ok(())
66    }
67
68    async fn write_read(
69        &mut self,
70        address: u8,
71        write: &[u8],
72        read: &mut [u8],
73    ) -> Result<(), I2cDeviceError<BUS::Error>> {
74        let mut bus = self.bus.lock().await;
75        bus.write_read(address, write, read)
76            .await
77            .map_err(I2cDeviceError::I2c)?;
78        Ok(())
79    }
80
81    async fn transaction(
82        &mut self,
83        address: u8,
84        operations: &mut [embedded_hal_async::i2c::Operation<'_>],
85    ) -> Result<(), I2cDeviceError<BUS::Error>> {
86        let mut bus = self.bus.lock().await;
87        bus.transaction(address, operations)
88            .await
89            .map_err(I2cDeviceError::I2c)?;
90        Ok(())
91    }
92}
93
94/// I2C device on a shared bus, with its own configuration.
95///
96/// This is like [`I2cDevice`], with an additional bus configuration that's applied
97/// to the bus before each use using [`SetConfig`]. This allows different
98/// devices on the same bus to use different communication settings.
99pub struct I2cDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig> {
100    bus: &'a Mutex<M, BUS>,
101    config: BUS::Config,
102}
103
104impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> {
105    /// Create a new `I2cDeviceWithConfig`.
106    pub fn new(bus: &'a Mutex<M, BUS>, config: BUS::Config) -> Self {
107        Self { bus, config }
108    }
109
110    /// Change the device's config at runtime
111    pub fn set_config(&mut self, config: BUS::Config) {
112        self.config = config;
113    }
114}
115
116impl<'a, M, BUS> i2c::ErrorType for I2cDeviceWithConfig<'a, M, BUS>
117where
118    BUS: i2c::ErrorType,
119    M: RawMutex,
120    BUS: SetConfig,
121{
122    type Error = I2cDeviceError<BUS::Error>;
123}
124
125impl<M, BUS> i2c::I2c for I2cDeviceWithConfig<'_, M, BUS>
126where
127    M: RawMutex + 'static,
128    BUS: i2c::I2c + SetConfig + 'static,
129{
130    async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
131        let mut bus = self.bus.lock().await;
132        bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
133        bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
134        Ok(())
135    }
136
137    async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
138        let mut bus = self.bus.lock().await;
139        bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
140        bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
141        Ok(())
142    }
143
144    async fn write_read(
145        &mut self,
146        address: u8,
147        wr_buffer: &[u8],
148        rd_buffer: &mut [u8],
149    ) -> Result<(), I2cDeviceError<BUS::Error>> {
150        let mut bus = self.bus.lock().await;
151        bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
152        bus.write_read(address, wr_buffer, rd_buffer)
153            .await
154            .map_err(I2cDeviceError::I2c)?;
155        Ok(())
156    }
157
158    async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> {
159        let mut bus = self.bus.lock().await;
160        bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
161        bus.transaction(address, operations)
162            .await
163            .map_err(I2cDeviceError::I2c)?;
164        Ok(())
165    }
166}