mirror of
https://github.com/rust-embedded/embedded-hal.git
synced 2026-03-23 15:40:19 +00:00
spi: remove write-only and read-only traits.
This commit is contained in:
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Removed
|
||||
- spi: removed read-only and write-only traits.
|
||||
|
||||
## [v0.2.0-alpha.1] - 2023-04-04
|
||||
|
||||
### Added
|
||||
|
||||
@@ -8,96 +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
|
||||
///
|
||||
/// `SpiDeviceRead` 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<Word: Copy + 'static = u8>: ErrorType {
|
||||
/// Perform a read 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 read_transaction(&mut self, operations: &mut [&mut [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`]
|
||||
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
|
||||
self.read_transaction(&mut [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<Word: Copy + 'static = u8>: 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`]
|
||||
async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
|
||||
self.write_transaction(&[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<Word: Copy + 'static = u8>:
|
||||
SpiDeviceRead<Word> + SpiDeviceWrite<Word> + ErrorType
|
||||
{
|
||||
pub trait SpiDevice<Word: Copy + 'static = u8>: 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.
|
||||
///
|
||||
@@ -112,6 +35,24 @@ pub trait SpiDevice<Word: Copy + 'static = u8>:
|
||||
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: [`SpiDevice::transaction`], [`SpiDevice::read`]
|
||||
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
|
||||
self.transaction(&mut [Operation::Read(buf)]).await
|
||||
}
|
||||
|
||||
/// Do a write within a transaction.
|
||||
///
|
||||
/// This is a convenience method equivalent to `device.write_transaction(&mut [buf])`.
|
||||
///
|
||||
/// See also: [`SpiDevice::transaction`], [`SpiDevice::write`]
|
||||
async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
|
||||
self.transaction(&mut [Operation::Write(buf)]).await
|
||||
}
|
||||
|
||||
/// Do a transfer within a transaction.
|
||||
///
|
||||
/// This is a convenience method equivalent to `device.transaction(|bus| bus.transfer(read, write))`.
|
||||
@@ -133,29 +74,6 @@ pub trait SpiDevice<Word: Copy + 'static = u8>:
|
||||
}
|
||||
}
|
||||
|
||||
impl<Word: Copy + 'static, T: SpiDeviceRead<Word>> SpiDeviceRead<Word> for &mut T {
|
||||
async fn read_transaction(
|
||||
&mut self,
|
||||
operations: &mut [&mut [Word]],
|
||||
) -> Result<(), Self::Error> {
|
||||
T::read_transaction(self, operations).await
|
||||
}
|
||||
|
||||
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
|
||||
T::read(self, buf).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<Word: Copy + 'static, T: SpiDeviceWrite<Word>> SpiDeviceWrite<Word> 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<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> for &mut T {
|
||||
async fn transaction(
|
||||
&mut self,
|
||||
@@ -164,6 +82,14 @@ impl<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> for &mut T {
|
||||
T::transaction(self, operations).await
|
||||
}
|
||||
|
||||
async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
|
||||
T::read(self, buf).await
|
||||
}
|
||||
|
||||
async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
|
||||
T::write(self, buf).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<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> 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<T: SpiBusFlush> SpiBusFlush for &mut T {
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
T::flush(self).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Read-only SPI bus
|
||||
pub trait SpiBusRead<Word: 'static + Copy = u8>: 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<Word: 'static + Copy = u8>: ErrorType {
|
||||
/// Read `words` from the slave.
|
||||
///
|
||||
/// The word value sent on MOSI during reading is implementation-defined,
|
||||
@@ -197,35 +113,13 @@ pub trait SpiBusRead<Word: 'static + Copy = u8>: 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<T: SpiBusRead<Word>, Word: 'static + Copy> SpiBusRead<Word> 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<Word: 'static + Copy = u8>: 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<T: SpiBusWrite<Word>, Word: 'static + Copy> SpiBusWrite<Word> 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<Word: 'static + Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word> {
|
||||
/// 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<Word: 'static + Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word
|
||||
///
|
||||
/// 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 transfer<'a>(
|
||||
&'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<Word: 'static + Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word
|
||||
///
|
||||
/// 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 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>;
|
||||
|
||||
/// 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<T: SpiBus<Word>, Word: 'static + Copy> SpiBus<Word> 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<BUS::Error, CS::Error>;
|
||||
}
|
||||
|
||||
impl<Word: Copy + 'static, BUS, CS> blocking::SpiDeviceRead<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: blocking::SpiBusRead<Word>,
|
||||
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<Word: Copy + 'static, BUS, CS> blocking::SpiDeviceWrite<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: blocking::SpiBusWrite<Word>,
|
||||
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<Word: Copy + 'static, BUS, CS> blocking::SpiDevice<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: blocking::SpiBus<Word>,
|
||||
@@ -405,67 +250,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Word: Copy + 'static, BUS, CS> SpiDeviceRead<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: SpiBusRead<Word>,
|
||||
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<Word: Copy + 'static, BUS, CS> SpiDeviceWrite<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: SpiBusWrite<Word>,
|
||||
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<Word: Copy + 'static, BUS, CS> SpiDevice<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: SpiBus<Word>,
|
||||
|
||||
Reference in New Issue
Block a user