mirror of
https://github.com/rust-embedded/embedded-hal.git
synced 2026-03-14 01:47:38 +00:00
spi: remove write-only and read-only traits.
This commit is contained in:
parent
804e1de2df
commit
1567f258bf
@ -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>,
|
||||
|
||||
@ -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<BUS::Error, CS::Error>;
|
||||
}
|
||||
|
||||
impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceRead<Word> for CriticalSectionDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBusRead<Word>,
|
||||
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<Word> for CriticalSectionDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBusWrite<Word>,
|
||||
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<Word> for CriticalSectionDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBus<Word>,
|
||||
|
||||
@ -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<BUS::Error, CS::Error>;
|
||||
}
|
||||
|
||||
impl<Word: Copy + 'static, BUS, CS> SpiDeviceRead<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: SpiBusRead<Word>,
|
||||
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<Word: Copy + 'static, BUS, CS> SpiDeviceWrite<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: SpiBusWrite<Word>,
|
||||
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<Word: Copy + 'static, BUS, CS> SpiDevice<Word> for ExclusiveDevice<BUS, CS>
|
||||
where
|
||||
BUS: SpiBus<Word>,
|
||||
|
||||
@ -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<BUS::Error, CS::Error>;
|
||||
}
|
||||
|
||||
impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceRead<Word> for MutexDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBusRead<Word>,
|
||||
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<Word> for MutexDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBusWrite<Word>,
|
||||
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<Word> for MutexDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBus<Word>,
|
||||
|
||||
@ -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<BUS::Error, CS::Error>;
|
||||
}
|
||||
|
||||
impl<'a, Word: Copy + 'static, BUS, CS> SpiDeviceRead<Word> for RefCellDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBusRead<Word>,
|
||||
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<Word> for RefCellDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBusWrite<Word>,
|
||||
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<Word> for RefCellDevice<'a, BUS, CS>
|
||||
where
|
||||
BUS: SpiBus<Word>,
|
||||
|
||||
@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Removed
|
||||
- spi: removed read-only and write-only traits.
|
||||
|
||||
## [v1.0.0-alpha.10] - 2023-04-04
|
||||
|
||||
*** This is (also) an alpha release with breaking changes (sorry) ***
|
||||
|
||||
@ -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: 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: SPI,
|
||||
//! }
|
||||
//!
|
||||
//! impl<SPI> MyDriver<SPI>
|
||||
//! 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<T: ErrorType> 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,89 +315,19 @@ pub enum Operation<'a, Word: 'static> {
|
||||
TransferInPlace(&'a mut [Word]),
|
||||
}
|
||||
|
||||
/// 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 [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.
|
||||
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`]
|
||||
fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
|
||||
self.read_transaction(&mut [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<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.
|
||||
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`]
|
||||
fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
|
||||
self.write_transaction(&[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<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.
|
||||
///
|
||||
@ -417,6 +339,24 @@ pub trait SpiDevice<Word: Copy + 'static = u8>:
|
||||
/// 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 read within a transaction.
|
||||
///
|
||||
/// This is a convenience method equivalent to `device.transaction(&mut [Operation::Read(buf)])`.
|
||||
///
|
||||
/// See also: [`SpiDevice::transaction`], [`SpiBus::read`]
|
||||
fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
|
||||
self.transaction(&mut [Operation::Read(buf)])
|
||||
}
|
||||
|
||||
/// Do a write within a transaction.
|
||||
///
|
||||
/// This is a convenience method equivalent to `device.transaction(&mut [Operation::Write(buf)])`.
|
||||
///
|
||||
/// See also: [`SpiDevice::transaction`], [`SpiBus::write`]
|
||||
fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
|
||||
self.transaction(&mut [Operation::Write(buf)])
|
||||
}
|
||||
|
||||
/// Do a transfer within a transaction.
|
||||
///
|
||||
/// This is a convenience method equivalent to `device.transaction(&mut [Operation::Transfer(read, write)]`.
|
||||
@ -428,7 +368,7 @@ pub trait SpiDevice<Word: Copy + 'static = u8>:
|
||||
|
||||
/// 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<Word: Copy + 'static = u8>:
|
||||
}
|
||||
}
|
||||
|
||||
impl<Word: Copy + 'static, T: SpiDeviceRead<Word>> SpiDeviceRead<Word> for &mut T {
|
||||
fn read_transaction(&mut self, operations: &mut [&mut [Word]]) -> Result<(), Self::Error> {
|
||||
T::read_transaction(self, operations)
|
||||
impl<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> 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<Word: Copy + 'static, T: SpiDeviceWrite<Word>> SpiDeviceWrite<Word> 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<Word: Copy + 'static, T: SpiDevice<Word>> SpiDevice<Word> 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<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 [module-level documentation](self) for important usage information.
|
||||
fn flush(&mut self) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
impl<T: SpiBusFlush> SpiBusFlush for &mut T {
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
T::flush(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read-only SPI bus
|
||||
pub trait SpiBusRead<Word: Copy + 'static = u8>: 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<Word: Copy + 'static = u8>: ErrorType {
|
||||
/// Read `words` from the slave.
|
||||
///
|
||||
/// The word value sent on MOSI during reading is implementation-defined,
|
||||
@ -494,35 +412,13 @@ pub trait SpiBusRead<Word: Copy + 'static = u8>: 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<T: SpiBusRead<Word>, Word: Copy + 'static> SpiBusRead<Word> for &mut T {
|
||||
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
|
||||
T::read(self, words)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write-only SPI bus
|
||||
pub trait SpiBusWrite<Word: Copy + 'static = u8>: 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<T: SpiBusWrite<Word>, Word: Copy + 'static> SpiBusWrite<Word> 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<Word: Copy + 'static = 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`.
|
||||
///
|
||||
@ -543,9 +439,22 @@ pub trait SpiBus<Word: Copy + 'static = u8>: SpiBusRead<Word> + SpiBusWrite<Word
|
||||
/// Implementations are allowed to return before the operation is
|
||||
/// complete. See the [module-level documentation](self) for details.
|
||||
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 [module-level documentation](self) for important usage information.
|
||||
fn flush(&mut self) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
impl<T: SpiBus<Word>, Word: Copy + 'static> SpiBus<Word> 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<T: SpiBus<Word>, Word: Copy + 'static> SpiBus<Word> 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)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user