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 | |