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