1use core::{marker::PhantomData, ops::Range};
7
8use atsamd_hal_macros::hal_macro_helper;
9
10use crate::{
11 dmac::{
12 self,
13 channel::{AnyChannel, Busy, Channel, InterruptFlags, Ready},
14 sram::DmacDescriptor,
15 transfer::BufferPair,
16 Beat, Buffer, Transfer, TriggerAction,
17 },
18 sercom::{
19 i2c::{self, I2c},
20 spi::{self, Spi},
21 uart::{self, Uart},
22 Sercom,
23 },
24};
25
26#[doc(hidden)]
35pub(crate) struct SharedSliceBuffer<'a, T: Beat> {
36 ptrs: Range<*mut T>,
37 _lifetime: PhantomData<&'a T>,
38}
39
40impl<'a, T: Beat> SharedSliceBuffer<'a, T> {
41 #[inline]
42 pub(in super::super) fn from_slice(slice: &'a [T]) -> Self {
43 unsafe { Self::from_slice_unchecked(slice) }
44 }
45
46 #[inline]
47 pub(in super::super) unsafe fn from_slice_unchecked(slice: &[T]) -> Self {
48 let ptrs = slice.as_ptr_range();
49
50 let ptrs = Range {
51 start: ptrs.start.cast_mut(),
52 end: ptrs.end.cast_mut(),
53 };
54
55 Self {
56 ptrs,
57 _lifetime: PhantomData,
58 }
59 }
60}
61
62unsafe impl<T: Beat> Buffer for SharedSliceBuffer<'_, T> {
63 type Beat = T;
64 #[inline]
65 fn dma_ptr(&mut self) -> *mut Self::Beat {
66 if self.incrementing() {
67 self.ptrs.end
68 } else {
69 self.ptrs.start
70 }
71 }
72
73 #[inline]
74 fn incrementing(&self) -> bool {
75 self.buffer_len() > 1
76 }
77
78 #[inline]
79 fn buffer_len(&self) -> usize {
80 self.ptrs.end as usize - self.ptrs.start as usize
81 }
82}
83
84pub(super) struct SinkSourceBuffer<'a, T: Beat> {
94 word: &'a mut T,
95 length: usize,
96}
97
98impl<'a, T: Beat> SinkSourceBuffer<'a, T> {
99 pub(super) fn new(word: &'a mut T, length: usize) -> Self {
100 Self { word, length }
101 }
102}
103unsafe impl<T: Beat> Buffer for SinkSourceBuffer<'_, T> {
104 type Beat = T;
105 #[inline]
106 fn incrementing(&self) -> bool {
107 false
108 }
109
110 #[inline]
111 fn buffer_len(&self) -> usize {
112 self.length
113 }
114
115 #[inline]
116 fn dma_ptr(&mut self) -> *mut Self::Beat {
117 self.word as *mut _
118 }
119}
120#[doc(hidden)]
124#[derive(Clone)]
125pub(crate) struct SercomPtr<T: Beat>(pub(in super::super) *mut T);
126
127unsafe impl<T: Beat> Buffer for SercomPtr<T> {
128 type Beat = T;
129
130 #[inline]
131 fn dma_ptr(&mut self) -> *mut Self::Beat {
132 self.0
133 }
134
135 #[inline]
136 fn incrementing(&self) -> bool {
137 false
138 }
139
140 #[inline]
141 fn buffer_len(&self) -> usize {
142 1
143 }
144}
145
146#[deprecated(
156 since = "0.19.0",
157 note = "Use `I2c::with_dma_channel` instead. You will have access to DMA-enabled `embedded-hal` implementations."
158)]
159pub struct I2cBusReady;
160
161unsafe impl<C: i2c::AnyConfig> Buffer for I2c<C> {
162 type Beat = i2c::Word;
163
164 #[inline]
165 fn dma_ptr(&mut self) -> *mut Self::Beat {
166 self.data_ptr()
167 }
168
169 #[inline]
170 fn incrementing(&self) -> bool {
171 false
172 }
173
174 #[inline]
175 fn buffer_len(&self) -> usize {
176 1
177 }
178}
179
180impl<C: i2c::AnyConfig> I2c<C> {
181 #[deprecated(
200 since = "0.19.0",
201 note = "Use `I2c::with_dma_channel` instead. You will have access to DMA-enabled `embedded-hal` implementations."
202 )]
203 #[allow(deprecated)]
204 pub fn init_dma_transfer(&mut self) -> Result<I2cBusReady, super::i2c::Error> {
205 self.check_bus_status()?;
206 Ok(I2cBusReady)
207 }
208
209 #[deprecated(
216 since = "0.19.0",
217 note = "Use `I2c::with_dma_channel` instead. You will have access to DMA-enabled `embedded-hal` implementations."
218 )]
219 #[allow(deprecated)]
220 #[hal_macro_helper]
221 pub fn receive_with_dma<Ch, B>(
222 self,
223 address: u8,
224 _ready_token: I2cBusReady,
225 buf: B,
226 mut channel: Ch,
227 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<Self, B>>
228 where
229 Ch: AnyChannel<Status = Ready>,
230 B: Buffer<Beat = i2c::Word> + 'static,
231 {
232 let len = buf.buffer_len();
233 assert!(len > 0 && len <= 255);
234
235 channel
236 .as_mut()
237 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
238
239 #[hal_cfg("sercom0-d5x")]
240 let trigger_action = TriggerAction::Burst;
241
242 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
243 let trigger_action = TriggerAction::Beat;
244
245 let xfer = unsafe { dmac::Transfer::new_unchecked(channel, self, buf, false) };
248 let mut xfer = xfer.begin(C::Sercom::DMA_RX_TRIGGER, trigger_action);
249
250 unsafe { xfer.borrow_source().start_dma_read(address, len as u8) };
255 xfer
256 }
257
258 #[inline]
265 #[hal_macro_helper]
266 #[deprecated(
267 since = "0.19.0",
268 note = "Use `I2c::with_dma_chahnnel` instead. You will have access to DMA-enabled `embedded-hal` implementations."
269 )]
270 #[allow(deprecated)]
271 pub fn send_with_dma<Ch, B>(
272 self,
273 address: u8,
274 _ready_token: I2cBusReady,
275 buf: B,
276 mut channel: Ch,
277 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<B, Self>>
278 where
279 Ch: AnyChannel<Status = Ready>,
280 B: Buffer<Beat = i2c::Word> + 'static,
281 {
282 let len = buf.buffer_len();
283 assert!(len > 0 && len <= 255);
284
285 channel
286 .as_mut()
287 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
288
289 #[hal_cfg("sercom0-d5x")]
290 let trigger_action = TriggerAction::Burst;
291
292 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
293 let trigger_action = TriggerAction::Beat;
294
295 let xfer = unsafe { dmac::Transfer::new_unchecked(channel, buf, self, false) };
298 let mut xfer = xfer.begin(C::Sercom::DMA_TX_TRIGGER, trigger_action);
299
300 unsafe {
305 xfer.borrow_destination()
306 .start_dma_write(address, len as u8)
307 };
308 xfer
309 }
310}
311
312unsafe impl<C, D> Buffer for Uart<C, D>
316where
317 C: uart::ValidConfig,
318 C::Word: Beat,
319 D: uart::Capability,
320{
321 type Beat = C::Word;
322
323 #[inline]
324 fn dma_ptr(&mut self) -> *mut Self::Beat {
325 self.data_ptr()
326 }
327
328 #[inline]
329 fn incrementing(&self) -> bool {
330 false
331 }
332
333 #[inline]
334 fn buffer_len(&self) -> usize {
335 1
336 }
337}
338
339impl<C, D> Uart<C, D>
340where
341 Self: Buffer<Beat = C::Word>,
342 C: uart::ValidConfig,
343 D: uart::Receive,
344{
345 #[inline]
354 #[hal_macro_helper]
355 pub fn receive_with_dma<Ch, B>(
356 self,
357 buf: B,
358 mut channel: Ch,
359 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<Self, B>>
360 where
361 Ch: AnyChannel<Status = Ready>,
362 B: Buffer<Beat = C::Word> + 'static,
363 {
364 channel
365 .as_mut()
366 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
367
368 #[hal_cfg("sercom0-d5x")]
369 let trigger_action = TriggerAction::Burst;
370
371 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
372 let trigger_action = TriggerAction::Beat;
373
374 let xfer = unsafe { dmac::Transfer::new_unchecked(channel, self, buf, false) };
377 xfer.begin(C::Sercom::DMA_RX_TRIGGER, trigger_action)
378 }
379}
380
381impl<C, D> Uart<C, D>
382where
383 Self: Buffer<Beat = C::Word>,
384 C: uart::ValidConfig,
385 D: uart::Transmit,
386{
387 #[inline]
396 #[hal_macro_helper]
397 pub fn send_with_dma<Ch, B>(
398 self,
399 buf: B,
400 mut channel: Ch,
401 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<B, Self>>
402 where
403 Ch: AnyChannel<Status = Ready>,
404 B: Buffer<Beat = C::Word> + 'static,
405 {
406 channel
407 .as_mut()
408 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
409
410 #[hal_cfg("sercom0-d5x")]
411 let trigger_action = TriggerAction::Burst;
412
413 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
414 let trigger_action = TriggerAction::Beat;
415
416 let xfer = unsafe { dmac::Transfer::new_unchecked(channel, buf, self, false) };
419 xfer.begin(C::Sercom::DMA_TX_TRIGGER, trigger_action)
420 }
421}
422
423unsafe impl<C, A> Buffer for Spi<C, A>
428where
429 C: spi::ValidConfig,
430 C::OpMode: spi::MasterMode,
431 C::Size: spi::AtomicSize<Word = C::Word>,
432 C::Word: Beat,
433 A: spi::Capability,
434{
435 type Beat = C::Word;
436
437 #[inline]
438 fn dma_ptr(&mut self) -> *mut Self::Beat {
439 self.data_ptr()
440 }
441
442 #[inline]
443 fn incrementing(&self) -> bool {
444 false
445 }
446
447 #[inline]
448 fn buffer_len(&self) -> usize {
449 1
450 }
451}
452
453impl<C, A> Spi<C, A>
454where
455 C: spi::ValidConfig,
456 A: spi::Transmit,
457 Self: Buffer<Beat = C::Word>,
458{
459 #[inline]
462 #[hal_macro_helper]
463 #[deprecated(
464 since = "0.19.0",
465 note = "Use `Spi::with_dma_channels` instead. You will have access to DMA-enabled `embedded-hal` implementations."
466 )]
467 pub fn send_with_dma<Ch, B>(
468 self,
469 buf: B,
470 mut channel: Ch,
471 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<B, Self>>
472 where
473 Ch: AnyChannel<Status = Ready>,
474 B: Buffer<Beat = C::Word> + 'static,
475 {
476 channel
477 .as_mut()
478 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
479
480 #[hal_cfg("sercom0-d5x")]
481 let trigger_action = TriggerAction::Burst;
482
483 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
484 let trigger_action = TriggerAction::Beat;
485
486 let xfer = unsafe { Transfer::new_unchecked(channel, buf, self, false) };
489 xfer.begin(C::Sercom::DMA_TX_TRIGGER, trigger_action)
490 }
491}
492
493impl<C, A> Spi<C, A>
494where
495 C: spi::ValidConfig,
496 A: spi::Receive,
497 Self: Buffer<Beat = C::Word>,
498{
499 #[inline]
502 #[hal_macro_helper]
503 #[deprecated(
504 since = "0.19.0",
505 note = "Use `Spi::with_dma_channels` instead. You will have access to DMA-enabled `embedded-hal` implementations."
506 )]
507 pub fn receive_with_dma<Ch, B>(
508 self,
509 buf: B,
510 mut channel: Ch,
511 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<Self, B>>
512 where
513 Ch: AnyChannel<Status = Ready>,
514 B: Buffer<Beat = C::Word> + 'static,
515 {
516 channel
517 .as_mut()
518 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
519
520 #[hal_cfg("sercom0-d5x")]
521 let trigger_action = TriggerAction::Burst;
522
523 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
524 let trigger_action = TriggerAction::Beat;
525
526 let xfer = unsafe { Transfer::new_unchecked(channel, self, buf, false) };
529 xfer.begin(C::Sercom::DMA_RX_TRIGGER, trigger_action)
530 }
531}
532
533#[hal_macro_helper]
540pub(super) unsafe fn read_dma<T, B, S>(
541 channel: &mut impl AnyChannel<Status = Ready>,
542 sercom_ptr: SercomPtr<T>,
543 buf: &mut B,
544) where
545 T: Beat,
546 B: Buffer<Beat = T>,
547 S: Sercom,
548{
549 read_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None);
550}
551
552#[hal_macro_helper]
560pub(super) unsafe fn read_dma_linked<T, B, S>(
561 channel: &mut impl AnyChannel<Status = Ready>,
562 mut sercom_ptr: SercomPtr<T>,
563 buf: &mut B,
564 next: Option<&mut DmacDescriptor>,
565) where
566 T: Beat,
567 B: Buffer<Beat = T>,
568 S: Sercom,
569{
570 #[hal_cfg("dmac-d5x")]
571 let trigger_action = TriggerAction::Burst;
572
573 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
574 let trigger_action = TriggerAction::Beat;
575
576 channel.as_mut().transfer_unchecked(
579 &mut sercom_ptr,
580 buf,
581 S::DMA_RX_TRIGGER,
582 trigger_action,
583 next,
584 );
585}
586
587#[hal_macro_helper]
594pub(super) unsafe fn write_dma<T, B, S>(
595 channel: &mut impl AnyChannel<Status = Ready>,
596 sercom_ptr: SercomPtr<T>,
597 buf: &mut B,
598) where
599 T: Beat,
600 B: Buffer<Beat = T>,
601 S: Sercom,
602{
603 write_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None);
604}
605
606#[hal_macro_helper]
614pub(super) unsafe fn write_dma_linked<T, B, S>(
615 channel: &mut impl AnyChannel<Status = Ready>,
616 mut sercom_ptr: SercomPtr<T>,
617 buf: &mut B,
618 next: Option<&mut DmacDescriptor>,
619) where
620 T: Beat,
621 B: Buffer<Beat = T>,
622 S: Sercom,
623{
624 #[hal_cfg("dmac-d5x")]
625 let trigger_action = TriggerAction::Burst;
626
627 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
628 let trigger_action = TriggerAction::Beat;
629
630 channel.as_mut().transfer_unchecked(
633 buf,
634 &mut sercom_ptr,
635 S::DMA_TX_TRIGGER,
636 trigger_action,
637 next,
638 );
639}
640
641#[cfg(feature = "async")]
647pub(crate) mod async_dma {
648 use dmac::{Error, ReadyFuture};
649
650 use super::*;
651
652 #[inline]
654 pub(in super::super) async fn read_dma<T, B, S>(
655 channel: &mut impl AnyChannel<Status = ReadyFuture>,
656 sercom_ptr: SercomPtr<T>,
657 buf: &mut B,
658 ) -> Result<(), Error>
659 where
660 B: Buffer<Beat = T>,
661 T: Beat,
662 S: Sercom,
663 {
664 unsafe { read_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None).await }
665 }
666
667 #[inline]
676 #[hal_macro_helper]
677 pub(in super::super) async unsafe fn read_dma_linked<T, B, S>(
678 channel: &mut impl AnyChannel<Status = ReadyFuture>,
679 mut sercom_ptr: SercomPtr<T>,
680 buf: &mut B,
681 next: Option<&mut DmacDescriptor>,
682 ) -> Result<(), Error>
683 where
684 T: Beat,
685 B: Buffer<Beat = T>,
686 S: Sercom,
687 {
688 #[hal_cfg("dmac-d5x")]
689 let trigger_action = TriggerAction::Burst;
690
691 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
692 let trigger_action = TriggerAction::Beat;
693
694 channel
697 .as_mut()
698 .transfer_future_linked(
699 &mut sercom_ptr,
700 buf,
701 S::DMA_RX_TRIGGER,
702 trigger_action,
703 next,
704 )
705 .await
706 }
707
708 #[inline]
710 pub(in super::super) async fn write_dma<T, B, S>(
711 channel: &mut impl AnyChannel<Status = ReadyFuture>,
712 sercom_ptr: SercomPtr<T>,
713 buf: &mut B,
714 ) -> Result<(), Error>
715 where
716 B: Buffer<Beat = T>,
717 T: Beat,
718 S: Sercom,
719 {
720 unsafe { write_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None).await }
721 }
722
723 #[inline]
732 #[hal_macro_helper]
733 pub(in super::super) async unsafe fn write_dma_linked<T, B, S>(
734 channel: &mut impl AnyChannel<Status = ReadyFuture>,
735 mut sercom_ptr: SercomPtr<T>,
736 buf: &mut B,
737 next: Option<&mut DmacDescriptor>,
738 ) -> Result<(), Error>
739 where
740 B: Buffer<Beat = T>,
741 T: Beat,
742 S: Sercom,
743 {
744 #[hal_cfg("dmac-d5x")]
745 let trigger_action = TriggerAction::Burst;
746
747 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
748 let trigger_action = TriggerAction::Beat;
749
750 channel
753 .as_mut()
754 .transfer_future_linked(
755 buf,
756 &mut sercom_ptr,
757 S::DMA_TX_TRIGGER,
758 trigger_action,
759 next,
760 )
761 .await
762 }
763}