Skip to content

Commit 89e118a

Browse files
committed
spi: split into Bus and Device traits, to allow bus sharing.
1 parent ddf4375 commit 89e118a

File tree

2 files changed

+59
-70
lines changed

2 files changed

+59
-70
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@
352352
353353
#![deny(missing_docs)]
354354
#![no_std]
355+
#![feature(trait_alias)]
355356

356357
pub mod fmt;
357358
pub use nb;

src/spi/blocking.rs

Lines changed: 58 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,96 @@
11
//! Blocking SPI API
2+
use crate::spi::ErrorType;
23

3-
use super::ErrorType;
4+
/// SPI device base trait
5+
///
6+
/// If you're writing a driver, require [`SpiDevice`] (read-write), [`SpiDeviceRead`], [`SpiDeviceWrite`]
7+
/// to specify the kind of access to the device.
8+
pub trait SpiDeviceBase: ErrorType {
9+
/// SPI Bus type for this device.
10+
type Bus: ErrorType;
411

5-
/// Blocking transfer with separate buffers
6-
pub trait Transfer<Word = u8>: ErrorType {
7-
/// Writes and reads simultaneously. `write` is written to the slave on MOSI and
8-
/// words received on MISO are stored in `read`.
12+
/// Start a transaction against the device.
913
///
10-
/// It is allowed for `read` and `write` to have different lengths, even zero length.
11-
/// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
12-
/// incoming words after `read` has been filled will be discarded. If `write` is shorter,
13-
/// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
14-
/// typically `0x00`, `0xFF`, or configurable.
15-
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>;
14+
/// - Locks the bus, asserting the Chip Select pin (if any).
15+
/// - Calls `f` with an exclusive reference to the bus, which can then be used to do transfers against the device.
16+
/// - Unlocks the bus, deasserting the Chip Select pin (if any).
17+
///
18+
/// The lock mechanism is implementation-defined. The only requirement is it must prevent two
19+
/// transactions from executing concurrently against the same bus. Examples of implementations are:
20+
/// critical sections, blocking mutexes, or returning an error or panicking if the bus is already busy.
21+
fn transaction<R>(&mut self, f: impl FnOnce(&mut Self::Bus) -> R) -> Result<R, Self::Error>;
1622
}
1723

18-
impl<T: Transfer<Word>, Word: Copy> Transfer<Word> for &mut T {
19-
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
20-
T::transfer(self, read, write)
24+
impl<T: SpiDeviceBase> SpiDeviceBase for &mut T {
25+
type Bus = T::Bus;
26+
fn transaction<R>(&mut self, f: impl FnOnce(&mut Self::Bus) -> R) -> Result<R, Self::Error> {
27+
T::transaction(self, f)
2128
}
2229
}
2330

24-
/// Blocking transfer with single buffer (in-place)
25-
pub trait TransferInplace<Word: Copy = u8>: ErrorType {
26-
/// Writes and reads simultaneously. The contents of `words` are
27-
/// written to the slave, and the received words are stored into the same
28-
/// `words` buffer, overwriting it.
29-
fn transfer_inplace(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
30-
}
31+
/// SPI device
32+
pub trait SpiDevice<Word: Copy = u8> =
33+
SpiDeviceBase where <Self as SpiDeviceBase>::Bus: SpiBus<Word>;
3134

32-
impl<T: TransferInplace<Word>, Word: Copy> TransferInplace<Word> for &mut T {
33-
fn transfer_inplace(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
34-
T::transfer_inplace(self, words)
35-
}
36-
}
35+
/// SPI device with read-only access
36+
pub trait SpiDeviceRead<Word: Copy = u8> =
37+
SpiDeviceBase where <Self as SpiDeviceBase>::Bus: SpiBusRead<Word>;
38+
39+
/// SPI device with write-only access
40+
pub trait SpiDeviceWrite<Word: Copy = u8> =
41+
SpiDeviceBase where <Self as SpiDeviceBase>::Bus: SpiBusWrite<Word>;
3742

38-
/// Blocking read
39-
pub trait Read<Word: Copy = u8>: ErrorType {
43+
/// Read-only SPI bus
44+
pub trait SpiBusRead<Word: Copy = u8>: ErrorType {
4045
/// Reads `words` from the slave.
4146
///
4247
/// The word value sent on MOSI during reading is implementation-defined,
4348
/// typically `0x00`, `0xFF`, or configurable.
4449
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
4550
}
4651

47-
impl<T: Read<Word>, Word: Copy> Read<Word> for &mut T {
52+
impl<T: SpiBusRead<Word>, Word: Copy> SpiBusRead<Word> for &mut T {
4853
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
4954
T::read(self, words)
5055
}
5156
}
5257

53-
/// Blocking write
54-
pub trait Write<Word: Copy = u8>: ErrorType {
58+
/// Write-only SPI bus
59+
pub trait SpiBusWrite<Word: Copy = u8>: ErrorType {
5560
/// Writes `words` to the slave, ignoring all the incoming words
5661
fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>;
5762
}
5863

59-
impl<T: Write<Word>, Word: Copy> Write<Word> for &mut T {
64+
impl<T: SpiBusWrite<Word>, Word: Copy> SpiBusWrite<Word> for &mut T {
6065
fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
6166
T::write(self, words)
6267
}
6368
}
6469

65-
/// Blocking write (iterator version)
66-
pub trait WriteIter<Word: Copy = u8>: ErrorType {
67-
/// Writes `words` to the slave, ignoring all the incoming words
68-
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
69-
where
70-
WI: IntoIterator<Item = Word>;
71-
}
72-
73-
impl<T: WriteIter<Word>, Word: Copy> WriteIter<Word> for &mut T {
74-
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
75-
where
76-
WI: IntoIterator<Item = Word>,
77-
{
78-
T::write_iter(self, words)
79-
}
80-
}
70+
/// Read-write SPI bus
71+
pub trait SpiBus<Word: Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word> {
72+
/// Writes and reads simultaneously. `write` is written to the slave on MOSI and
73+
/// words received on MISO are stored in `read`.
74+
///
75+
/// It is allowed for `read` and `write` to have different lengths, even zero length.
76+
/// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
77+
/// incoming words after `read` has been filled will be discarded. If `write` is shorter,
78+
/// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
79+
/// typically `0x00`, `0xFF`, or configurable.
80+
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>;
8181

82-
/// Operation for transactional SPI trait
83-
///
84-
/// This allows composition of SPI operations into a single bus transaction
85-
#[derive(Debug, PartialEq)]
86-
pub enum Operation<'a, Word: 'static + Copy = u8> {
87-
/// Read data into the provided buffer.
88-
Read(&'a mut [Word]),
89-
/// Write data from the provided buffer, discarding read data
90-
Write(&'a [Word]),
91-
/// Write data out while reading data into the provided buffer
92-
Transfer(&'a mut [Word], &'a [Word]),
93-
/// Write data out while reading data into the provided buffer
94-
TransferInplace(&'a mut [Word]),
82+
/// Writes and reads simultaneously. The contents of `words` are
83+
/// written to the slave, and the received words are stored into the same
84+
/// `words` buffer, overwriting it.
85+
fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
9586
}
9687

97-
/// Transactional trait allows multiple actions to be executed
98-
/// as part of a single SPI transaction
99-
pub trait Transactional<Word: 'static + Copy = u8>: ErrorType {
100-
/// Execute the provided transactions
101-
fn exec<'a>(&mut self, operations: &mut [Operation<'a, Word>]) -> Result<(), Self::Error>;
102-
}
88+
impl<T: SpiBus<Word>, Word: Copy> SpiBus<Word> for &mut T {
89+
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
90+
T::transfer(self, read, write)
91+
}
10392

104-
impl<T: Transactional<Word>, Word: 'static + Copy> Transactional<Word> for &mut T {
105-
fn exec<'a>(&mut self, operations: &mut [Operation<'a, Word>]) -> Result<(), Self::Error> {
106-
T::exec(self, operations)
93+
fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
94+
T::transfer_in_place(self, words)
10795
}
10896
}

0 commit comments

Comments
 (0)