diff --git a/embedded-hal-async/src/spi.rs b/embedded-hal-async/src/spi.rs index 4d215c16a..0c99d79bf 100644 --- a/embedded-hal-async/src/spi.rs +++ b/embedded-hal-async/src/spi.rs @@ -8,21 +8,19 @@ pub use embedded_hal::spi::{ Error, ErrorKind, ErrorType, Mode, Operation, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3, }; -/// SPI read-only device trait +/// SPI device trait /// -/// `SpiDeviceRead` represents ownership over a single SPI device on a (possibly shared) bus, selected +/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected /// with a CS (Chip Select) pin. /// /// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits. -/// -/// See the [module-level documentation](self) for important usage information. -pub trait SpiDeviceRead: ErrorType { - /// Perform a read transaction against the device. +pub trait SpiDevice: ErrorType { + /// Perform a transaction against the device. /// /// - Locks the bus /// - Asserts the CS (Chip Select) pin. /// - Performs all the operations. - /// - [Flushes](SpiBusFlush::flush) the bus. + /// - [Flushes](SpiBus::flush) the bus. /// - Deasserts the CS pin. /// - Unlocks the bus. /// @@ -32,85 +30,28 @@ pub trait SpiDeviceRead: ErrorType { /// /// On bus errors the implementation should try to deassert CS. /// If an error occurs while deasserting CS the bus error should take priority as the return value. - async fn read_transaction(&mut self, operations: &mut [&mut [Word]]) - -> Result<(), Self::Error>; + async fn transaction( + &mut self, + operations: &mut [Operation<'_, Word>], + ) -> Result<(), Self::Error>; /// Do a read within a transaction. /// /// This is a convenience method equivalent to `device.read_transaction(&mut [buf])`. /// - /// See also: [`SpiDeviceRead::read_transaction`], [`SpiBusRead::read`] + /// See also: [`SpiDevice::transaction`], [`SpiDevice::read`] async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> { - self.read_transaction(&mut [buf]).await + self.transaction(&mut [Operation::Read(buf)]).await } -} - -/// SPI write-only device trait -/// -/// `SpiDeviceWrite` represents ownership over a single SPI device on a (possibly shared) bus, selected -/// with a CS (Chip Select) pin. -/// -/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits. -/// -/// See the [module-level documentation](self) for important usage information. -pub trait SpiDeviceWrite: ErrorType { - /// Perform a write transaction against the device. - /// - /// - Locks the bus - /// - Asserts the CS (Chip Select) pin. - /// - Performs all the operations. - /// - [Flushes](SpiBusFlush::flush) the bus. - /// - Deasserts the CS pin. - /// - Unlocks the bus. - /// - /// The locking mechanism is implementation-defined. The only requirement is it must prevent two - /// transactions from executing concurrently against the same bus. Examples of implementations are: - /// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy. - /// - /// On bus errors the implementation should try to deassert CS. - /// If an error occurs while deasserting CS the bus error should take priority as the return value. - async fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error>; /// Do a write within a transaction. /// /// This is a convenience method equivalent to `device.write_transaction(&mut [buf])`. /// - /// See also: [`SpiDeviceWrite::write_transaction`], [`SpiBusWrite::write`] + /// See also: [`SpiDevice::transaction`], [`SpiDevice::write`] async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> { - self.write_transaction(&[buf]).await + self.transaction(&mut [Operation::Write(buf)]).await } -} - -/// SPI device trait -/// -/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected -/// with a CS (Chip Select) pin. -/// -/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits. -/// -/// See the [module-level documentation](self) for important usage information. -pub trait SpiDevice: - SpiDeviceRead + SpiDeviceWrite + ErrorType -{ - /// Perform a transaction against the device. - /// - /// - Locks the bus - /// - Asserts the CS (Chip Select) pin. - /// - Performs all the operations. - /// - [Flushes](SpiBusFlush::flush) the bus. - /// - Deasserts the CS pin. - /// - Unlocks the bus. - /// - /// The locking mechanism is implementation-defined. The only requirement is it must prevent two - /// transactions from executing concurrently against the same bus. Examples of implementations are: - /// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy. - /// - /// On bus errors the implementation should try to deassert CS. - /// If an error occurs while deasserting CS the bus error should take priority as the return value. - async fn transaction( - &mut self, - operations: &mut [Operation<'_, Word>], - ) -> Result<(), Self::Error>; /// Do a transfer within a transaction. /// @@ -133,36 +74,21 @@ pub trait SpiDevice: } } -impl> SpiDeviceRead for &mut T { - async fn read_transaction( +impl> SpiDevice for &mut T { + async fn transaction( &mut self, - operations: &mut [&mut [Word]], + operations: &mut [Operation<'_, Word>], ) -> Result<(), Self::Error> { - T::read_transaction(self, operations).await + T::transaction(self, operations).await } async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> { T::read(self, buf).await } -} - -impl> SpiDeviceWrite for &mut T { - async fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - T::write_transaction(self, operations).await - } async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> { T::write(self, buf).await } -} - -impl> SpiDevice for &mut T { - async fn transaction( - &mut self, - operations: &mut [Operation<'_, Word>], - ) -> Result<(), Self::Error> { - T::transaction(self, operations).await - } async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { T::transfer(self, read, write).await @@ -173,22 +99,12 @@ impl> SpiDevice for &mut T { } } -/// Flush support for SPI bus -pub trait SpiBusFlush: ErrorType { - /// Wait until all operations have completed and the bus is idle. - /// - /// See (the docs on embedded-hal)[embedded_hal::spi] for information on flushing. - async fn flush(&mut self) -> Result<(), Self::Error>; -} - -impl SpiBusFlush for &mut T { - async fn flush(&mut self) -> Result<(), Self::Error> { - T::flush(self).await - } -} - -/// Read-only SPI bus -pub trait SpiBusRead: SpiBusFlush { +/// SPI bus +/// +/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins. +/// +/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits. +pub trait SpiBus: ErrorType { /// Read `words` from the slave. /// /// The word value sent on MOSI during reading is implementation-defined, @@ -197,35 +113,13 @@ pub trait SpiBusRead: SpiBusFlush { /// Implementations are allowed to return before the operation is /// complete. See (the docs on embedded-hal)[embedded_hal::spi] for details on flushing. async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>; -} - -impl, Word: 'static + Copy> SpiBusRead for &mut T { - async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { - T::read(self, words).await - } -} -/// Write-only SPI -pub trait SpiBusWrite: SpiBusFlush { /// Write `words` to the slave, ignoring all the incoming words /// /// Implementations are allowed to return before the operation is /// complete. See (the docs on embedded-hal)[embedded_hal::spi] for details on flushing. async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>; -} - -impl, Word: 'static + Copy> SpiBusWrite for &mut T { - async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> { - T::write(self, words).await - } -} -/// Read-write SPI bus -/// -/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins. -/// -/// See (the docs on embedded-hal)[embedded_hal::spi] for important information on SPI Bus vs Device traits. -pub trait SpiBus: SpiBusRead + SpiBusWrite { /// Write and read simultaneously. `write` is written to the slave on MOSI and /// words received on MISO are stored in `read`. /// @@ -237,11 +131,7 @@ pub trait SpiBus: SpiBusRead + SpiBusWrite( - &'a mut self, - read: &'a mut [Word], - write: &'a [Word], - ) -> Result<(), Self::Error>; + async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>; /// Write and read simultaneously. The contents of `words` are /// written to the slave, and the received words are stored into the same @@ -249,21 +139,34 @@ pub trait SpiBus: SpiBusRead + SpiBusWrite(&'a mut self, words: &'a mut [Word]) -> Result<(), Self::Error>; + async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error>; + + /// Wait until all operations have completed and the bus is idle. + /// + /// See (the docs on embedded-hal)[embedded_hal::spi] for information on flushing. + async fn flush(&mut self) -> Result<(), Self::Error>; } impl, Word: 'static + Copy> SpiBus for &mut T { - async fn transfer<'a>( - &'a mut self, - read: &'a mut [Word], - write: &'a [Word], - ) -> Result<(), Self::Error> { + async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + T::read(self, words).await + } + + async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> { + T::write(self, words).await + } + + async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { T::transfer(self, read, write).await } - async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [Word]) -> Result<(), Self::Error> { + async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { T::transfer_in_place(self, words).await } + + async fn flush(&mut self) -> Result<(), Self::Error> { + T::flush(self).await + } } /// Error type for [`ExclusiveDevice`] operations. @@ -312,64 +215,6 @@ where type Error = ExclusiveDeviceError; } -impl blocking::SpiDeviceRead for ExclusiveDevice -where - BUS: blocking::SpiBusRead, - CS: OutputPin, -{ - fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> { - self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?; - - let mut op_res = Ok(()); - - for buf in operations { - if let Err(e) = self.bus.read(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = self.bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(ExclusiveDeviceError::Spi)?; - flush_res.map_err(ExclusiveDeviceError::Spi)?; - cs_res.map_err(ExclusiveDeviceError::Cs)?; - - Ok(()) - } -} - -impl blocking::SpiDeviceWrite for ExclusiveDevice -where - BUS: blocking::SpiBusWrite, - CS: OutputPin, -{ - fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?; - - let mut op_res = Ok(()); - - for buf in operations { - if let Err(e) = self.bus.write(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = self.bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(ExclusiveDeviceError::Spi)?; - flush_res.map_err(ExclusiveDeviceError::Spi)?; - cs_res.map_err(ExclusiveDeviceError::Cs)?; - - Ok(()) - } -} - impl blocking::SpiDevice for ExclusiveDevice where BUS: blocking::SpiBus, @@ -405,67 +250,6 @@ where } } -impl SpiDeviceRead for ExclusiveDevice -where - BUS: SpiBusRead, - CS: OutputPin, -{ - async fn read_transaction( - &mut self, - operations: &mut [&mut [Word]], - ) -> Result<(), Self::Error> { - self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?; - - let mut op_res = Ok(()); - - for buf in operations { - if let Err(e) = self.bus.read(buf).await { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = self.bus.flush().await; - let cs_res = self.cs.set_high(); - - op_res.map_err(ExclusiveDeviceError::Spi)?; - flush_res.map_err(ExclusiveDeviceError::Spi)?; - cs_res.map_err(ExclusiveDeviceError::Cs)?; - - Ok(()) - } -} - -impl SpiDeviceWrite for ExclusiveDevice -where - BUS: SpiBusWrite, - CS: OutputPin, -{ - async fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?; - - let mut op_res = Ok(()); - - for buf in operations { - if let Err(e) = self.bus.write(buf).await { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = self.bus.flush().await; - let cs_res = self.cs.set_high(); - - op_res.map_err(ExclusiveDeviceError::Spi)?; - flush_res.map_err(ExclusiveDeviceError::Spi)?; - cs_res.map_err(ExclusiveDeviceError::Cs)?; - - Ok(()) - } -} - impl SpiDevice for ExclusiveDevice where BUS: SpiBus, diff --git a/embedded-hal-bus/src/spi/critical_section.rs b/embedded-hal-bus/src/spi/critical_section.rs index a327609fd..c3e8cf699 100644 --- a/embedded-hal-bus/src/spi/critical_section.rs +++ b/embedded-hal-bus/src/spi/critical_section.rs @@ -1,9 +1,7 @@ use core::cell::RefCell; use critical_section::Mutex; use embedded_hal::digital::OutputPin; -use embedded_hal::spi::{ - ErrorType, Operation, SpiBus, SpiBusRead, SpiBusWrite, SpiDevice, SpiDeviceRead, SpiDeviceWrite, -}; +use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice}; use super::DeviceError; @@ -37,70 +35,6 @@ where type Error = DeviceError; } -impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceRead for CriticalSectionDevice<'a, BUS, CS> -where - BUS: SpiBusRead, - CS: OutputPin, -{ - fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> { - critical_section::with(|cs| { - let bus = &mut *self.bus.borrow_ref_mut(cs); - - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - for buf in operations { - if let Err(e) = bus.read(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - }) - } -} - -impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceWrite for CriticalSectionDevice<'a, BUS, CS> -where - BUS: SpiBusWrite, - CS: OutputPin, -{ - fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - critical_section::with(|cs| { - let bus = &mut *self.bus.borrow_ref_mut(cs); - - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - for buf in operations { - if let Err(e) = bus.write(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - }) - } -} - impl<'a, Word: Copy + 'static, BUS, CS> SpiDevice for CriticalSectionDevice<'a, BUS, CS> where BUS: SpiBus, diff --git a/embedded-hal-bus/src/spi/exclusive.rs b/embedded-hal-bus/src/spi/exclusive.rs index fc7926eeb..9d4d002c9 100644 --- a/embedded-hal-bus/src/spi/exclusive.rs +++ b/embedded-hal-bus/src/spi/exclusive.rs @@ -1,9 +1,7 @@ //! SPI bus sharing mechanisms. use embedded_hal::digital::OutputPin; -use embedded_hal::spi::{ - ErrorType, Operation, SpiBus, SpiBusRead, SpiBusWrite, SpiDevice, SpiDeviceRead, SpiDeviceWrite, -}; +use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice}; use super::DeviceError; @@ -31,64 +29,6 @@ where type Error = DeviceError; } -impl SpiDeviceRead for ExclusiveDevice -where - BUS: SpiBusRead, - CS: OutputPin, -{ - fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> { - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - - for buf in operations { - if let Err(e) = self.bus.read(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = self.bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - } -} - -impl SpiDeviceWrite for ExclusiveDevice -where - BUS: SpiBusWrite, - CS: OutputPin, -{ - fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - - for buf in operations { - if let Err(e) = self.bus.write(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = self.bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - } -} - impl SpiDevice for ExclusiveDevice where BUS: SpiBus, diff --git a/embedded-hal-bus/src/spi/mutex.rs b/embedded-hal-bus/src/spi/mutex.rs index 1bb693ded..59f8dfe95 100644 --- a/embedded-hal-bus/src/spi/mutex.rs +++ b/embedded-hal-bus/src/spi/mutex.rs @@ -1,7 +1,5 @@ use embedded_hal::digital::OutputPin; -use embedded_hal::spi::{ - ErrorType, Operation, SpiBus, SpiBusRead, SpiBusWrite, SpiDevice, SpiDeviceRead, SpiDeviceWrite, -}; +use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice}; use std::sync::Mutex; use super::DeviceError; @@ -34,66 +32,6 @@ where type Error = DeviceError; } -impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceRead for MutexDevice<'a, BUS, CS> -where - BUS: SpiBusRead, - CS: OutputPin, -{ - fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> { - let bus = &mut *self.bus.lock().unwrap(); - - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - for buf in operations { - if let Err(e) = bus.read(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - } -} - -impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceWrite for MutexDevice<'a, BUS, CS> -where - BUS: SpiBusWrite, - CS: OutputPin, -{ - fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - let bus = &mut *self.bus.lock().unwrap(); - - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - for buf in operations { - if let Err(e) = bus.write(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - } -} - impl<'a, Word: Copy + 'static, BUS, CS> SpiDevice for MutexDevice<'a, BUS, CS> where BUS: SpiBus, diff --git a/embedded-hal-bus/src/spi/refcell.rs b/embedded-hal-bus/src/spi/refcell.rs index 47e29a879..9fd5d3e03 100644 --- a/embedded-hal-bus/src/spi/refcell.rs +++ b/embedded-hal-bus/src/spi/refcell.rs @@ -1,8 +1,6 @@ use core::cell::RefCell; use embedded_hal::digital::OutputPin; -use embedded_hal::spi::{ - ErrorType, Operation, SpiBus, SpiBusRead, SpiBusWrite, SpiDevice, SpiDeviceRead, SpiDeviceWrite, -}; +use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice}; use super::DeviceError; @@ -34,66 +32,6 @@ where type Error = DeviceError; } -impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceRead for RefCellDevice<'a, BUS, CS> -where - BUS: SpiBusRead, - CS: OutputPin, -{ - fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> { - let bus = &mut *self.bus.borrow_mut(); - - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - for buf in operations { - if let Err(e) = bus.read(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - } -} - -impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceWrite for RefCellDevice<'a, BUS, CS> -where - BUS: SpiBusWrite, - CS: OutputPin, -{ - fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - let bus = &mut *self.bus.borrow_mut(); - - self.cs.set_low().map_err(DeviceError::Cs)?; - - let mut op_res = Ok(()); - for buf in operations { - if let Err(e) = bus.write(buf) { - op_res = Err(e); - break; - } - } - - // On failure, it's important to still flush and deassert CS. - let flush_res = bus.flush(); - let cs_res = self.cs.set_high(); - - op_res.map_err(DeviceError::Spi)?; - flush_res.map_err(DeviceError::Spi)?; - cs_res.map_err(DeviceError::Cs)?; - - Ok(()) - } -} - impl<'a, Word: Copy + 'static, BUS, CS> SpiDevice for RefCellDevice<'a, BUS, CS> where BUS: SpiBus, diff --git a/embedded-hal/src/spi.rs b/embedded-hal/src/spi.rs index e8310d5ce..ea77bf982 100644 --- a/embedded-hal/src/spi.rs +++ b/embedded-hal/src/spi.rs @@ -23,21 +23,15 @@ //! //! ## Bus //! -//! SPI bus traits represent **exclusive ownership** over the whole SPI bus. This is usually the entire +//! The [`SpiBus`] trait represents **exclusive ownership** over the whole SPI bus. This is usually the entire //! SPI MCU peripheral, plus the SCK, MOSI and MISO pins. //! //! Owning an instance of an SPI bus guarantees exclusive access, this is, we have the guarantee no other //! piece of code will try to use the bus while we own it. //! -//! There's 3 bus traits, depending on the bus capabilities. -//! -//! - [`SpiBus`]: Read-write access. This is the most commonly used. -//! - [`SpiBusRead`]: Read-only access, for example a bus with a MISO pin but no MOSI pin. -//! - [`SpiBusWrite`]: Write-only access, for example a bus with a MOSI pin but no MISO pin. -//! //! ## Device //! -//! [`SpiDevice`] represents **ownership over a single SPI device selected by a CS pin** in a (possibly shared) bus. This is typically: +//! The [`SpiDevice`] trait represents **ownership over a single SPI device selected by a CS pin** in a (possibly shared) bus. This is typically: //! //! - Exclusive ownership of the **CS pin**. //! - Access to the **underlying SPI bus**. If shared, it'll be behind some kind of lock/mutex. @@ -46,19 +40,17 @@ //! consists of asserting CS, then doing one or more transfers, then deasserting CS. For the entire duration of the transaction, the [`SpiDevice`] //! implementation will ensure no other transaction can be opened on the same bus. This is the key that allows correct sharing of the bus. //! -//! For read-only or write-only SPI devices, the [`SpiDeviceRead`] and [`SpiDeviceWrite`] are available. -//! //! # For driver authors //! //! When implementing a driver, it's crucial to pick the right trait, to ensure correct operation //! with maximum interoperability. Here are some guidelines depending on the device you're implementing a driver for: //! -//! If your device **has a CS pin**, use [`SpiDevice`] (or [`SpiDeviceRead`]/[`SpiDeviceWrite`]). Do not manually +//! If your device **has a CS pin**, use [`SpiDevice`]. Do not manually //! manage the CS pin, the [`SpiDevice`] implementation will do it for you. //! By using [`SpiDevice`], your driver will cooperate nicely with other drivers for other devices in the same shared SPI bus. //! //! ``` -//! # use embedded_hal::spi::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice, Operation}; +//! # use embedded_hal::spi::{SpiBus, SpiDevice, Operation}; //! pub struct MyDriver { //! spi: SPI, //! } @@ -91,19 +83,19 @@ //! } //! ``` //! -//! If your device **does not have a CS pin**, use [`SpiBus`] (or [`SpiBusRead`], [`SpiBusWrite`]). This will ensure +//! If your device **does not have a CS pin**, use [`SpiBus`]. This will ensure //! your driver has exclusive access to the bus, so no other drivers can interfere. It's not possible to safely share //! a bus without CS pins. By requiring [`SpiBus`] you disallow sharing, ensuring correct operation. //! //! ``` -//! # use embedded_hal::spi::{SpiBus, SpiBusRead, SpiBusWrite}; +//! # use embedded_hal::spi::SpiBus; //! pub struct MyDriver { //! spi: SPI, //! } //! //! impl MyDriver //! where -//! SPI: SpiBus, // or SpiBusRead/SpiBusWrite if you only need to read or only write. +//! SPI: SpiBus, //! { //! pub fn new(spi: SPI) -> Self { //! Self { spi } @@ -129,7 +121,7 @@ //! //! # For HAL authors //! -//! HALs **must** implement [`SpiBus`], [`SpiBusRead`] and [`SpiBusWrite`]. Users can combine the bus together with the CS pin (which should +//! HALs **must** implement [`SpiBus`]. Users can combine the bus together with the CS pin (which should //! implement [`OutputPin`](crate::digital::OutputPin)) using HAL-independent [`SpiDevice`] implementations such as the ones in [`embedded-hal-bus`](https://crates.io/crates/embedded-hal-bus). //! //! HALs may additionally implement [`SpiDevice`] to **take advantage of hardware CS management**, which may provide some performance @@ -148,23 +140,23 @@ //! to finish, or enqueue the new one, but they must not return a "busy" error. Users must be able to do multiple method calls in a row //! and have them executed "as if" they were done sequentially, without having to check for "busy" errors. //! -//! When using a [`SpiBus`], call [`flush`](SpiBusFlush::flush) to wait for operations to actually finish. Examples of situations +//! When using a [`SpiBus`], call [`flush`](SpiBus::flush) to wait for operations to actually finish. Examples of situations //! where this is needed are: //! - To synchronize SPI activity and GPIO activity, for example before deasserting a CS pin. //! - Before deinitializing the hardware SPI peripheral. //! -//! When using a [`SpiDevice`], you can still call [`flush`](SpiBusFlush::flush) on the bus within a transaction. +//! When using a [`SpiDevice`], you can still call [`flush`](SpiBus::flush) on the bus within a transaction. //! It's very rarely needed, because [`transaction`](SpiDevice::transaction) already flushes for you //! before deasserting CS. For example, you may need it to synchronize with GPIOs other than CS, such as DCX pins //! sometimes found in SPI displays. //! -//! For example, for [`write`](SpiBusWrite::write) operations, it is common for hardware SPI peripherals to have a small +//! For example, for [`write`](SpiBus::write) operations, it is common for hardware SPI peripherals to have a small //! FIFO buffer, usually 1-4 bytes. Software writes data to the FIFO, and the peripheral sends it on MOSI at its own pace, -//! at the specified SPI frequency. It is allowed for an implementation of [`write`](SpiBusWrite::write) to return as soon -//! as all the data has been written to the FIFO, before it is actually sent. Calling [`flush`](SpiBusFlush::flush) would +//! at the specified SPI frequency. It is allowed for an implementation of [`write`](SpiBus::write) to return as soon +//! as all the data has been written to the FIFO, before it is actually sent. Calling [`flush`](SpiBus::flush) would //! wait until all the bits have actually been sent, the FIFO is empty, and the bus is idle. //! -//! This still applies to other operations such as [`read`](SpiBusRead::read) or [`transfer`](SpiBus::transfer). It is less obvious +//! This still applies to other operations such as [`read`](SpiBus::read) or [`transfer`](SpiBus::transfer). It is less obvious //! why, because these methods can't return before receiving all the read data. However it's still technically possible //! for them to return before the bus is idle. For example, assuming SPI mode 0, the last bit is sampled on the first (rising) edge //! of SCK, at which point a method could return, but the second (falling) SCK edge still has to happen before the bus is idle. @@ -307,11 +299,11 @@ impl ErrorType for &mut T { pub enum Operation<'a, Word: 'static> { /// Read data into the provided buffer. /// - /// Equivalent to [`SpiBusRead::read`]. + /// Equivalent to [`SpiBus::read`]. Read(&'a mut [Word]), /// Write data from the provided buffer, discarding read data /// - /// Equivalent to [`SpiBusWrite::write`]. + /// Equivalent to [`SpiBus::write`]. Write(&'a [Word]), /// Read data into the first buffer, while writing data from the second buffer. /// @@ -323,19 +315,19 @@ pub enum Operation<'a, Word: 'static> { TransferInPlace(&'a mut [Word]), } -/// SPI read-only device trait +/// SPI device trait /// -/// `SpiDeviceRead` represents ownership over a single SPI device on a (possibly shared) bus, selected +/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected /// with a CS (Chip Select) pin. /// /// See the [module-level documentation](self) for important usage information. -pub trait SpiDeviceRead: ErrorType { - /// Perform a read transaction against the device. +pub trait SpiDevice: ErrorType { + /// Perform a transaction against the device. /// /// - Locks the bus /// - Asserts the CS (Chip Select) pin. /// - Performs all the operations. - /// - [Flushes](SpiBusFlush::flush) the bus. + /// - [Flushes](SpiBus::flush) the bus. /// - Deasserts the CS pin. /// - Unlocks the bus. /// @@ -345,77 +337,25 @@ pub trait SpiDeviceRead: ErrorType { /// /// On bus errors the implementation should try to deassert CS. /// If an error occurs while deasserting CS the bus error should take priority as the return value. - fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error>; + fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error>; /// Do a read within a transaction. /// - /// This is a convenience method equivalent to `device.read_transaction(&mut [buf])`. + /// This is a convenience method equivalent to `device.transaction(&mut [Operation::Read(buf)])`. /// - /// See also: [`SpiDeviceRead::read_transaction`], [`SpiBusRead::read`] + /// See also: [`SpiDevice::transaction`], [`SpiBus::read`] fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> { - self.read_transaction(&mut [buf]) + self.transaction(&mut [Operation::Read(buf)]) } -} - -/// SPI write-only device trait -/// -/// `SpiDeviceWrite` represents ownership over a single SPI device on a (possibly shared) bus, selected -/// with a CS (Chip Select) pin. -/// -/// See the [module-level documentation](self) for important usage information. -pub trait SpiDeviceWrite: ErrorType { - /// Perform a write transaction against the device. - /// - /// - Locks the bus - /// - Asserts the CS (Chip Select) pin. - /// - Performs all the operations. - /// - [Flushes](SpiBusFlush::flush) the bus. - /// - Deasserts the CS pin. - /// - Unlocks the bus. - /// - /// The locking mechanism is implementation-defined. The only requirement is it must prevent two - /// transactions from executing concurrently against the same bus. Examples of implementations are: - /// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy. - /// - /// On bus errors the implementation should try to deassert CS. - /// If an error occurs while deasserting CS the bus error should take priority as the return value. - fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error>; /// Do a write within a transaction. /// - /// This is a convenience method equivalent to `device.write_transaction(&mut [buf])`. + /// This is a convenience method equivalent to `device.transaction(&mut [Operation::Write(buf)])`. /// - /// See also: [`SpiDeviceWrite::write_transaction`], [`SpiBusWrite::write`] + /// See also: [`SpiDevice::transaction`], [`SpiBus::write`] fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> { - self.write_transaction(&[buf]) + self.transaction(&mut [Operation::Write(buf)]) } -} - -/// SPI device trait -/// -/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected -/// with a CS (Chip Select) pin. -/// -/// See the [module-level documentation](self) for important usage information. -pub trait SpiDevice: - SpiDeviceRead + SpiDeviceWrite + ErrorType -{ - /// Perform a transaction against the device. - /// - /// - Locks the bus - /// - Asserts the CS (Chip Select) pin. - /// - Performs all the operations. - /// - [Flushes](SpiBusFlush::flush) the bus. - /// - Deasserts the CS pin. - /// - Unlocks the bus. - /// - /// The locking mechanism is implementation-defined. The only requirement is it must prevent two - /// transactions from executing concurrently against the same bus. Examples of implementations are: - /// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy. - /// - /// On bus errors the implementation should try to deassert CS. - /// If an error occurs while deasserting CS the bus error should take priority as the return value. - fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error>; /// Do a transfer within a transaction. /// @@ -428,7 +368,7 @@ pub trait SpiDevice: /// Do an in-place transfer within a transaction. /// - /// This is a convenience method equivalent to `device.transaction([Operation::TransferInPlace(buf)]`. + /// This is a convenience method equivalent to `device.transaction(&mut [Operation::TransferInPlace(buf)]`. /// /// See also: [`SpiDevice::transaction`], [`SpiBus::transfer_in_place`] fn transfer_in_place(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> { @@ -436,30 +376,18 @@ pub trait SpiDevice: } } -impl> SpiDeviceRead for &mut T { - fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> { - T::read_transaction(self, operations) +impl> SpiDevice for &mut T { + fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> { + T::transaction(self, operations) } fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> { T::read(self, buf) } -} - -impl> SpiDeviceWrite for &mut T { - fn write_transaction(&mut self, operations: &[&[Word]]) -> Result<(), Self::Error> { - T::write_transaction(self, operations) - } fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> { T::write(self, buf) } -} - -impl> SpiDevice for &mut T { - fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> { - T::transaction(self, operations) - } fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { T::transfer(self, read, write) @@ -470,22 +398,12 @@ impl> SpiDevice for &mut T { } } -/// Flush support for SPI bus -pub trait SpiBusFlush: ErrorType { - /// Wait until all operations have completed and the bus is idle. - /// - /// See the [module-level documentation](self) for important usage information. - fn flush(&mut self) -> Result<(), Self::Error>; -} - -impl SpiBusFlush for &mut T { - fn flush(&mut self) -> Result<(), Self::Error> { - T::flush(self) - } -} - -/// Read-only SPI bus -pub trait SpiBusRead: SpiBusFlush { +/// SPI bus +/// +/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins. +/// +/// See the [module-level documentation](self) for important information on SPI Bus vs Device traits. +pub trait SpiBus: ErrorType { /// Read `words` from the slave. /// /// The word value sent on MOSI during reading is implementation-defined, @@ -494,35 +412,13 @@ pub trait SpiBusRead: SpiBusFlush { /// Implementations are allowed to return before the operation is /// complete. See the [module-level documentation](self) for details. fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>; -} - -impl, Word: Copy + 'static> SpiBusRead for &mut T { - fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { - T::read(self, words) - } -} -/// Write-only SPI bus -pub trait SpiBusWrite: SpiBusFlush { /// Write `words` to the slave, ignoring all the incoming words /// /// Implementations are allowed to return before the operation is /// complete. See the [module-level documentation](self) for details. fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>; -} -impl, Word: Copy + 'static> SpiBusWrite for &mut T { - fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> { - T::write(self, words) - } -} - -/// Read-write SPI bus -/// -/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins. -/// -/// See the [module-level documentation](self) for important information on SPI Bus vs Device traits. -pub trait SpiBus: SpiBusRead + SpiBusWrite { /// Write and read simultaneously. `write` is written to the slave on MOSI and /// words received on MISO are stored in `read`. /// @@ -543,9 +439,22 @@ pub trait SpiBus: SpiBusRead + SpiBusWrite Result<(), Self::Error>; + + /// Wait until all operations have completed and the bus is idle. + /// + /// See the [module-level documentation](self) for important usage information. + fn flush(&mut self) -> Result<(), Self::Error>; } impl, Word: Copy + 'static> SpiBus for &mut T { + fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + T::read(self, words) + } + + fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> { + T::write(self, words) + } + fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { T::transfer(self, read, write) } @@ -553,4 +462,8 @@ impl, Word: Copy + 'static> SpiBus for &mut T { fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { T::transfer_in_place(self, words) } + + fn flush(&mut self) -> Result<(), Self::Error> { + T::flush(self) + } }