embedded_hal_async/spi.rs
1//! SPI master mode traits.
2
3pub use embedded_hal::spi::{
4 Error, ErrorKind, ErrorType, Mode, Operation, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3,
5};
6
7/// SPI device trait.
8///
9/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected
10/// with a CS (Chip Select) pin.
11///
12/// See [the docs on embedded-hal](embedded_hal::spi) for important information on SPI Bus vs Device traits.
13pub trait SpiDevice<Word: Copy + 'static = u8>: ErrorType {
14 /// Perform a transaction against the device.
15 ///
16 /// - Locks the bus
17 /// - Asserts the CS (Chip Select) pin.
18 /// - Performs all the operations.
19 /// - [Flushes](SpiBus::flush) the bus.
20 /// - Deasserts the CS pin.
21 /// - Unlocks the bus.
22 ///
23 /// The locking mechanism is implementation-defined. The only requirement is it must prevent two
24 /// transactions from executing concurrently against the same bus. Examples of implementations are:
25 /// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy.
26 ///
27 /// On bus errors the implementation should try to deassert CS.
28 /// If an error occurs while deasserting CS the bus error should take priority as the return value.
29 async fn transaction(
30 &mut self,
31 operations: &mut [Operation<'_, Word>],
32 ) -> Result<(), Self::Error>;
33
34 /// Do a read within a transaction.
35 ///
36 /// This is a convenience method equivalent to `device.read_transaction(&mut [buf])`.
37 ///
38 /// See also: [`SpiDevice::transaction`], [`SpiDevice::read`]
39 #[inline]
40 async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
41 self.transaction(&mut [Operation::Read(buf)]).await
42 }
43
44 /// Do a write within a transaction.
45 ///
46 /// This is a convenience method equivalent to `device.write_transaction(&mut [buf])`.
47 ///
48 /// See also: [`SpiDevice::transaction`], [`SpiDevice::write`]
49 #[inline]
50 async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
51 self.transaction(&mut [Operation::Write(buf)]).await
52 }
53
54 /// Do a transfer within a transaction.
55 ///
56 /// This is a convenience method equivalent to `device.transaction(&mut [Operation::Transfer(read, write)])`.
57 ///
58 /// See also: [`SpiDevice::transaction`], [`SpiBus::transfer`]
59 #[inline]
60 async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
61 self.transaction(&mut [Operation::Transfer(read, write)])
62 .await
63 }
64
65 /// Do an in-place transfer within a transaction.
66 ///
67 /// This is a convenience method equivalent to `device.transaction(&mut [Operation::TransferInPlace(buf)])`.
68 ///
69 /// See also: [`SpiDevice::transaction`], [`SpiBus::transfer_in_place`]
70 #[inline]
71 async fn transfer_in_place(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
72 self.transaction(&mut [Operation::TransferInPlace(buf)])
73 .await
74 }
75}
76
77impl<Word: Copy + 'static, T: SpiDevice<Word> + ?Sized> SpiDevice<Word> for &mut T {
78 #[inline]
79 async fn transaction(
80 &mut self,
81 operations: &mut [Operation<'_, Word>],
82 ) -> Result<(), Self::Error> {
83 T::transaction(self, operations).await
84 }
85
86 #[inline]
87 async fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
88 T::read(self, buf).await
89 }
90
91 #[inline]
92 async fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
93 T::write(self, buf).await
94 }
95
96 #[inline]
97 async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
98 T::transfer(self, read, write).await
99 }
100
101 #[inline]
102 async fn transfer_in_place(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
103 T::transfer_in_place(self, buf).await
104 }
105}
106
107/// SPI bus.
108///
109/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins.
110///
111/// See [the docs on embedded-hal][embedded_hal::spi] for important information on SPI Bus vs Device traits.
112pub trait SpiBus<Word: 'static + Copy = u8>: ErrorType {
113 /// Read `words` from the slave.
114 ///
115 /// The word value sent on MOSI during reading is implementation-defined,
116 /// typically `0x00`, `0xFF`, or configurable.
117 ///
118 /// Implementations are allowed to return before the operation is
119 /// complete. See [the docs on embedded-hal][embedded_hal::spi] for details on flushing.
120 async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
121
122 /// Write `words` to the slave, ignoring all the incoming words.
123 ///
124 /// Implementations are allowed to return before the operation is
125 /// complete. See [the docs on embedded-hal][embedded_hal::spi] for details on flushing.
126 async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>;
127
128 /// Write and read simultaneously. `write` is written to the slave on MOSI and
129 /// words received on MISO are stored in `read`.
130 ///
131 /// It is allowed for `read` and `write` to have different lengths, even zero length.
132 /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
133 /// incoming words after `read` has been filled will be discarded. If `write` is shorter,
134 /// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
135 /// typically `0x00`, `0xFF`, or configurable.
136 ///
137 /// Implementations are allowed to return before the operation is
138 /// complete. See [the docs on embedded-hal][embedded_hal::spi] for details on flushing.
139 async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>;
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 ///
145 /// Implementations are allowed to return before the operation is
146 /// complete. See [the docs on embedded-hal][embedded_hal::spi] for details on flushing.
147 async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
148
149 /// Wait until all operations have completed and the bus is idle.
150 ///
151 /// See [the docs on embedded-hal][embedded_hal::spi] for information on flushing.
152 async fn flush(&mut self) -> Result<(), Self::Error>;
153}
154
155impl<T: SpiBus<Word> + ?Sized, Word: 'static + Copy> SpiBus<Word> for &mut T {
156 #[inline]
157 async fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
158 T::read(self, words).await
159 }
160
161 #[inline]
162 async fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
163 T::write(self, words).await
164 }
165
166 #[inline]
167 async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
168 T::transfer(self, read, write).await
169 }
170
171 #[inline]
172 async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
173 T::transfer_in_place(self, words).await
174 }
175
176 #[inline]
177 async fn flush(&mut self) -> Result<(), Self::Error> {
178 T::flush(self).await
179 }
180}