Skip to content

Commit e0a30b5

Browse files
committed
async: add SPI.
1 parent 678a5eb commit e0a30b5

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed

embedded-hal-async/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
pub mod delay;
1515
pub mod digital;
1616
pub mod i2c;
17+
pub mod spi;

embedded-hal-async/src/spi.rs

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
//! Serial Peripheral Interface
2+
3+
use core::future::Future;
4+
5+
pub use embedded_hal::spi::{
6+
Error, ErrorKind, ErrorType, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3,
7+
};
8+
9+
/// SPI device trait
10+
///
11+
/// SpiDevice represents ownership over a single SPI device on a (possibly shared) bus, selected
12+
/// with a CS pin.
13+
///
14+
/// See (the docs on embedded-hal)[embedded_hal::spi::blocking] for important information on SPI Bus vs Device traits.
15+
pub trait SpiDevice: ErrorType {
16+
/// SPI Bus type for this device.
17+
type Bus: ErrorType;
18+
19+
/// Future returned by the `transaction` method.
20+
type TransactionFuture<'a, R, F, Fut>: Future<Output = Result<R, Self::Error>> + 'a
21+
where
22+
Self: 'a,
23+
R: 'a,
24+
F: FnMut(&'a mut Self::Bus) -> Fut + 'a,
25+
Fut: Future<Output = R> + 'a;
26+
27+
/// Start a transaction against the device.
28+
///
29+
/// - Locks the bus
30+
/// - Asserts the CS (Chip Select) pin.
31+
/// - Calls `f` with an exclusive reference to the bus, which can then be used to do transfers against the device.
32+
/// - Deasserts the CS pin.
33+
/// - Unlocks the bus,
34+
///
35+
/// The lock mechanism is implementation-defined. The only requirement is it must prevent two
36+
/// transactions from executing concurrently against the same bus. Examples of implementations are:
37+
/// critical sections, blocking mutexes, async mutexes, or returning an error or panicking if the bus is already busy.
38+
fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut>
39+
where
40+
F: FnMut(&'a mut Self::Bus) -> Fut + 'a,
41+
Fut: Future<Output = R> + 'a;
42+
}
43+
44+
impl<T: SpiDevice> SpiDevice for &mut T {
45+
type Bus = T::Bus;
46+
47+
type TransactionFuture<'a, R, F, Fut>
48+
where
49+
Self: 'a,
50+
R: 'a,
51+
F: FnMut(&'a mut Self::Bus) -> Fut + 'a,
52+
Fut: Future<Output = R> + 'a,
53+
= T::TransactionFuture<'a, R, F, Fut>;
54+
55+
fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut>
56+
where
57+
F: FnMut(&'a mut Self::Bus) -> Fut + 'a,
58+
Fut: Future<Output = R> + 'a,
59+
{
60+
T::transaction(self, f)
61+
}
62+
}
63+
64+
/// Read-only SPI bus
65+
pub trait SpiBusRead<Word: 'static + Copy = u8>: ErrorType {
66+
/// Future returned by the `read` method.
67+
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
68+
where
69+
Self: 'a;
70+
71+
/// Read `words` from the slave.
72+
///
73+
/// The word value sent on MOSI during reading is implementation-defined,
74+
/// typically `0x00`, `0xFF`, or configurable.
75+
fn read<'a>(&'a mut self, words: &'a mut [Word]) -> Self::ReadFuture<'a>;
76+
}
77+
78+
impl<T: SpiBusRead<Word>, Word: 'static + Copy> SpiBusRead<Word> for &mut T {
79+
type ReadFuture<'a>
80+
where
81+
Self: 'a,
82+
= T::ReadFuture<'a>;
83+
84+
fn read<'a>(&'a mut self, words: &'a mut [Word]) -> Self::ReadFuture<'a> {
85+
T::read(self, words)
86+
}
87+
}
88+
89+
/// Write-only SPI
90+
pub trait SpiBusWrite<Word: 'static + Copy = u8>: ErrorType {
91+
/// Future returned by the `write` method.
92+
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
93+
where
94+
Self: 'a;
95+
96+
/// Write `words` to the slave, ignoring all the incoming words
97+
fn write<'a>(&'a mut self, words: &'a [Word]) -> Self::WriteFuture<'a>;
98+
}
99+
100+
impl<T: SpiBusWrite<Word>, Word: 'static + Copy> SpiBusWrite<Word> for &mut T {
101+
type WriteFuture<'a>
102+
where
103+
Self: 'a,
104+
= T::WriteFuture<'a>;
105+
106+
fn write<'a>(&'a mut self, words: &'a [Word]) -> Self::WriteFuture<'a> {
107+
T::write(self, words)
108+
}
109+
}
110+
111+
/// Read-write SPI bus
112+
///
113+
/// SpiBus represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins.
114+
///
115+
/// See the [module-level documentation](self) for important information on SPI Bus vs Device traits.
116+
pub trait SpiBus<Word: 'static + Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word> {
117+
/// Future returned by the `transfer` method.
118+
type TransferFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
119+
where
120+
Self: 'a;
121+
122+
/// Write and read simultaneously. `write` is written to the slave on MOSI and
123+
/// words received on MISO are stored in `read`.
124+
///
125+
/// It is allowed for `read` and `write` to have different lengths, even zero length.
126+
/// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
127+
/// incoming words after `read` has been filled will be discarded. If `write` is shorter,
128+
/// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
129+
/// typically `0x00`, `0xFF`, or configurable.
130+
fn transfer<'a>(
131+
&'a mut self,
132+
read: &'a mut [Word],
133+
write: &'a [Word],
134+
) -> Self::TransferFuture<'a>;
135+
136+
/// Future returned by the `transfer_in_place` method.
137+
type TransferInPlaceFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
138+
where
139+
Self: 'a;
140+
141+
/// Write and read simultaneously. The contents of `words` are
142+
/// written to the slave, and the received words are stored into the same
143+
/// `words` buffer, overwriting it.
144+
fn transfer_in_place<'a>(
145+
&'a mut self,
146+
words: &'a mut [Word],
147+
) -> Self::TransferInPlaceFuture<'a>;
148+
}
149+
150+
impl<T: SpiBus<Word>, Word: 'static + Copy> SpiBus<Word> for &mut T {
151+
type TransferFuture<'a>
152+
where
153+
Self: 'a,
154+
= T::TransferFuture<'a>;
155+
156+
fn transfer<'a>(
157+
&'a mut self,
158+
read: &'a mut [Word],
159+
write: &'a [Word],
160+
) -> Self::TransferFuture<'a> {
161+
T::transfer(self, read, write)
162+
}
163+
164+
type TransferInPlaceFuture<'a>
165+
where
166+
Self: 'a,
167+
= T::TransferInPlaceFuture<'a>;
168+
169+
fn transfer_in_place<'a>(
170+
&'a mut self,
171+
words: &'a mut [Word],
172+
) -> Self::TransferInPlaceFuture<'a> {
173+
T::transfer_in_place(self, words)
174+
}
175+
}

0 commit comments

Comments
 (0)