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