1use embedded_hal_async::spi::SpiBus;
2use num_traits::{AsPrimitive, PrimInt};
3
4use super::SpiFuture;
5use crate::{
6 dmac::{
7 AnyChannel, Beat, Buffer, ReadyFuture,
8 channel::{self, Channel},
9 sram::DmacDescriptor,
10 },
11 sercom::{
12 Sercom,
13 dma::{
14 SharedSliceBuffer, SinkSourceBuffer,
15 async_dma::{self, read_dma, read_dma_linked, write_dma, write_dma_linked},
16 },
17 spi::{
18 Capability, Config, DataWidth, Duplex, Error, MasterMode, OpMode, Receive, Rx, Size,
19 Slave, Spi, Transmit, Tx, ValidConfig, ValidPads, Word,
20 },
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, T> SpiFuture<C, D, NoneT, T>
44where
45 C: ValidConfig<Sercom: Sercom, OpMode = Slave, Word: PrimInt + AsPrimitive<DataWidth>>,
46 D: Receive,
47 DataWidth: AsPrimitive<C::Word>,
48{
49 #[inline]
54 pub fn with_rx_dma_channel<Chan: AnyChannel<Status = ReadyFuture>>(
55 self,
56 rx_channel: Chan,
57 ) -> SpiFuture<C, D, Chan, T> {
58 SpiFuture {
59 spi: Spi {
60 config: self.spi.config,
61 capability: self.spi.capability,
62 _rx_channel: rx_channel,
63 _tx_channel: self.spi._tx_channel,
64 },
65 }
66 }
67}
68
69impl<C, D, R> SpiFuture<C, D, R, NoneT>
70where
71 C: ValidConfig<Sercom: Sercom, Word: PrimInt + AsPrimitive<DataWidth>>,
72 D: Transmit,
73 DataWidth: AsPrimitive<C::Word>,
74{
75 #[inline]
80 pub fn with_tx_dma_channel<Chan: AnyChannel<Status = ReadyFuture>>(
81 self,
82 tx_channel: Chan,
83 ) -> SpiFuture<C, D, R, Chan> {
84 SpiFuture {
85 spi: Spi {
86 config: self.spi.config,
87 capability: self.spi.capability,
88 _rx_channel: self.spi._rx_channel,
89 _tx_channel: tx_channel,
90 },
91 }
92 }
93}
94
95impl<C, D> SpiFuture<C, D, NoneT, NoneT>
96where
97 C: ValidConfig<Sercom: Sercom, OpMode: MasterMode, Word: PrimInt + AsPrimitive<DataWidth>>,
98 D: Receive,
99 DataWidth: AsPrimitive<C::Word>,
100{
101 #[inline]
107 pub fn with_dma_channels<R, T>(self, rx_channel: R, tx_channel: T) -> SpiFuture<C, D, R, T>
108 where
109 R: AnyChannel<Status = ReadyFuture>,
110 T: AnyChannel<Status = ReadyFuture>,
111 {
112 SpiFuture {
113 spi: Spi {
114 config: self.spi.config,
115 capability: self.spi.capability,
116 _rx_channel: rx_channel,
117 _tx_channel: tx_channel,
118 },
119 }
120 }
121}
122
123impl<C> SpiFuture<C, Duplex>
124where
125 C: ValidConfig<OpMode = Slave>,
126{
127 pub fn with_dma_channels_slave<R, T>(self, rx: R, tx: T) -> SpiFuture<C, Duplex, R, T>
132 where
133 R: AnyChannel<Status = ReadyFuture>,
134 T: AnyChannel<Status = ReadyFuture>,
135 {
136 SpiFuture {
137 spi: Spi {
138 capability: self.spi.capability,
139 config: self.spi.config,
140 _rx_channel: rx,
141 _tx_channel: tx,
142 },
143 }
144 }
145}
146
147impl<C, D, R, T> SpiFuture<C, D, R, T>
148where
149 C: ValidConfig,
150 D: Capability,
151{
152 pub fn take_dma_channels(self) -> (SpiFuture<C, D, NoneT, NoneT>, R, T)
155 where
156 R: AnyChannel<Status = ReadyFuture>,
157 T: AnyChannel<Status = ReadyFuture>,
158 {
159 let (spi, rx, tx) = self.spi.take_dma_channels();
160 (SpiFuture { spi }, rx, tx)
161 }
162
163 pub fn take_rx_channel(self) -> (SpiFuture<C, D, NoneT, T>, R)
166 where
167 R: AnyChannel<Status = ReadyFuture>,
168 {
169 let (spi, channel) = self.spi.take_rx_channel();
170 (SpiFuture { spi }, channel)
171 }
172
173 pub fn take_tx_channel(self) -> (SpiFuture<C, D, R, NoneT>, T)
176 where
177 T: AnyChannel<Status = ReadyFuture>,
178 {
179 let (spi, channel) = self.spi.take_tx_channel();
180 (SpiFuture { spi }, channel)
181 }
182}
183
184impl<P, M, Z, D, R, T, S> SpiFuture<Config<P, M, Z>, D, R, T>
186where
187 P: ValidPads,
188 M: OpMode,
189 Z: Size + 'static,
190 Config<P, M, Z>: ValidConfig<Sercom = S>,
191 D: Transmit,
192 S: Sercom,
193 Z::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
194 DataWidth: AsPrimitive<Z::Word>,
195 T: AnyChannel<Status = ReadyFuture>,
196{
197 #[inline]
199 pub async fn write_dma(&mut self, words: &[Z::Word]) -> Result<usize, Error> {
200 if words.is_empty() {
201 return Ok(0);
202 }
203
204 self.spi.config.as_mut().regs.rx_disable();
206
207 let sercom_ptr = self.spi.sercom_ptr();
208 let tx = self.spi._tx_channel.as_mut();
209 let mut buf = SharedSliceBuffer::from_slice(words);
210
211 let tx_result = async_dma::write_dma::<_, _, S>(tx, sercom_ptr, &mut buf).await;
212
213 if D::RX_ENABLE {
215 self.spi.config.as_mut().regs.rx_enable();
216 }
217
218 tx_result?;
219 Ok(words.len())
220 }
221}
222
223impl<P, M, S, C, D, R, T> SpiFuture<Config<P, M, C>, D, R, T>
224where
225 Config<P, M, C>: ValidConfig<Sercom = S>,
226 S: Sercom,
227 P: ValidPads,
228 M: MasterMode,
229 C: Size + 'static,
230 C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
231 D: Capability,
232 DataWidth: AsPrimitive<C::Word>,
233 R: AnyChannel<Status = ReadyFuture>,
234 T: AnyChannel<Status = ReadyFuture>,
235{
236 #[inline]
237 async fn transfer_blocking<Source: Buffer<Beat = C::Word>, Dest: Buffer<Beat = C::Word>>(
238 &mut self,
239 dest: &mut Dest,
240 source: &mut Source,
241 ) -> Result<(), Error> {
242 let sercom_ptr = self.spi.sercom_ptr();
243 let rx = self.spi._rx_channel.as_mut();
244 let tx = self.spi._tx_channel.as_mut();
245
246 let (rx_result, tx_result) = futures::join!(
247 read_dma::<_, _, S>(rx, sercom_ptr.clone(), dest),
248 write_dma::<_, _, S>(tx, sercom_ptr, source)
249 );
250
251 self.spi.read_status().check_bus_error()?;
253 rx_result.and(tx_result)?;
254 Ok(())
255 }
256
257 #[inline]
259 pub async fn read_dma_master(&mut self, mut words: &mut [C::Word]) -> Result<(), Error> {
260 if words.is_empty() {
261 return Ok(());
262 }
263
264 let mut source_word = self.spi.config.nop_word.as_();
265 let mut source = SinkSourceBuffer::new(&mut source_word, words.len());
266
267 self.transfer_blocking(&mut words, &mut source).await
268 }
269}
270
271impl<P, M, C, S, R, T> SpiBus<Word<C>> for SpiFuture<Config<P, M, C>, Duplex, R, T>
273where
274 S: Sercom,
275 Config<P, M, C>: ValidConfig<Sercom = S>,
276 P: ValidPads,
277 M: MasterMode,
278 C: Size + 'static,
279 C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
280 DataWidth: AsPrimitive<C::Word>,
281 R: AnyChannel<Status = ReadyFuture>,
282 T: AnyChannel<Status = ReadyFuture>,
283{
284 #[inline]
285 async fn read(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
286 self.read_dma_master(words).await
287 }
288
289 #[inline]
290 async fn write(&mut self, words: &[C::Word]) -> Result<(), Self::Error> {
291 self.write_dma(words).await?;
292 Ok(())
293 }
294
295 #[inline]
296 async fn transfer(
297 &mut self,
298 mut read: &mut [C::Word],
299 write: &[C::Word],
300 ) -> Result<(), Self::Error> {
301 use core::cmp::Ordering;
302
303 if write.is_empty() && read.is_empty() {
305 return Ok(());
306 }
307
308 if write.is_empty() {
310 return self.read_dma_master(read).await;
311 } else if read.is_empty() {
312 self.write_dma(write).await?;
313 return Ok(());
314 }
315
316 let mut linked_descriptor = DmacDescriptor::default();
320
321 let mut source_sink_word = self.spi.config.as_mut().nop_word.as_();
327 let mut sercom_ptr = self.spi.sercom_ptr();
328
329 let (read_link, write_link) = match read.len().cmp(&write.len()) {
330 Ordering::Equal => {
331 let mut write = SharedSliceBuffer::from_slice(write);
332 return self.transfer_blocking(&mut read, &mut write).await;
333 }
334
335 Ordering::Less => {
338 let mut sink =
339 SinkSourceBuffer::new(&mut source_sink_word, write.len() - read.len());
340 unsafe {
341 channel::write_descriptor(
342 &mut linked_descriptor,
343 &mut sercom_ptr,
344 &mut sink,
345 core::ptr::null_mut(),
347 );
348 }
349
350 (Some(&mut linked_descriptor), None)
351 }
352
353 Ordering::Greater => {
356 let mut source =
357 SinkSourceBuffer::new(&mut source_sink_word, read.len() - write.len());
358 unsafe {
359 channel::write_descriptor(
360 &mut linked_descriptor,
361 &mut source,
362 &mut sercom_ptr,
363 core::ptr::null_mut(),
365 );
366 }
367
368 (None, Some(&mut linked_descriptor))
369 }
370 };
371
372 let rx = self.spi._rx_channel.as_mut();
373 let tx = self.spi._tx_channel.as_mut();
374
375 let mut write = SharedSliceBuffer::from_slice(write);
376
377 let (rx_result, tx_result) = unsafe {
381 futures::join!(
382 read_dma_linked::<_, _, S>(rx, sercom_ptr.clone(), &mut read, read_link),
383 write_dma_linked::<_, _, S>(tx, sercom_ptr, &mut write, write_link)
384 )
385 };
386
387 self.spi.read_status().check_bus_error()?;
389 rx_result.and(tx_result)?;
390 Ok(())
391 }
392
393 #[inline]
394 async fn transfer_in_place(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
395 unsafe {
403 let mut read_buf = SharedSliceBuffer::from_slice_unchecked(words);
404 let mut write_buf = SharedSliceBuffer::from_slice(words);
405 self.transfer_blocking(&mut read_buf, &mut write_buf).await
406 }
407 }
408
409 #[inline]
410 async fn flush(&mut self) -> Result<(), Self::Error> {
411 self.flush_tx().await;
413 Ok(())
414 }
415}
416
417impl<P, M, Z, D, R, T> embedded_io_async::Write for SpiFuture<Config<P, M, Z>, D, R, T>
420where
421 P: ValidPads,
422 M: OpMode,
423 Z: Size<Word = u8> + 'static,
424 Config<P, M, Z>: ValidConfig<Sercom: Sercom>,
425 D: Transmit,
426 T: AnyChannel<Status = ReadyFuture>,
427{
428 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
429 SpiFuture::write_dma(self, buf).await
430 }
431
432 async fn flush(&mut self) -> Result<(), Self::Error> {
433 self.flush_tx().await;
434 Ok(())
435 }
436}
437
438impl<P, M, Z, D, R, T> embedded_io_async::Read for SpiFuture<Config<P, M, Z>, D, R, T>
441where
442 P: ValidPads,
443 M: MasterMode,
444 Z: Size<Word = u8> + 'static,
445 Config<P, M, Z>: ValidConfig<Sercom: Sercom>,
446 D: Receive,
447 R: AnyChannel<Status = ReadyFuture>,
448 T: AnyChannel<Status = ReadyFuture>,
449{
450 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
451 self.read_dma_master(buf).await?;
452 Ok(buf.len())
453 }
454}
455
456impl<P, Z, D, R, T, S> embedded_io_async::Read for SpiFuture<Config<P, Slave, Z>, D, R, T>
459where
460 P: ValidPads,
461 Z: Size<Word = u8> + 'static,
462 Config<P, Slave, Z>: ValidConfig<Sercom = S>,
463 D: Receive,
464 S: Sercom,
465 R: AnyChannel<Status = ReadyFuture>,
466{
467 async fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
468 if buf.is_empty() {
469 return Ok(0);
470 }
471
472 self.flush_rx().await?;
476 let sercom_ptr = self.spi.sercom_ptr();
477 let rx = self.spi._rx_channel.as_mut();
478
479 let result = read_dma::<_, _, S>(rx, sercom_ptr.clone(), &mut buf).await;
482
483 self.flush_rx().await?;
485 result?;
486 Ok(buf.len())
487 }
488}