Preliminary DMA support for RP2040
This commit is contained in:
		@@ -1,39 +1,71 @@
 | 
			
		||||
use core::pin::Pin;
 | 
			
		||||
use core::sync::atomic::{compiler_fence, Ordering};
 | 
			
		||||
use core::task::{Context, Poll};
 | 
			
		||||
 | 
			
		||||
use embassy_hal_common::impl_peripheral;
 | 
			
		||||
use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
 | 
			
		||||
use futures::Future;
 | 
			
		||||
 | 
			
		||||
use crate::pac::dma::vals;
 | 
			
		||||
use crate::{pac, peripherals};
 | 
			
		||||
 | 
			
		||||
pub struct Dma<T: Channel> {
 | 
			
		||||
    _inner: T,
 | 
			
		||||
pub fn copy<'a, C: Channel, W: Word>(ch: impl Peripheral<P = C> + 'a, from: &[W], to: &mut [W]) -> Transfer<'a, C> {
 | 
			
		||||
    assert!(from.len() == to.len());
 | 
			
		||||
 | 
			
		||||
    into_ref!(ch);
 | 
			
		||||
 | 
			
		||||
    unsafe {
 | 
			
		||||
        let p = ch.regs();
 | 
			
		||||
 | 
			
		||||
        p.read_addr().write_value(from.as_ptr() as u32);
 | 
			
		||||
        p.write_addr().write_value(to.as_mut_ptr() as u32);
 | 
			
		||||
        p.trans_count().write_value(from.len() as u32);
 | 
			
		||||
 | 
			
		||||
        compiler_fence(Ordering::SeqCst);
 | 
			
		||||
 | 
			
		||||
        p.ctrl_trig().write(|w| {
 | 
			
		||||
            w.set_data_size(W::size());
 | 
			
		||||
            w.set_incr_read(true);
 | 
			
		||||
            w.set_incr_write(true);
 | 
			
		||||
            w.set_chain_to(ch.number());
 | 
			
		||||
            w.set_en(true);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // FIXME:
 | 
			
		||||
        while p.ctrl_trig().read().busy() {}
 | 
			
		||||
 | 
			
		||||
        compiler_fence(Ordering::SeqCst);
 | 
			
		||||
    }
 | 
			
		||||
    Transfer::new(ch)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: Channel> Dma<T> {
 | 
			
		||||
    pub fn copy(inner: T, from: &[u32], to: &mut [u32]) {
 | 
			
		||||
        assert!(from.len() == to.len());
 | 
			
		||||
pub(crate) struct Transfer<'a, C: Channel> {
 | 
			
		||||
    channel: PeripheralRef<'a, C>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let p = inner.regs();
 | 
			
		||||
impl<'a, C: Channel> Transfer<'a, C> {
 | 
			
		||||
    pub(crate) fn new(channel: impl Peripheral<P = C> + 'a) -> Self {
 | 
			
		||||
        into_ref!(channel);
 | 
			
		||||
        Self { channel }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            p.read_addr().write_value(from.as_ptr() as u32);
 | 
			
		||||
            p.write_addr().write_value(to.as_mut_ptr() as u32);
 | 
			
		||||
            p.trans_count().write_value(from.len() as u32);
 | 
			
		||||
impl<'a, C: Channel> Drop for Transfer<'a, C> {
 | 
			
		||||
    fn drop(&mut self) {
 | 
			
		||||
        // self.channel.request_stop();
 | 
			
		||||
        // while self.channel.is_running() {}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            compiler_fence(Ordering::SeqCst);
 | 
			
		||||
 | 
			
		||||
            p.ctrl_trig().write(|w| {
 | 
			
		||||
                w.set_data_size(vals::DataSize::SIZE_WORD);
 | 
			
		||||
                w.set_incr_read(true);
 | 
			
		||||
                w.set_incr_write(true);
 | 
			
		||||
                w.set_chain_to(inner.number());
 | 
			
		||||
                w.set_en(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            while p.ctrl_trig().read().busy() {}
 | 
			
		||||
 | 
			
		||||
            compiler_fence(Ordering::SeqCst);
 | 
			
		||||
        }
 | 
			
		||||
impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
 | 
			
		||||
impl<'a, C: Channel> Future for Transfer<'a, C> {
 | 
			
		||||
    type Output = ();
 | 
			
		||||
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
 | 
			
		||||
        // self.channel.set_waker(cx.waker());
 | 
			
		||||
        // if self.channel.is_running() {
 | 
			
		||||
        //     Poll::Pending
 | 
			
		||||
        // } else {
 | 
			
		||||
            Poll::Ready(())
 | 
			
		||||
        // }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -42,38 +74,77 @@ pub struct NoDma;
 | 
			
		||||
impl_peripheral!(NoDma);
 | 
			
		||||
 | 
			
		||||
mod sealed {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    pub trait Channel {}
 | 
			
		||||
 | 
			
		||||
    pub trait Channel {
 | 
			
		||||
        fn number(&self) -> u8;
 | 
			
		||||
    pub trait Word {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
        fn regs(&self) -> pac::dma::Channel {
 | 
			
		||||
            pac::DMA.ch(self.number() as _)
 | 
			
		||||
pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static {
 | 
			
		||||
    fn number(&self) -> u8;
 | 
			
		||||
 | 
			
		||||
    fn regs(&self) -> pac::dma::Channel {
 | 
			
		||||
        pac::DMA.ch(self.number() as _)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn degrade(self) -> AnyChannel {
 | 
			
		||||
        AnyChannel {
 | 
			
		||||
            number: self.number(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait Channel: sealed::Channel {}
 | 
			
		||||
pub trait Word: sealed::Word {
 | 
			
		||||
    fn size() -> vals::DataSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl sealed::Word for u8 {}
 | 
			
		||||
impl Word for u8 {
 | 
			
		||||
    fn size() -> vals::DataSize {
 | 
			
		||||
        vals::DataSize::SIZE_BYTE
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl sealed::Word for u16 {}
 | 
			
		||||
impl Word for u16 {
 | 
			
		||||
    fn size() -> vals::DataSize {
 | 
			
		||||
        vals::DataSize::SIZE_HALFWORD
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl sealed::Word for u32 {}
 | 
			
		||||
impl Word for u32 {
 | 
			
		||||
    fn size() -> vals::DataSize {
 | 
			
		||||
        vals::DataSize::SIZE_WORD
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AnyChannel {
 | 
			
		||||
    number: u8,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Channel for AnyChannel {}
 | 
			
		||||
impl sealed::Channel for AnyChannel {
 | 
			
		||||
impl_peripheral!(AnyChannel);
 | 
			
		||||
 | 
			
		||||
impl sealed::Channel for AnyChannel {}
 | 
			
		||||
impl Channel for AnyChannel {
 | 
			
		||||
    fn number(&self) -> u8 {
 | 
			
		||||
        self.number
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
macro_rules! channel {
 | 
			
		||||
    ($type:ident, $num:expr) => {
 | 
			
		||||
        impl Channel for peripherals::$type {}
 | 
			
		||||
        impl sealed::Channel for peripherals::$type {
 | 
			
		||||
    ($name:ident, $num:expr) => {
 | 
			
		||||
        impl sealed::Channel for peripherals::$name {}
 | 
			
		||||
        impl Channel for peripherals::$name {
 | 
			
		||||
            fn number(&self) -> u8 {
 | 
			
		||||
                $num
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl From<peripherals::$name> for crate::dma::AnyChannel {
 | 
			
		||||
            fn from(val: peripherals::$name) -> Self {
 | 
			
		||||
                crate::dma::Channel::degrade(val)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user