1use core::{marker::PhantomData, ops::Range};
8
9use atsamd_hal_macros::hal_macro_helper;
10
11use crate::dmac::{
12 self, Beat, Buffer, Transfer, TriggerAction,
13 channel::{AnyChannel, Busy, Channel, InterruptFlags, Ready},
14 sram::DmacDescriptor,
15 transfer::BufferPair,
16};
17use crate::sercom::{
18 Sercom,
19 uart::{self, Uart},
20};
21
22#[doc(hidden)]
31pub(crate) struct SharedSliceBuffer<'a, T: Beat> {
32 ptrs: Range<*mut T>,
33 _lifetime: PhantomData<&'a T>,
34}
35
36impl<'a, T: Beat> SharedSliceBuffer<'a, T> {
37 #[inline]
38 pub(in super::super) fn from_slice(slice: &'a [T]) -> Self {
39 unsafe { Self::from_slice_unchecked(slice) }
40 }
41
42 #[inline]
43 pub(in super::super) unsafe fn from_slice_unchecked(slice: &[T]) -> Self {
44 let ptrs = slice.as_ptr_range();
45
46 let ptrs = Range {
47 start: ptrs.start.cast_mut(),
48 end: ptrs.end.cast_mut(),
49 };
50
51 Self {
52 ptrs,
53 _lifetime: PhantomData,
54 }
55 }
56}
57
58unsafe impl<T: Beat> Buffer for SharedSliceBuffer<'_, T> {
59 type Beat = T;
60 #[inline]
61 fn dma_ptr(&mut self) -> *mut Self::Beat {
62 if self.incrementing() {
63 self.ptrs.end
64 } else {
65 self.ptrs.start
66 }
67 }
68
69 #[inline]
70 fn incrementing(&self) -> bool {
71 self.buffer_len() > 1
72 }
73
74 #[inline]
75 fn buffer_len(&self) -> usize {
76 self.ptrs.end as usize - self.ptrs.start as usize
77 }
78}
79
80pub(super) struct SinkSourceBuffer<'a, T: Beat> {
90 word: &'a mut T,
91 length: usize,
92}
93
94impl<'a, T: Beat> SinkSourceBuffer<'a, T> {
95 pub(super) fn new(word: &'a mut T, length: usize) -> Self {
96 Self { word, length }
97 }
98}
99unsafe impl<T: Beat> Buffer for SinkSourceBuffer<'_, T> {
100 type Beat = T;
101 #[inline]
102 fn incrementing(&self) -> bool {
103 false
104 }
105
106 #[inline]
107 fn buffer_len(&self) -> usize {
108 self.length
109 }
110
111 #[inline]
112 fn dma_ptr(&mut self) -> *mut Self::Beat {
113 self.word as *mut _
114 }
115}
116#[doc(hidden)]
120#[derive(Clone)]
121pub(crate) struct SercomPtr<T: Beat>(pub(in super::super) *mut T);
122
123unsafe impl<T: Beat> Buffer for SercomPtr<T> {
124 type Beat = T;
125
126 #[inline]
127 fn dma_ptr(&mut self) -> *mut Self::Beat {
128 self.0
129 }
130
131 #[inline]
132 fn incrementing(&self) -> bool {
133 false
134 }
135
136 #[inline]
137 fn buffer_len(&self) -> usize {
138 1
139 }
140}
141
142unsafe impl<C, D> Buffer for Uart<C, D>
146where
147 C: uart::ValidConfig,
148 C::Word: Beat,
149 D: uart::Capability,
150{
151 type Beat = C::Word;
152
153 #[inline]
154 fn dma_ptr(&mut self) -> *mut Self::Beat {
155 self.data_ptr()
156 }
157
158 #[inline]
159 fn incrementing(&self) -> bool {
160 false
161 }
162
163 #[inline]
164 fn buffer_len(&self) -> usize {
165 1
166 }
167}
168
169impl<C, D> Uart<C, D>
170where
171 Self: Buffer<Beat = C::Word>,
172 C: uart::ValidConfig,
173 D: uart::Receive,
174{
175 #[inline]
184 #[hal_macro_helper]
185 pub fn receive_with_dma<Ch, B>(
186 self,
187 buf: B,
188 mut channel: Ch,
189 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<Self, B>>
190 where
191 Ch: AnyChannel<Status = Ready>,
192 B: Buffer<Beat = C::Word> + 'static,
193 {
194 channel
195 .as_mut()
196 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
197
198 #[hal_cfg("sercom0-d5x")]
199 let trigger_action = TriggerAction::Burst;
200
201 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
202 let trigger_action = TriggerAction::Beat;
203
204 let xfer = unsafe { dmac::Transfer::new_unchecked(channel, self, buf, false) };
207 xfer.begin(C::Sercom::DMA_RX_TRIGGER, trigger_action)
208 }
209}
210
211impl<C, D> Uart<C, D>
212where
213 Self: Buffer<Beat = C::Word>,
214 C: uart::ValidConfig,
215 D: uart::Transmit,
216{
217 #[inline]
226 #[hal_macro_helper]
227 pub fn send_with_dma<Ch, B>(
228 self,
229 buf: B,
230 mut channel: Ch,
231 ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<B, Self>>
232 where
233 Ch: AnyChannel<Status = Ready>,
234 B: Buffer<Beat = C::Word> + 'static,
235 {
236 channel
237 .as_mut()
238 .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
239
240 #[hal_cfg("sercom0-d5x")]
241 let trigger_action = TriggerAction::Burst;
242
243 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
244 let trigger_action = TriggerAction::Beat;
245
246 let xfer = unsafe { dmac::Transfer::new_unchecked(channel, buf, self, false) };
249 xfer.begin(C::Sercom::DMA_TX_TRIGGER, trigger_action)
250 }
251}
252
253#[hal_macro_helper]
260pub(super) unsafe fn read_dma<T, B, S>(
261 channel: &mut impl AnyChannel<Status = Ready>,
262 sercom_ptr: SercomPtr<T>,
263 buf: &mut B,
264) where
265 T: Beat,
266 B: Buffer<Beat = T>,
267 S: Sercom,
268{
269 unsafe {
270 read_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None);
271 }
272}
273
274#[hal_macro_helper]
282pub(super) unsafe fn read_dma_linked<T, B, S>(
283 channel: &mut impl AnyChannel<Status = Ready>,
284 mut sercom_ptr: SercomPtr<T>,
285 buf: &mut B,
286 next: Option<&mut DmacDescriptor>,
287) where
288 T: Beat,
289 B: Buffer<Beat = T>,
290 S: Sercom,
291{
292 #[hal_cfg("dmac-d5x")]
293 let trigger_action = TriggerAction::Burst;
294
295 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
296 let trigger_action = TriggerAction::Beat;
297
298 unsafe {
301 channel.as_mut().transfer_unchecked(
302 &mut sercom_ptr,
303 buf,
304 S::DMA_RX_TRIGGER,
305 trigger_action,
306 next,
307 );
308 }
309}
310
311#[hal_macro_helper]
318pub(super) unsafe fn write_dma<T, B, S>(
319 channel: &mut impl AnyChannel<Status = Ready>,
320 sercom_ptr: SercomPtr<T>,
321 buf: &mut B,
322) where
323 T: Beat,
324 B: Buffer<Beat = T>,
325 S: Sercom,
326{
327 unsafe {
328 write_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None);
329 }
330}
331
332#[hal_macro_helper]
340pub(super) unsafe fn write_dma_linked<T, B, S>(
341 channel: &mut impl AnyChannel<Status = Ready>,
342 mut sercom_ptr: SercomPtr<T>,
343 buf: &mut B,
344 next: Option<&mut DmacDescriptor>,
345) where
346 T: Beat,
347 B: Buffer<Beat = T>,
348 S: Sercom,
349{
350 #[hal_cfg("dmac-d5x")]
351 let trigger_action = TriggerAction::Burst;
352
353 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
354 let trigger_action = TriggerAction::Beat;
355
356 unsafe {
359 channel.as_mut().transfer_unchecked(
360 buf,
361 &mut sercom_ptr,
362 S::DMA_TX_TRIGGER,
363 trigger_action,
364 next,
365 );
366 }
367}
368
369#[cfg(feature = "async")]
375pub(crate) mod async_dma {
376 use dmac::{Error, ReadyFuture};
377
378 use super::*;
379
380 #[inline]
382 pub(in super::super) async fn read_dma<T, B, S>(
383 channel: &mut impl AnyChannel<Status = ReadyFuture>,
384 sercom_ptr: SercomPtr<T>,
385 buf: &mut B,
386 ) -> Result<(), Error>
387 where
388 B: Buffer<Beat = T>,
389 T: Beat,
390 S: Sercom,
391 {
392 unsafe { read_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None).await }
393 }
394
395 #[inline]
404 #[hal_macro_helper]
405 pub(in super::super) async unsafe fn read_dma_linked<T, B, S>(
406 channel: &mut impl AnyChannel<Status = ReadyFuture>,
407 mut sercom_ptr: SercomPtr<T>,
408 buf: &mut B,
409 next: Option<&mut DmacDescriptor>,
410 ) -> Result<(), Error>
411 where
412 T: Beat,
413 B: Buffer<Beat = T>,
414 S: Sercom,
415 {
416 #[hal_cfg("dmac-d5x")]
417 let trigger_action = TriggerAction::Burst;
418
419 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
420 let trigger_action = TriggerAction::Beat;
421
422 unsafe {
425 channel
426 .as_mut()
427 .transfer_future_linked(
428 &mut sercom_ptr,
429 buf,
430 S::DMA_RX_TRIGGER,
431 trigger_action,
432 next,
433 )
434 .await
435 }
436 }
437
438 #[inline]
440 pub(in super::super) async fn write_dma<T, B, S>(
441 channel: &mut impl AnyChannel<Status = ReadyFuture>,
442 sercom_ptr: SercomPtr<T>,
443 buf: &mut B,
444 ) -> Result<(), Error>
445 where
446 B: Buffer<Beat = T>,
447 T: Beat,
448 S: Sercom,
449 {
450 unsafe { write_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None).await }
451 }
452
453 #[inline]
462 #[hal_macro_helper]
463 pub(in super::super) async unsafe fn write_dma_linked<T, B, S>(
464 channel: &mut impl AnyChannel<Status = ReadyFuture>,
465 mut sercom_ptr: SercomPtr<T>,
466 buf: &mut B,
467 next: Option<&mut DmacDescriptor>,
468 ) -> Result<(), Error>
469 where
470 B: Buffer<Beat = T>,
471 T: Beat,
472 S: Sercom,
473 {
474 #[hal_cfg("dmac-d5x")]
475 let trigger_action = TriggerAction::Burst;
476
477 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
478 let trigger_action = TriggerAction::Beat;
479
480 unsafe {
483 channel
484 .as_mut()
485 .transfer_future_linked(
486 buf,
487 &mut sercom_ptr,
488 S::DMA_TX_TRIGGER,
489 trigger_action,
490 next,
491 )
492 .await
493 }
494 }
495}