1use embedded_hal_async::spi::SpiBus;
2use num_traits::{AsPrimitive, PrimInt};
3
4use super::SpiFuture;
5use crate::{
6 dmac::{
7 channel::{self, Channel},
8 sram::DmacDescriptor,
9 AnyChannel, Beat, Buffer, ReadyFuture,
10 },
11 sercom::{
12 dma::{
13 async_dma::{self, read_dma, read_dma_linked, write_dma, write_dma_linked},
14 SharedSliceBuffer, SinkSourceBuffer,
15 },
16 spi::{
17 Capability, Config, DataWidth, Duplex, Error, MasterMode, OpMode, Receive, Rx, Size,
18 Slave, Spi, Transmit, Tx, ValidConfig, ValidPads, Word,
19 },
20 Sercom,
21 },
22 typelevel::NoneT,
23};
24
25pub type SpiFutureDuplexDma<C, R, T> =
31 SpiFuture<C, Duplex, Channel<R, ReadyFuture>, Channel<T, ReadyFuture>>;
32
33pub type SpiFutureRxDma<C, R> = SpiFuture<C, Rx, Channel<R, ReadyFuture>, NoneT>;
37
38pub type SpiFutureTxDma<C, T> = SpiFuture<C, Tx, NoneT, Channel<T, ReadyFuture>>;
42
43impl<C, D, RxDma, TxDma> SpiFuture<C, D, RxDma, TxDma>
44where
45 C: ValidConfig,
46 D: Capability,
47 RxDma: AnyChannel<Status = ReadyFuture>,
48 TxDma: AnyChannel<Status = ReadyFuture>,
49{
50 pub fn take_dma_channels(self) -> (SpiFuture<C, D, NoneT, NoneT>, RxDma, TxDma) {
53 let (spi, rx, tx) = self.spi.take_dma_channels();
54 (SpiFuture { spi }, rx, tx)
55 }
56}
57
58impl<C, D, R, T> SpiFuture<C, D, R, T>
59where
60 C: ValidConfig,
61 D: Receive,
62 R: AnyChannel<Status = ReadyFuture>,
63{
64 pub fn take_rx_channel(self) -> (SpiFuture<C, D, NoneT, T>, R) {
67 let (spi, channel) = self.spi.take_rx_channel();
68 (SpiFuture { spi }, channel)
69 }
70}
71
72impl<C, D, R, T> SpiFuture<C, D, R, T>
73where
74 C: ValidConfig,
75 D: Capability,
76 T: AnyChannel<Status = ReadyFuture>,
77{
78 pub fn take_tx_channel(self) -> (SpiFuture<C, D, R, NoneT>, T) {
81 let (spi, channel) = self.spi.take_tx_channel();
82 (SpiFuture { spi }, channel)
83 }
84}
85
86impl<C, S, R> SpiFuture<C, Rx, R, NoneT>
87where
88 C: ValidConfig<Sercom = S>,
89 C::Word: PrimInt + AsPrimitive<DataWidth>,
90 DataWidth: AsPrimitive<C::Word>,
91 S: Sercom,
92{
93 #[inline]
95 pub fn with_rx_dma_channel<Chan: AnyChannel<Status = ReadyFuture>>(
96 self,
97 rx_channel: Chan,
98 ) -> SpiFuture<C, Rx, Chan, NoneT> {
99 SpiFuture {
100 spi: Spi {
101 config: self.spi.config,
102 capability: self.spi.capability,
103 _rx_channel: rx_channel,
104 _tx_channel: self.spi._tx_channel,
105 },
106 }
107 }
108}
109
110impl<C, S, T> SpiFuture<C, Tx, NoneT, T>
111where
112 C: ValidConfig<Sercom = S>,
113 C::Word: PrimInt + AsPrimitive<DataWidth>,
114 DataWidth: AsPrimitive<C::Word>,
115 S: Sercom,
116{
117 #[inline]
119 pub fn with_tx_dma_channel<Chan: AnyChannel<Status = ReadyFuture>>(
120 self,
121 tx_channel: Chan,
122 ) -> SpiFuture<C, Tx, NoneT, Chan> {
123 SpiFuture {
124 spi: Spi {
125 config: self.spi.config,
126 capability: self.spi.capability,
127 _rx_channel: self.spi._rx_channel,
128 _tx_channel: tx_channel,
129 },
130 }
131 }
132}
133
134impl<C, S, R, T> SpiFuture<C, Duplex, R, T>
135where
136 C: ValidConfig<Sercom = S>,
137 C::Word: PrimInt + AsPrimitive<DataWidth>,
138 DataWidth: AsPrimitive<C::Word>,
139 S: Sercom,
140{
141 #[inline]
143 pub fn with_dma_channels<ChanRx, ChanTx>(
144 self,
145 rx_channel: ChanRx,
146 tx_channel: ChanTx,
147 ) -> SpiFuture<C, Duplex, ChanRx, ChanTx>
148 where
149 ChanRx: AnyChannel<Status = ReadyFuture>,
150 ChanTx: AnyChannel<Status = ReadyFuture>,
151 {
152 SpiFuture {
153 spi: Spi {
154 config: self.spi.config,
155 capability: self.spi.capability,
156 _rx_channel: rx_channel,
157 _tx_channel: tx_channel,
158 },
159 }
160 }
161}
162
163impl<P, M, Z, D, R, T, S> SpiFuture<Config<P, M, Z>, D, R, T>
165where
166 P: ValidPads,
167 M: OpMode,
168 Z: Size + 'static,
169 Config<P, M, Z>: ValidConfig<Sercom = S>,
170 D: Transmit,
171 S: Sercom,
172 Z::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
173 DataWidth: AsPrimitive<Z::Word>,
174 T: AnyChannel<Status = ReadyFuture>,
175{
176 #[inline]
178 pub async fn write_dma(&mut self, words: &[Z::Word]) -> Result<usize, Error> {
179 if words.is_empty() {
180 return Ok(0);
181 }
182
183 self.spi.config.as_mut().regs.rx_disable();
185
186 let sercom_ptr = self.spi.sercom_ptr();
187 let tx = self.spi._tx_channel.as_mut();
188 let mut buf = SharedSliceBuffer::from_slice(words);
189
190 let tx_result = async_dma::write_dma::<_, _, S>(tx, sercom_ptr, &mut buf).await;
191
192 if D::RX_ENABLE {
194 self.spi.config.as_mut().regs.rx_enable();
195 }
196
197 tx_result?;
198 Ok(words.len())
199 }
200}
201
202impl<P, M, S, C, D, R, T> SpiFuture<Config<P, M, C>, D, R, T>
203where
204 Config<P, M, C>: ValidConfig<Sercom = S>,
205 S: Sercom,
206 P: ValidPads,
207 M: MasterMode,
208 C: Size + 'static,
209 C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
210 D: Capability,
211 DataWidth: AsPrimitive<C::Word>,
212 R: AnyChannel<Status = ReadyFuture>,
213 T: AnyChannel<Status = ReadyFuture>,
214{
215 #[inline]
216 async fn transfer_blocking<Source: Buffer<Beat = C::Word>, Dest: Buffer<Beat = C::Word>>(
217 &mut self,
218 dest: &mut Dest,
219 source: &mut Source,
220 ) -> Result<(), Error> {
221 let sercom_ptr = self.spi.sercom_ptr();
222 let rx = self.spi._rx_channel.as_mut();
223 let tx = self.spi._tx_channel.as_mut();
224
225 let (rx_result, tx_result) = futures::join!(
226 read_dma::<_, _, S>(rx, sercom_ptr.clone(), dest),
227 write_dma::<_, _, S>(tx, sercom_ptr, source)
228 );
229
230 self.spi.read_status().check_bus_error()?;
232 rx_result.and(tx_result)?;
233 Ok(())
234 }
235
236 #[inline]
238 pub async fn read_dma_master(&mut self, mut words: &mut [C::Word]) -> Result<(), Error> {
239 if words.is_empty() {
240 return Ok(());
241 }
242
243 let mut source_word = self.spi.config.nop_word.as_();
244 let mut source = SinkSourceBuffer::new(&mut source_word, words.len());
245
246 self.transfer_blocking(&mut words, &mut source).await
247 }
248}
249
250impl<P, M, C, S, R, T> SpiBus<Word<C>> for SpiFuture<Config<P, M, C>, Duplex, R, T>
252where
253 S: Sercom,
254 Config<P, M, C>: ValidConfig<Sercom = S>,
255 P: ValidPads,
256 M: MasterMode,
257 C: Size + 'static,
258 C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
259 DataWidth: AsPrimitive<C::Word>,
260 R: AnyChannel<Status = ReadyFuture>,
261 T: AnyChannel<Status = ReadyFuture>,
262{
263 #[inline]
264 async fn read(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
265 self.read_dma_master(words).await
266 }
267
268 #[inline]
269 async fn write(&mut self, words: &[C::Word]) -> Result<(), Self::Error> {
270 self.write_dma(words).await?;
271 Ok(())
272 }
273
274 #[inline]
275 async fn transfer(
276 &mut self,
277 mut read: &mut [C::Word],
278 write: &[C::Word],
279 ) -> Result<(), Self::Error> {
280 use core::cmp::Ordering;
281
282 if write.is_empty() && read.is_empty() {
284 return Ok(());
285 }
286
287 if write.is_empty() {
289 return self.read_dma_master(read).await;
290 } else if read.is_empty() {
291 self.write_dma(write).await?;
292 return Ok(());
293 }
294
295 let mut linked_descriptor = DmacDescriptor::default();
299
300 let mut source_sink_word = self.spi.config.as_mut().nop_word.as_();
306 let mut sercom_ptr = self.spi.sercom_ptr();
307
308 let (read_link, write_link) = match read.len().cmp(&write.len()) {
309 Ordering::Equal => {
310 let mut write = SharedSliceBuffer::from_slice(write);
311 return self.transfer_blocking(&mut read, &mut write).await;
312 }
313
314 Ordering::Less => {
317 let mut sink =
318 SinkSourceBuffer::new(&mut source_sink_word, write.len() - read.len());
319 unsafe {
320 channel::write_descriptor(
321 &mut linked_descriptor,
322 &mut sercom_ptr,
323 &mut sink,
324 core::ptr::null_mut(),
326 );
327 }
328
329 (Some(&mut linked_descriptor), None)
330 }
331
332 Ordering::Greater => {
335 let mut source =
336 SinkSourceBuffer::new(&mut source_sink_word, read.len() - write.len());
337 unsafe {
338 channel::write_descriptor(
339 &mut linked_descriptor,
340 &mut source,
341 &mut sercom_ptr,
342 core::ptr::null_mut(),
344 );
345 }
346
347 (None, Some(&mut linked_descriptor))
348 }
349 };
350
351 let rx = self.spi._rx_channel.as_mut();
352 let tx = self.spi._tx_channel.as_mut();
353
354 let mut write = SharedSliceBuffer::from_slice(write);
355
356 let (rx_result, tx_result) = unsafe {
360 futures::join!(
361 read_dma_linked::<_, _, S>(rx, sercom_ptr.clone(), &mut read, read_link),
362 write_dma_linked::<_, _, S>(tx, sercom_ptr, &mut write, write_link)
363 )
364 };
365
366 self.spi.read_status().check_bus_error()?;
368 rx_result.and(tx_result)?;
369 Ok(())
370 }
371
372 #[inline]
373 async fn transfer_in_place(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
374 unsafe {
382 let mut read_buf = SharedSliceBuffer::from_slice_unchecked(words);
383 let mut write_buf = SharedSliceBuffer::from_slice(words);
384 self.transfer_blocking(&mut read_buf, &mut write_buf).await
385 }
386 }
387
388 #[inline]
389 async fn flush(&mut self) -> Result<(), Self::Error> {
390 self.flush_tx().await;
392 Ok(())
393 }
394}
395
396impl<P, M, Z, D, R, T, S> embedded_io_async::Write for SpiFuture<Config<P, M, Z>, D, R, T>
399where
400 P: ValidPads,
401 M: OpMode,
402 Z: Size<Word = u8> + 'static,
403 Config<P, M, Z>: ValidConfig<Sercom = S>,
404 D: Transmit,
405 S: Sercom,
406 T: AnyChannel<Status = ReadyFuture>,
407{
408 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
409 SpiFuture::write_dma(self, buf).await
410 }
411
412 async fn flush(&mut self) -> Result<(), Self::Error> {
413 self.flush_tx().await;
414 Ok(())
415 }
416}
417
418impl<P, M, Z, D, R, T, S> embedded_io_async::Read for SpiFuture<Config<P, M, Z>, D, R, T>
421where
422 P: ValidPads,
423 M: MasterMode,
424 Z: Size<Word = u8> + 'static,
425 Config<P, M, Z>: ValidConfig<Sercom = S>,
426 D: Receive,
427 S: Sercom,
428 R: AnyChannel<Status = ReadyFuture>,
429 T: AnyChannel<Status = ReadyFuture>,
430{
431 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
432 self.read_dma_master(buf).await?;
433 Ok(buf.len())
434 }
435}
436
437impl<P, Z, D, R, T, S> embedded_io_async::Read for SpiFuture<Config<P, Slave, Z>, D, R, T>
440where
441 P: ValidPads,
442 Z: Size<Word = u8> + 'static,
443 Config<P, Slave, Z>: ValidConfig<Sercom = S>,
444 D: Receive,
445 S: Sercom,
446 R: AnyChannel<Status = ReadyFuture>,
447{
448 async fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
449 if buf.is_empty() {
450 return Ok(0);
451 }
452
453 self.flush_rx().await?;
457 let sercom_ptr = self.spi.sercom_ptr();
458 let rx = self.spi._rx_channel.as_mut();
459
460 let result = read_dma::<_, _, S>(rx, sercom_ptr.clone(), &mut buf).await;
463
464 self.flush_rx().await?;
466 result?;
467 Ok(buf.len())
468 }
469}