1 | //! SPI master mode traits. |
2 | |
3 | pub 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. |
13 | pub 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 | |
77 | impl<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. |
112 | pub 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 | |
155 | impl<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 | } |
181 | |