imxrt_dma/memcpy.rs
1//! DMA-powered memcpy
2
3use crate::{
4 channel::{self, Channel},
5 interrupt::Transfer,
6 Element, Error,
7};
8
9use core::{
10 future::Future,
11 pin::Pin,
12 task::{Context, Poll},
13};
14
15/// A memcpy operation
16///
17/// `Memcpy` yields when it's moved the minimum amount of elements between two linear
18/// buffers. Use the [`memcpy`](crate::memcpy::memcpy) function to define the transfer.
19pub struct Memcpy<'a, E> {
20 transfer: Transfer<'a>,
21 channel: &'a Channel,
22 _elem: core::marker::PhantomData<(&'a E, &'a mut E)>,
23}
24
25/// Perform a DMA-powered `memcpy` between the `source` and `destination` buffers
26///
27/// Copies the minimum number of elements between the two buffers. You're responsible
28/// for enabling any interrupts, and calling [`on_interrupt`](crate::Dma::on_interrupt)
29/// if the interrupt fires. Otherwise, you may poll the transfer until completion.
30///
31/// # Example
32///
33/// Transfer 5 `u32`s between a source and destination buffer. The transfer completes when
34/// the DMA channel 7 interrupt fires.
35///
36/// ```no_run
37/// use imxrt_dma::{channel::Channel, memcpy};
38///
39/// # static DMA: imxrt_dma::Dma<32> = unsafe { imxrt_dma::Dma::new(core::ptr::null(), core::ptr::null()) };
40/// // #[cortex_m_rt::interrupt]
41/// fn DMA7() {
42/// // Safety: DMA channel 7 valid and used by a future.
43/// unsafe { DMA.on_interrupt(7) };
44/// }
45///
46/// # async fn f() -> imxrt_dma::Result<()> {
47/// let mut channel_7: Channel = // DMA channel 7
48/// # unsafe { DMA.channel(7) };
49/// channel_7.set_interrupt_on_completion(true);
50/// // TODO unmask DMA7 interrupt!
51///
52/// let source = [4u32, 5, 6, 7, 8];
53/// let mut destination = [0; 5];
54///
55/// memcpy::memcpy(&source, &mut destination, &mut channel_7).await?;
56/// # Ok(()) }
57/// ```
58pub fn memcpy<'a, E: Element>(
59 source: &'a [E],
60 destination: &'a mut [E],
61 channel: &'a mut Channel,
62) -> Memcpy<'a, E> {
63 channel.disable();
64
65 channel.set_disable_on_completion(true);
66
67 // Safety: buffers borrowed by `memcpy`, and will be valid
68 // while a transfer is in progress.
69 unsafe {
70 channel::set_source_linear_buffer(channel, source);
71 channel::set_destination_linear_buffer(channel, destination);
72 }
73
74 // Turn off any DMAMUX configuration.
75 //
76 // Alternatively, we could use an always-on transfer, which might not need an
77 // explicit "start()" activation. This means we could express the transfer
78 // as a series of major loops, each transferring sizeof(E) bytes in the minor
79 // loop. TBD...
80 channel.set_channel_configuration(channel::Configuration::Off);
81
82 // Transfer all elements in a single major loop
83 //
84 // Safety: transferring the minimum number of bytes between buffers,
85 // and there's only one major loop to perform the transfer.
86 unsafe {
87 channel.set_minor_loop_bytes(
88 core::mem::size_of::<E>().saturating_mul(source.len().min(destination.len())) as u32,
89 );
90 channel.set_transfer_iterations(1);
91 }
92
93 Memcpy {
94 // Safety: transfer is properly prepared
95 transfer: unsafe { Transfer::new(channel) },
96 channel,
97 _elem: core::marker::PhantomData,
98 }
99}
100
101impl<E> Future for Memcpy<'_, E> {
102 type Output = Result<(), Error>;
103
104 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
105 // Safety: data not moved
106 let transfer = unsafe { self.as_mut().map_unchecked_mut(|this| &mut this.transfer) };
107 let poll = transfer.poll(cx);
108 if poll.is_pending() && !self.channel.is_active() {
109 self.channel.start();
110 }
111 poll
112 }
113}
114
115// Drop handled by Transfer impl