aboutsummaryrefslogtreecommitdiff
path: root/embassy-embedded-hal/src/shared_bus/asynch
diff options
context:
space:
mode:
authorHenrik Alsér <[email protected]>2022-07-10 00:05:57 +0200
committerHenrik Alsér <[email protected]>2022-07-10 00:05:57 +0200
commitef24faf2df594d0eca1542ac02834af6aafa3853 (patch)
tree6092b31b84be58e3c54b5bddef12bded57d69e2a /embassy-embedded-hal/src/shared_bus/asynch
parent20f56b856feb3cefde300b76ceab85b6bd29c5a7 (diff)
Add asynch mod to shared_bus
Diffstat (limited to 'embassy-embedded-hal/src/shared_bus/asynch')
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/i2c.rs194
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/mod.rs3
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/spi.rs168
3 files changed, 365 insertions, 0 deletions
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
new file mode 100644
index 000000000..408317490
--- /dev/null
+++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
@@ -0,0 +1,194 @@
1//! Asynchronous shared I2C bus
2//!
3//! # Example (nrf52)
4//!
5//! ```rust
6//! use embassy_embedded_hal::shared_bus::i2c::I2cBusDevice;
7//! use embassy::mutex::Mutex;
8//! use embassy::blocking_mutex::raw::ThreadModeRawMutex;
9//!
10//! static I2C_BUS: Forever<Mutex::<ThreadModeRawMutex, Twim<TWISPI0>>> = Forever::new();
11//! let config = twim::Config::default();
12//! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
13//! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
14//! let i2c_bus = Mutex::<ThreadModeRawMutex, _>::new(i2c);
15//! let i2c_bus = I2C_BUS.put(i2c_bus);
16//!
17//! // Device 1, using embedded-hal-async compatible driver for QMC5883L compass
18//! let i2c_dev1 = I2cBusDevice::new(i2c_bus);
19//! let compass = QMC5883L::new(i2c_dev1).await.unwrap();
20//!
21//! // Device 2, using embedded-hal-async compatible driver for Mpu6050 accelerometer
22//! let i2c_dev2 = I2cBusDevice::new(i2c_bus);
23//! let mpu = Mpu6050::new(i2c_dev2);
24//! ```
25use core::fmt::Debug;
26use core::future::Future;
27
28use embassy::blocking_mutex::raw::RawMutex;
29use embassy::mutex::Mutex;
30use embedded_hal_async::i2c;
31
32use crate::shared_bus::I2cBusDeviceError;
33use crate::SetConfig;
34
35pub struct I2cBusDevice<'a, M: RawMutex, BUS> {
36 bus: &'a Mutex<M, BUS>,
37}
38
39impl<'a, M: RawMutex, BUS> I2cBusDevice<'a, M, BUS> {
40 pub fn new(bus: &'a Mutex<M, BUS>) -> Self {
41 Self { bus }
42 }
43}
44
45impl<BUS> i2c::Error for I2cBusDeviceError<BUS>
46where
47 BUS: i2c::Error + Debug,
48{
49 fn kind(&self) -> i2c::ErrorKind {
50 match self {
51 Self::I2c(e) => e.kind(),
52 }
53 }
54}
55
56impl<'a, M: RawMutex, BUS> i2c::ErrorType for I2cBusDevice<'a, M, BUS>
57where
58 BUS: i2c::ErrorType,
59{
60 type Error = I2cBusDeviceError<BUS::Error>;
61}
62
63impl<M, BUS> i2c::I2c for I2cBusDevice<'_, M, BUS>
64where
65 M: RawMutex + 'static,
66 BUS: i2c::I2c + 'static,
67{
68 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
69
70 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
71 async move {
72 let mut bus = self.bus.lock().await;
73 bus.read(address, buffer).await.map_err(I2cBusDeviceError::I2c)?;
74 Ok(())
75 }
76 }
77
78 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
79
80 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
81 async move {
82 let mut bus = self.bus.lock().await;
83 bus.write(address, bytes).await.map_err(I2cBusDeviceError::I2c)?;
84 Ok(())
85 }
86 }
87
88 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
89
90 fn write_read<'a>(
91 &'a mut self,
92 address: u8,
93 wr_buffer: &'a [u8],
94 rd_buffer: &'a mut [u8],
95 ) -> Self::WriteReadFuture<'a> {
96 async move {
97 let mut bus = self.bus.lock().await;
98 bus.write_read(address, wr_buffer, rd_buffer)
99 .await
100 .map_err(I2cBusDeviceError::I2c)?;
101 Ok(())
102 }
103 }
104
105 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a;
106
107 fn transaction<'a, 'b>(
108 &'a mut self,
109 address: u8,
110 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
111 ) -> Self::TransactionFuture<'a, 'b> {
112 let _ = address;
113 let _ = operations;
114 async move { todo!() }
115 }
116}
117
118pub struct I2cBusDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig> {
119 bus: &'a Mutex<M, BUS>,
120 config: BUS::Config,
121}
122
123impl<'a, M: RawMutex, BUS: SetConfig> I2cBusDeviceWithConfig<'a, M, BUS> {
124 pub fn new(bus: &'a Mutex<M, BUS>, config: BUS::Config) -> Self {
125 Self { bus, config }
126 }
127}
128
129impl<'a, M, BUS> i2c::ErrorType for I2cBusDeviceWithConfig<'a, M, BUS>
130where
131 BUS: i2c::ErrorType,
132 M: RawMutex,
133 BUS: SetConfig,
134{
135 type Error = I2cBusDeviceError<BUS::Error>;
136}
137
138impl<M, BUS> i2c::I2c for I2cBusDeviceWithConfig<'_, M, BUS>
139where
140 M: RawMutex + 'static,
141 BUS: i2c::I2c + SetConfig + 'static,
142{
143 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
144
145 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
146 async move {
147 let mut bus = self.bus.lock().await;
148 bus.set_config(&self.config);
149 bus.read(address, buffer).await.map_err(I2cBusDeviceError::I2c)?;
150 Ok(())
151 }
152 }
153
154 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
155
156 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
157 async move {
158 let mut bus = self.bus.lock().await;
159 bus.set_config(&self.config);
160 bus.write(address, bytes).await.map_err(I2cBusDeviceError::I2c)?;
161 Ok(())
162 }
163 }
164
165 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
166
167 fn write_read<'a>(
168 &'a mut self,
169 address: u8,
170 wr_buffer: &'a [u8],
171 rd_buffer: &'a mut [u8],
172 ) -> Self::WriteReadFuture<'a> {
173 async move {
174 let mut bus = self.bus.lock().await;
175 bus.set_config(&self.config);
176 bus.write_read(address, wr_buffer, rd_buffer)
177 .await
178 .map_err(I2cBusDeviceError::I2c)?;
179 Ok(())
180 }
181 }
182
183 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a;
184
185 fn transaction<'a, 'b>(
186 &'a mut self,
187 address: u8,
188 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
189 ) -> Self::TransactionFuture<'a, 'b> {
190 let _ = address;
191 let _ = operations;
192 async move { todo!() }
193 }
194}
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/mod.rs b/embassy-embedded-hal/src/shared_bus/asynch/mod.rs
new file mode 100644
index 000000000..2e660b724
--- /dev/null
+++ b/embassy-embedded-hal/src/shared_bus/asynch/mod.rs
@@ -0,0 +1,3 @@
1//! Asynchronous shared bus implementations for embedded-hal-async
2pub mod i2c;
3pub mod spi;
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
new file mode 100644
index 000000000..f3795bb19
--- /dev/null
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -0,0 +1,168 @@
1//! Asynchronous shared SPI bus
2//!
3//! # Example (nrf52)
4//!
5//! ```rust
6//! use embassy_embedded_hal::shared_bus::spi::SpiBusDevice;
7//! use embassy::mutex::Mutex;
8//! use embassy::blocking_mutex::raw::ThreadModeRawMutex;
9//!
10//! static SPI_BUS: Forever<Mutex<ThreadModeRawMutex, spim::Spim<SPI3>>> = Forever::new();
11//! let mut config = spim::Config::default();
12//! config.frequency = spim::Frequency::M32;
13//! let irq = interrupt::take!(SPIM3);
14//! let spi = spim::Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, config);
15//! let spi_bus = Mutex::<ThreadModeRawMutex, _>::new(spi);
16//! let spi_bus = SPI_BUS.put(spi_bus);
17//!
18//! // Device 1, using embedded-hal-async compatible driver for ST7735 LCD display
19//! let cs_pin1 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard);
20//! let spi_dev1 = SpiBusDevice::new(spi_bus, cs_pin1);
21//! let display1 = ST7735::new(spi_dev1, dc1, rst1, Default::default(), 160, 128);
22//!
23//! // Device 2
24//! let cs_pin2 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard);
25//! let spi_dev2 = SpiBusDevice::new(spi_bus, cs_pin2);
26//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128);
27//! ```
28use core::fmt::Debug;
29use core::future::Future;
30
31use embassy::blocking_mutex::raw::RawMutex;
32use embassy::mutex::Mutex;
33use embedded_hal_1::digital::blocking::OutputPin;
34use embedded_hal_1::spi::ErrorType;
35use embedded_hal_async::spi;
36
37use crate::shared_bus::SpiBusDeviceError;
38use crate::SetConfig;
39
40pub struct SpiBusDevice<'a, M: RawMutex, BUS, CS> {
41 bus: &'a Mutex<M, BUS>,
42 cs: CS,
43}
44
45impl<'a, M: RawMutex, BUS, CS> SpiBusDevice<'a, M, BUS, CS> {
46 pub fn new(bus: &'a Mutex<M, BUS>, cs: CS) -> Self {
47 Self { bus, cs }
48 }
49}
50
51impl<'a, M: RawMutex, BUS, CS> spi::ErrorType for SpiBusDevice<'a, M, BUS, CS>
52where
53 BUS: spi::ErrorType,
54 CS: OutputPin,
55{
56 type Error = SpiBusDeviceError<BUS::Error, CS::Error>;
57}
58
59impl<BUS, CS> spi::Error for SpiBusDeviceError<BUS, CS>
60where
61 BUS: spi::Error + Debug,
62 CS: Debug,
63{
64 fn kind(&self) -> spi::ErrorKind {
65 match self {
66 Self::Spi(e) => e.kind(),
67 Self::Cs(_) => spi::ErrorKind::Other,
68 }
69 }
70}
71
72impl<M, BUS, CS> spi::SpiDevice for SpiBusDevice<'_, M, BUS, CS>
73where
74 M: RawMutex + 'static,
75 BUS: spi::SpiBusFlush + 'static,
76 CS: OutputPin,
77{
78 type Bus = BUS;
79
80 type TransactionFuture<'a, R, F, Fut> = impl Future<Output = Result<R, Self::Error>> + 'a
81 where
82 Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a,
83 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a;
84
85 fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut>
86 where
87 R: 'a,
88 F: FnOnce(*mut Self::Bus) -> Fut + 'a,
89 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a,
90 {
91 async move {
92 let mut bus = self.bus.lock().await;
93 self.cs.set_low().map_err(SpiBusDeviceError::Cs)?;
94
95 let f_res = f(&mut *bus).await;
96
97 // On failure, it's important to still flush and deassert CS.
98 let flush_res = bus.flush().await;
99 let cs_res = self.cs.set_high();
100
101 let f_res = f_res.map_err(SpiBusDeviceError::Spi)?;
102 flush_res.map_err(SpiBusDeviceError::Spi)?;
103 cs_res.map_err(SpiBusDeviceError::Cs)?;
104
105 Ok(f_res)
106 }
107 }
108}
109
110pub struct SpiBusDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig, CS> {
111 bus: &'a Mutex<M, BUS>,
112 cs: CS,
113 config: BUS::Config,
114}
115
116impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiBusDeviceWithConfig<'a, M, BUS, CS> {
117 pub fn new(bus: &'a Mutex<M, BUS>, cs: CS, config: BUS::Config) -> Self {
118 Self { bus, cs, config }
119 }
120}
121
122impl<'a, M, BUS, CS> spi::ErrorType for SpiBusDeviceWithConfig<'a, M, BUS, CS>
123where
124 BUS: spi::ErrorType + SetConfig,
125 CS: OutputPin,
126 M: RawMutex,
127{
128 type Error = SpiBusDeviceError<BUS::Error, CS::Error>;
129}
130
131impl<M, BUS, CS> spi::SpiDevice for SpiBusDeviceWithConfig<'_, M, BUS, CS>
132where
133 M: RawMutex + 'static,
134 BUS: spi::SpiBusFlush + SetConfig + 'static,
135 CS: OutputPin,
136{
137 type Bus = BUS;
138
139 type TransactionFuture<'a, R, F, Fut> = impl Future<Output = Result<R, Self::Error>> + 'a
140 where
141 Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a,
142 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a;
143
144 fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut>
145 where
146 R: 'a,
147 F: FnOnce(*mut Self::Bus) -> Fut + 'a,
148 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a,
149 {
150 async move {
151 let mut bus = self.bus.lock().await;
152 bus.set_config(&self.config);
153 self.cs.set_low().map_err(SpiBusDeviceError::Cs)?;
154
155 let f_res = f(&mut *bus).await;
156
157 // On failure, it's important to still flush and deassert CS.
158 let flush_res = bus.flush().await;
159 let cs_res = self.cs.set_high();
160
161 let f_res = f_res.map_err(SpiBusDeviceError::Spi)?;
162 flush_res.map_err(SpiBusDeviceError::Spi)?;
163 cs_res.map_err(SpiBusDeviceError::Cs)?;
164
165 Ok(f_res)
166 }
167 }
168}