From ef24faf2df594d0eca1542ac02834af6aafa3853 Mon Sep 17 00:00:00 2001 From: Henrik Alsér Date: Sun, 10 Jul 2022 00:05:57 +0200 Subject: Add asynch mod to shared_bus --- embassy-embedded-hal/src/lib.rs | 2 + embassy-embedded-hal/src/shared_bus/asynch/i2c.rs | 194 ++++++++++++++++++++ embassy-embedded-hal/src/shared_bus/asynch/mod.rs | 3 + embassy-embedded-hal/src/shared_bus/asynch/spi.rs | 168 +++++++++++++++++ .../src/shared_bus/blocking/i2c.rs | 2 +- .../src/shared_bus/blocking/spi.rs | 2 +- embassy-embedded-hal/src/shared_bus/i2c.rs | 201 --------------------- embassy-embedded-hal/src/shared_bus/mod.rs | 18 +- embassy-embedded-hal/src/shared_bus/spi.rs | 176 ------------------ 9 files changed, 383 insertions(+), 383 deletions(-) create mode 100644 embassy-embedded-hal/src/shared_bus/asynch/i2c.rs create mode 100644 embassy-embedded-hal/src/shared_bus/asynch/mod.rs create mode 100644 embassy-embedded-hal/src/shared_bus/asynch/spi.rs delete mode 100644 embassy-embedded-hal/src/shared_bus/i2c.rs delete mode 100644 embassy-embedded-hal/src/shared_bus/spi.rs diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs index 688d0b48d..f57d83b5c 100644 --- a/embassy-embedded-hal/src/lib.rs +++ b/embassy-embedded-hal/src/lib.rs @@ -2,7 +2,9 @@ #![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] +#[cfg(feature = "nightly")] pub mod adapter; + pub mod shared_bus; pub trait SetConfig { 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 @@ +//! Asynchronous shared I2C bus +//! +//! # Example (nrf52) +//! +//! ```rust +//! use embassy_embedded_hal::shared_bus::i2c::I2cBusDevice; +//! use embassy::mutex::Mutex; +//! use embassy::blocking_mutex::raw::ThreadModeRawMutex; +//! +//! static I2C_BUS: Forever>> = Forever::new(); +//! let config = twim::Config::default(); +//! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); +//! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); +//! let i2c_bus = Mutex::::new(i2c); +//! let i2c_bus = I2C_BUS.put(i2c_bus); +//! +//! // Device 1, using embedded-hal-async compatible driver for QMC5883L compass +//! let i2c_dev1 = I2cBusDevice::new(i2c_bus); +//! let compass = QMC5883L::new(i2c_dev1).await.unwrap(); +//! +//! // Device 2, using embedded-hal-async compatible driver for Mpu6050 accelerometer +//! let i2c_dev2 = I2cBusDevice::new(i2c_bus); +//! let mpu = Mpu6050::new(i2c_dev2); +//! ``` +use core::fmt::Debug; +use core::future::Future; + +use embassy::blocking_mutex::raw::RawMutex; +use embassy::mutex::Mutex; +use embedded_hal_async::i2c; + +use crate::shared_bus::I2cBusDeviceError; +use crate::SetConfig; + +pub struct I2cBusDevice<'a, M: RawMutex, BUS> { + bus: &'a Mutex, +} + +impl<'a, M: RawMutex, BUS> I2cBusDevice<'a, M, BUS> { + pub fn new(bus: &'a Mutex) -> Self { + Self { bus } + } +} + +impl i2c::Error for I2cBusDeviceError +where + BUS: i2c::Error + Debug, +{ + fn kind(&self) -> i2c::ErrorKind { + match self { + Self::I2c(e) => e.kind(), + } + } +} + +impl<'a, M: RawMutex, BUS> i2c::ErrorType for I2cBusDevice<'a, M, BUS> +where + BUS: i2c::ErrorType, +{ + type Error = I2cBusDeviceError; +} + +impl i2c::I2c for I2cBusDevice<'_, M, BUS> +where + M: RawMutex + 'static, + BUS: i2c::I2c + 'static, +{ + type ReadFuture<'a> = impl Future> + 'a where Self: 'a; + + fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + async move { + let mut bus = self.bus.lock().await; + bus.read(address, buffer).await.map_err(I2cBusDeviceError::I2c)?; + Ok(()) + } + } + + type WriteFuture<'a> = impl Future> + 'a where Self: 'a; + + fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { + async move { + let mut bus = self.bus.lock().await; + bus.write(address, bytes).await.map_err(I2cBusDeviceError::I2c)?; + Ok(()) + } + } + + type WriteReadFuture<'a> = impl Future> + 'a where Self: 'a; + + fn write_read<'a>( + &'a mut self, + address: u8, + wr_buffer: &'a [u8], + rd_buffer: &'a mut [u8], + ) -> Self::WriteReadFuture<'a> { + async move { + let mut bus = self.bus.lock().await; + bus.write_read(address, wr_buffer, rd_buffer) + .await + .map_err(I2cBusDeviceError::I2c)?; + Ok(()) + } + } + + type TransactionFuture<'a, 'b> = impl Future> + 'a where Self: 'a, 'b: 'a; + + fn transaction<'a, 'b>( + &'a mut self, + address: u8, + operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], + ) -> Self::TransactionFuture<'a, 'b> { + let _ = address; + let _ = operations; + async move { todo!() } + } +} + +pub struct I2cBusDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig> { + bus: &'a Mutex, + config: BUS::Config, +} + +impl<'a, M: RawMutex, BUS: SetConfig> I2cBusDeviceWithConfig<'a, M, BUS> { + pub fn new(bus: &'a Mutex, config: BUS::Config) -> Self { + Self { bus, config } + } +} + +impl<'a, M, BUS> i2c::ErrorType for I2cBusDeviceWithConfig<'a, M, BUS> +where + BUS: i2c::ErrorType, + M: RawMutex, + BUS: SetConfig, +{ + type Error = I2cBusDeviceError; +} + +impl i2c::I2c for I2cBusDeviceWithConfig<'_, M, BUS> +where + M: RawMutex + 'static, + BUS: i2c::I2c + SetConfig + 'static, +{ + type ReadFuture<'a> = impl Future> + 'a where Self: 'a; + + fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + async move { + let mut bus = self.bus.lock().await; + bus.set_config(&self.config); + bus.read(address, buffer).await.map_err(I2cBusDeviceError::I2c)?; + Ok(()) + } + } + + type WriteFuture<'a> = impl Future> + 'a where Self: 'a; + + fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { + async move { + let mut bus = self.bus.lock().await; + bus.set_config(&self.config); + bus.write(address, bytes).await.map_err(I2cBusDeviceError::I2c)?; + Ok(()) + } + } + + type WriteReadFuture<'a> = impl Future> + 'a where Self: 'a; + + fn write_read<'a>( + &'a mut self, + address: u8, + wr_buffer: &'a [u8], + rd_buffer: &'a mut [u8], + ) -> Self::WriteReadFuture<'a> { + async move { + let mut bus = self.bus.lock().await; + bus.set_config(&self.config); + bus.write_read(address, wr_buffer, rd_buffer) + .await + .map_err(I2cBusDeviceError::I2c)?; + Ok(()) + } + } + + type TransactionFuture<'a, 'b> = impl Future> + 'a where Self: 'a, 'b: 'a; + + fn transaction<'a, 'b>( + &'a mut self, + address: u8, + operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], + ) -> Self::TransactionFuture<'a, 'b> { + let _ = address; + let _ = operations; + async move { todo!() } + } +} 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 @@ +//! Asynchronous shared bus implementations for embedded-hal-async +pub mod i2c; +pub 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 @@ +//! Asynchronous shared SPI bus +//! +//! # Example (nrf52) +//! +//! ```rust +//! use embassy_embedded_hal::shared_bus::spi::SpiBusDevice; +//! use embassy::mutex::Mutex; +//! use embassy::blocking_mutex::raw::ThreadModeRawMutex; +//! +//! static SPI_BUS: Forever>> = Forever::new(); +//! let mut config = spim::Config::default(); +//! config.frequency = spim::Frequency::M32; +//! let irq = interrupt::take!(SPIM3); +//! let spi = spim::Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, config); +//! let spi_bus = Mutex::::new(spi); +//! let spi_bus = SPI_BUS.put(spi_bus); +//! +//! // Device 1, using embedded-hal-async compatible driver for ST7735 LCD display +//! let cs_pin1 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard); +//! let spi_dev1 = SpiBusDevice::new(spi_bus, cs_pin1); +//! let display1 = ST7735::new(spi_dev1, dc1, rst1, Default::default(), 160, 128); +//! +//! // Device 2 +//! let cs_pin2 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard); +//! let spi_dev2 = SpiBusDevice::new(spi_bus, cs_pin2); +//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128); +//! ``` +use core::fmt::Debug; +use core::future::Future; + +use embassy::blocking_mutex::raw::RawMutex; +use embassy::mutex::Mutex; +use embedded_hal_1::digital::blocking::OutputPin; +use embedded_hal_1::spi::ErrorType; +use embedded_hal_async::spi; + +use crate::shared_bus::SpiBusDeviceError; +use crate::SetConfig; + +pub struct SpiBusDevice<'a, M: RawMutex, BUS, CS> { + bus: &'a Mutex, + cs: CS, +} + +impl<'a, M: RawMutex, BUS, CS> SpiBusDevice<'a, M, BUS, CS> { + pub fn new(bus: &'a Mutex, cs: CS) -> Self { + Self { bus, cs } + } +} + +impl<'a, M: RawMutex, BUS, CS> spi::ErrorType for SpiBusDevice<'a, M, BUS, CS> +where + BUS: spi::ErrorType, + CS: OutputPin, +{ + type Error = SpiBusDeviceError; +} + +impl spi::Error for SpiBusDeviceError +where + BUS: spi::Error + Debug, + CS: Debug, +{ + fn kind(&self) -> spi::ErrorKind { + match self { + Self::Spi(e) => e.kind(), + Self::Cs(_) => spi::ErrorKind::Other, + } + } +} + +impl spi::SpiDevice for SpiBusDevice<'_, M, BUS, CS> +where + M: RawMutex + 'static, + BUS: spi::SpiBusFlush + 'static, + CS: OutputPin, +{ + type Bus = BUS; + + type TransactionFuture<'a, R, F, Fut> = impl Future> + 'a + where + Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a, + Fut: Future::Error>> + 'a; + + fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut> + where + R: 'a, + F: FnOnce(*mut Self::Bus) -> Fut + 'a, + Fut: Future::Error>> + 'a, + { + async move { + let mut bus = self.bus.lock().await; + self.cs.set_low().map_err(SpiBusDeviceError::Cs)?; + + let f_res = f(&mut *bus).await; + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush().await; + let cs_res = self.cs.set_high(); + + let f_res = f_res.map_err(SpiBusDeviceError::Spi)?; + flush_res.map_err(SpiBusDeviceError::Spi)?; + cs_res.map_err(SpiBusDeviceError::Cs)?; + + Ok(f_res) + } + } +} + +pub struct SpiBusDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig, CS> { + bus: &'a Mutex, + cs: CS, + config: BUS::Config, +} + +impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiBusDeviceWithConfig<'a, M, BUS, CS> { + pub fn new(bus: &'a Mutex, cs: CS, config: BUS::Config) -> Self { + Self { bus, cs, config } + } +} + +impl<'a, M, BUS, CS> spi::ErrorType for SpiBusDeviceWithConfig<'a, M, BUS, CS> +where + BUS: spi::ErrorType + SetConfig, + CS: OutputPin, + M: RawMutex, +{ + type Error = SpiBusDeviceError; +} + +impl spi::SpiDevice for SpiBusDeviceWithConfig<'_, M, BUS, CS> +where + M: RawMutex + 'static, + BUS: spi::SpiBusFlush + SetConfig + 'static, + CS: OutputPin, +{ + type Bus = BUS; + + type TransactionFuture<'a, R, F, Fut> = impl Future> + 'a + where + Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a, + Fut: Future::Error>> + 'a; + + fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut> + where + R: 'a, + F: FnOnce(*mut Self::Bus) -> Fut + 'a, + Fut: Future::Error>> + 'a, + { + async move { + let mut bus = self.bus.lock().await; + bus.set_config(&self.config); + self.cs.set_low().map_err(SpiBusDeviceError::Cs)?; + + let f_res = f(&mut *bus).await; + + // On failure, it's important to still flush and deassert CS. + let flush_res = bus.flush().await; + let cs_res = self.cs.set_high(); + + let f_res = f_res.map_err(SpiBusDeviceError::Spi)?; + flush_res.map_err(SpiBusDeviceError::Spi)?; + cs_res.map_err(SpiBusDeviceError::Cs)?; + + Ok(f_res) + } + } +} diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index 0c8338c73..ac361a786 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -23,7 +23,7 @@ use embassy::blocking_mutex::Mutex; use embedded_hal_1::i2c::blocking::{I2c, Operation}; use embedded_hal_1::i2c::ErrorType; -use crate::shared_bus::i2c::I2cBusDeviceError; +use crate::shared_bus::I2cBusDeviceError; use crate::SetConfig; pub struct I2cBusDevice<'a, M: RawMutex, BUS> { diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index 456da8859..704858cdb 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs @@ -26,7 +26,7 @@ use embedded_hal_1::digital::blocking::OutputPin; use embedded_hal_1::spi; use embedded_hal_1::spi::blocking::{SpiBusFlush, SpiDevice}; -use crate::shared_bus::spi::SpiBusDeviceError; +use crate::shared_bus::SpiBusDeviceError; use crate::SetConfig; pub struct SpiBusDevice<'a, M: RawMutex, BUS, CS> { diff --git a/embassy-embedded-hal/src/shared_bus/i2c.rs b/embassy-embedded-hal/src/shared_bus/i2c.rs deleted file mode 100644 index f63190e6a..000000000 --- a/embassy-embedded-hal/src/shared_bus/i2c.rs +++ /dev/null @@ -1,201 +0,0 @@ -//! Asynchronous shared I2C bus -//! -//! # Example (nrf52) -//! -//! ```rust -//! use embassy_embedded_hal::shared_bus::i2c::I2cBusDevice; -//! use embassy::mutex::Mutex; -//! use embassy::blocking_mutex::raw::ThreadModeRawMutex; -//! -//! static I2C_BUS: Forever>> = Forever::new(); -//! let config = twim::Config::default(); -//! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -//! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); -//! let i2c_bus = Mutex::::new(i2c); -//! let i2c_bus = I2C_BUS.put(i2c_bus); -//! -//! // Device 1, using embedded-hal-async compatible driver for QMC5883L compass -//! let i2c_dev1 = I2cBusDevice::new(i2c_bus); -//! let compass = QMC5883L::new(i2c_dev1).await.unwrap(); -//! -//! // Device 2, using embedded-hal-async compatible driver for Mpu6050 accelerometer -//! let i2c_dev2 = I2cBusDevice::new(i2c_bus); -//! let mpu = Mpu6050::new(i2c_dev2); -//! ``` -use core::fmt::Debug; -use core::future::Future; - -use embassy::blocking_mutex::raw::RawMutex; -use embassy::mutex::Mutex; -#[cfg(feature = "nightly")] -use embedded_hal_async::i2c; - -use crate::SetConfig; - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum I2cBusDeviceError { - I2c(BUS), -} - -impl i2c::Error for I2cBusDeviceError -where - BUS: i2c::Error + Debug, -{ - fn kind(&self) -> i2c::ErrorKind { - match self { - Self::I2c(e) => e.kind(), - } - } -} - -pub struct I2cBusDevice<'a, M: RawMutex, BUS> { - bus: &'a Mutex, -} - -impl<'a, M: RawMutex, BUS> I2cBusDevice<'a, M, BUS> { - pub fn new(bus: &'a Mutex) -> Self { - Self { bus } - } -} - -impl<'a, M: RawMutex, BUS> i2c::ErrorType for I2cBusDevice<'a, M, BUS> -where - BUS: i2c::ErrorType, -{ - type Error = I2cBusDeviceError; -} - -#[cfg(feature = "nightly")] -impl i2c::I2c for I2cBusDevice<'_, M, BUS> -where - M: RawMutex + 'static, - BUS: i2c::I2c + 'static, -{ - type ReadFuture<'a> = impl Future> + 'a where Self: 'a; - - fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { - let mut bus = self.bus.lock().await; - bus.read(address, buffer).await.map_err(I2cBusDeviceError::I2c)?; - Ok(()) - } - } - - type WriteFuture<'a> = impl Future> + 'a where Self: 'a; - - fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { - async move { - let mut bus = self.bus.lock().await; - bus.write(address, bytes).await.map_err(I2cBusDeviceError::I2c)?; - Ok(()) - } - } - - type WriteReadFuture<'a> = impl Future> + 'a where Self: 'a; - - fn write_read<'a>( - &'a mut self, - address: u8, - wr_buffer: &'a [u8], - rd_buffer: &'a mut [u8], - ) -> Self::WriteReadFuture<'a> { - async move { - let mut bus = self.bus.lock().await; - bus.write_read(address, wr_buffer, rd_buffer) - .await - .map_err(I2cBusDeviceError::I2c)?; - Ok(()) - } - } - - type TransactionFuture<'a, 'b> = impl Future> + 'a where Self: 'a, 'b: 'a; - - fn transaction<'a, 'b>( - &'a mut self, - address: u8, - operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], - ) -> Self::TransactionFuture<'a, 'b> { - let _ = address; - let _ = operations; - async move { todo!() } - } -} - -pub struct I2cBusDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig> { - bus: &'a Mutex, - config: BUS::Config, -} - -impl<'a, M: RawMutex, BUS: SetConfig> I2cBusDeviceWithConfig<'a, M, BUS> { - pub fn new(bus: &'a Mutex, config: BUS::Config) -> Self { - Self { bus, config } - } -} - -impl<'a, M, BUS> i2c::ErrorType for I2cBusDeviceWithConfig<'a, M, BUS> -where - BUS: i2c::ErrorType, - M: RawMutex, - BUS: SetConfig, -{ - type Error = I2cBusDeviceError; -} - -#[cfg(feature = "nightly")] -impl i2c::I2c for I2cBusDeviceWithConfig<'_, M, BUS> -where - M: RawMutex + 'static, - BUS: i2c::I2c + SetConfig + 'static, -{ - type ReadFuture<'a> = impl Future> + 'a where Self: 'a; - - fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { - let mut bus = self.bus.lock().await; - bus.set_config(&self.config); - bus.read(address, buffer).await.map_err(I2cBusDeviceError::I2c)?; - Ok(()) - } - } - - type WriteFuture<'a> = impl Future> + 'a where Self: 'a; - - fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { - async move { - let mut bus = self.bus.lock().await; - bus.set_config(&self.config); - bus.write(address, bytes).await.map_err(I2cBusDeviceError::I2c)?; - Ok(()) - } - } - - type WriteReadFuture<'a> = impl Future> + 'a where Self: 'a; - - fn write_read<'a>( - &'a mut self, - address: u8, - wr_buffer: &'a [u8], - rd_buffer: &'a mut [u8], - ) -> Self::WriteReadFuture<'a> { - async move { - let mut bus = self.bus.lock().await; - bus.set_config(&self.config); - bus.write_read(address, wr_buffer, rd_buffer) - .await - .map_err(I2cBusDeviceError::I2c)?; - Ok(()) - } - } - - type TransactionFuture<'a, 'b> = impl Future> + 'a where Self: 'a, 'b: 'a; - - fn transaction<'a, 'b>( - &'a mut self, - address: u8, - operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], - ) -> Self::TransactionFuture<'a, 'b> { - let _ = address; - let _ = operations; - async move { todo!() } - } -} diff --git a/embassy-embedded-hal/src/shared_bus/mod.rs b/embassy-embedded-hal/src/shared_bus/mod.rs index cd748cac8..2309a6c35 100644 --- a/embassy-embedded-hal/src/shared_bus/mod.rs +++ b/embassy-embedded-hal/src/shared_bus/mod.rs @@ -1,6 +1,16 @@ //! Shared bus implementations +#[cfg(feature = "nightly")] +pub mod asynch; + pub mod blocking; -/// Shared i2c bus implementation for embedded-hal-async -pub mod i2c; -/// Shared SPI bus implementation for embedded-hal-async -pub mod spi; + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum I2cBusDeviceError { + I2c(BUS), +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum SpiBusDeviceError { + Spi(BUS), + Cs(CS), +} diff --git a/embassy-embedded-hal/src/shared_bus/spi.rs b/embassy-embedded-hal/src/shared_bus/spi.rs deleted file mode 100644 index 136352e0a..000000000 --- a/embassy-embedded-hal/src/shared_bus/spi.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! Asynchronous shared SPI bus -//! -//! # Example (nrf52) -//! -//! ```rust -//! use embassy_embedded_hal::shared_bus::spi::SpiBusDevice; -//! use embassy::mutex::Mutex; -//! use embassy::blocking_mutex::raw::ThreadModeRawMutex; -//! -//! static SPI_BUS: Forever>> = Forever::new(); -//! let mut config = spim::Config::default(); -//! config.frequency = spim::Frequency::M32; -//! let irq = interrupt::take!(SPIM3); -//! let spi = spim::Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, config); -//! let spi_bus = Mutex::::new(spi); -//! let spi_bus = SPI_BUS.put(spi_bus); -//! -//! // Device 1, using embedded-hal-async compatible driver for ST7735 LCD display -//! let cs_pin1 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard); -//! let spi_dev1 = SpiBusDevice::new(spi_bus, cs_pin1); -//! let display1 = ST7735::new(spi_dev1, dc1, rst1, Default::default(), 160, 128); -//! -//! // Device 2 -//! let cs_pin2 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard); -//! let spi_dev2 = SpiBusDevice::new(spi_bus, cs_pin2); -//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128); -//! ``` -use core::fmt::Debug; -use core::future::Future; - -use embassy::blocking_mutex::raw::RawMutex; -use embassy::mutex::Mutex; -use embedded_hal_1::digital::blocking::OutputPin; -use embedded_hal_1::spi::ErrorType; -#[cfg(feature = "nightly")] -use embedded_hal_async::spi; - -use crate::SetConfig; - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum SpiBusDeviceError { - Spi(BUS), - Cs(CS), -} - -impl spi::Error for SpiBusDeviceError -where - BUS: spi::Error + Debug, - CS: Debug, -{ - fn kind(&self) -> spi::ErrorKind { - match self { - Self::Spi(e) => e.kind(), - Self::Cs(_) => spi::ErrorKind::Other, - } - } -} - -pub struct SpiBusDevice<'a, M: RawMutex, BUS, CS> { - bus: &'a Mutex, - cs: CS, -} - -impl<'a, M: RawMutex, BUS, CS> SpiBusDevice<'a, M, BUS, CS> { - pub fn new(bus: &'a Mutex, cs: CS) -> Self { - Self { bus, cs } - } -} - -impl<'a, M: RawMutex, BUS, CS> spi::ErrorType for SpiBusDevice<'a, M, BUS, CS> -where - BUS: spi::ErrorType, - CS: OutputPin, -{ - type Error = SpiBusDeviceError; -} - -#[cfg(feature = "nightly")] -impl spi::SpiDevice for SpiBusDevice<'_, M, BUS, CS> -where - M: RawMutex + 'static, - BUS: spi::SpiBusFlush + 'static, - CS: OutputPin, -{ - type Bus = BUS; - - type TransactionFuture<'a, R, F, Fut> = impl Future> + 'a - where - Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a, - Fut: Future::Error>> + 'a; - - fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut> - where - R: 'a, - F: FnOnce(*mut Self::Bus) -> Fut + 'a, - Fut: Future::Error>> + 'a, - { - async move { - let mut bus = self.bus.lock().await; - self.cs.set_low().map_err(SpiBusDeviceError::Cs)?; - - let f_res = f(&mut *bus).await; - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush().await; - let cs_res = self.cs.set_high(); - - let f_res = f_res.map_err(SpiBusDeviceError::Spi)?; - flush_res.map_err(SpiBusDeviceError::Spi)?; - cs_res.map_err(SpiBusDeviceError::Cs)?; - - Ok(f_res) - } - } -} - -pub struct SpiBusDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig, CS> { - bus: &'a Mutex, - cs: CS, - config: BUS::Config, -} - -impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiBusDeviceWithConfig<'a, M, BUS, CS> { - pub fn new(bus: &'a Mutex, cs: CS, config: BUS::Config) -> Self { - Self { bus, cs, config } - } -} - -impl<'a, M, BUS, CS> spi::ErrorType for SpiBusDeviceWithConfig<'a, M, BUS, CS> -where - BUS: spi::ErrorType + SetConfig, - CS: OutputPin, - M: RawMutex, -{ - type Error = SpiBusDeviceError; -} - -#[cfg(feature = "nightly")] -impl spi::SpiDevice for SpiBusDeviceWithConfig<'_, M, BUS, CS> -where - M: RawMutex + 'static, - BUS: spi::SpiBusFlush + SetConfig + 'static, - CS: OutputPin, -{ - type Bus = BUS; - - type TransactionFuture<'a, R, F, Fut> = impl Future> + 'a - where - Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a, - Fut: Future::Error>> + 'a; - - fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut> - where - R: 'a, - F: FnOnce(*mut Self::Bus) -> Fut + 'a, - Fut: Future::Error>> + 'a, - { - async move { - let mut bus = self.bus.lock().await; - bus.set_config(&self.config); - self.cs.set_low().map_err(SpiBusDeviceError::Cs)?; - - let f_res = f(&mut *bus).await; - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush().await; - let cs_res = self.cs.set_high(); - - let f_res = f_res.map_err(SpiBusDeviceError::Spi)?; - flush_res.map_err(SpiBusDeviceError::Spi)?; - cs_res.map_err(SpiBusDeviceError::Cs)?; - - Ok(f_res) - } - } -} -- cgit