2022-08-18 19:39:13 +02:00
|
|
|
use core::pin::Pin;
|
2021-03-29 04:11:32 +02:00
|
|
|
use core::sync::atomic::{compiler_fence, Ordering};
|
2022-08-18 20:30:50 +02:00
|
|
|
use core::task::{Context, Poll, Waker};
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
|
2022-08-18 20:30:50 +02:00
|
|
|
use embassy_util::waitqueue::AtomicWaker;
|
2022-08-18 19:39:13 +02:00
|
|
|
use futures::Future;
|
2022-08-18 21:09:50 +02:00
|
|
|
use pac::dma::vals::DataSize;
|
2022-08-18 10:14:37 +02:00
|
|
|
|
2021-05-17 03:01:30 +02:00
|
|
|
use crate::pac::dma::vals;
|
2021-03-29 04:11:32 +02:00
|
|
|
use crate::{pac, peripherals};
|
|
|
|
|
2022-08-18 21:14:57 +02:00
|
|
|
pub(crate) fn read<'a, C: Channel, W: Word>(
|
|
|
|
ch: impl Peripheral<P = C> + 'a,
|
|
|
|
from: *const W,
|
|
|
|
to: *mut [W],
|
|
|
|
) -> Transfer<'a, C> {
|
2022-08-18 21:09:50 +02:00
|
|
|
let (ptr, len) = crate::dma::slice_ptr_parts_mut(to);
|
|
|
|
copy(ch, from as *const u32, ptr as *mut u32, len, W::size())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn write<'a, C: Channel, W: Word>(
|
|
|
|
ch: impl Peripheral<P = C> + 'a,
|
|
|
|
from: *const [W],
|
|
|
|
to: *mut W,
|
|
|
|
) -> Transfer<'a, C> {
|
|
|
|
let (from_ptr, len) = crate::dma::slice_ptr_parts(from);
|
|
|
|
copy(ch, from_ptr as *const u32, to as *mut u32, len, W::size())
|
|
|
|
}
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 21:09:50 +02:00
|
|
|
fn copy<'a, C: Channel>(
|
|
|
|
ch: impl Peripheral<P = C> + 'a,
|
|
|
|
from: *const u32,
|
|
|
|
to: *mut u32,
|
|
|
|
len: usize,
|
|
|
|
data_size: DataSize,
|
|
|
|
) -> Transfer<'a, C> {
|
2022-08-18 19:39:13 +02:00
|
|
|
into_ref!(ch);
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
unsafe {
|
|
|
|
let p = ch.regs();
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 21:09:50 +02:00
|
|
|
p.read_addr().write_value(from as u32);
|
|
|
|
p.write_addr().write_value(to as u32);
|
|
|
|
p.trans_count().write_value(len as u32);
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
compiler_fence(Ordering::SeqCst);
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
p.ctrl_trig().write(|w| {
|
2022-08-18 21:09:50 +02:00
|
|
|
w.set_data_size(data_size);
|
2022-08-18 21:14:57 +02:00
|
|
|
w.set_incr_read(false);
|
2022-08-18 19:39:13 +02:00
|
|
|
w.set_incr_write(true);
|
|
|
|
w.set_chain_to(ch.number());
|
|
|
|
w.set_en(true);
|
|
|
|
});
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
compiler_fence(Ordering::SeqCst);
|
|
|
|
}
|
|
|
|
Transfer::new(ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct Transfer<'a, C: Channel> {
|
|
|
|
channel: PeripheralRef<'a, C>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, C: Channel> Transfer<'a, C> {
|
|
|
|
pub(crate) fn new(channel: impl Peripheral<P = C> + 'a) -> Self {
|
|
|
|
into_ref!(channel);
|
|
|
|
Self { channel }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, C: Channel> Drop for Transfer<'a, C> {
|
|
|
|
fn drop(&mut self) {
|
2022-08-18 20:30:24 +02:00
|
|
|
let p = self.channel.regs();
|
|
|
|
unsafe {
|
|
|
|
p.ctrl_trig().write(|w| w.set_en(false));
|
|
|
|
while p.ctrl_trig().read().busy() {}
|
|
|
|
}
|
2022-08-18 19:39:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
|
|
|
|
impl<'a, C: Channel> Future for Transfer<'a, C> {
|
|
|
|
type Output = ();
|
2022-08-18 21:09:50 +02:00
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
2022-08-18 20:30:50 +02:00
|
|
|
self.channel.set_waker(cx.waker());
|
|
|
|
|
|
|
|
if self.channel.is_running() {
|
|
|
|
Poll::Pending
|
|
|
|
} else {
|
|
|
|
Poll::Ready(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ChannelState {
|
|
|
|
waker: AtomicWaker,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ChannelState {
|
|
|
|
const fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
waker: AtomicWaker::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct State {
|
|
|
|
channels: [ChannelState; 12],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
const fn new() -> Self {
|
|
|
|
const CH: ChannelState = ChannelState::new();
|
|
|
|
Self { channels: [CH; 12] }
|
2021-03-29 04:11:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-18 20:30:50 +02:00
|
|
|
static STATE: State = State::new();
|
|
|
|
|
2021-03-29 04:11:32 +02:00
|
|
|
mod sealed {
|
2022-08-18 19:39:13 +02:00
|
|
|
pub trait Channel {}
|
|
|
|
|
|
|
|
pub trait Word {}
|
|
|
|
}
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static {
|
|
|
|
fn number(&self) -> u8;
|
2021-03-29 04:11:32 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
fn regs(&self) -> pac::dma::Channel {
|
|
|
|
pac::DMA.ch(self.number() as _)
|
|
|
|
}
|
|
|
|
|
2022-08-18 20:30:50 +02:00
|
|
|
fn is_running(&self) -> bool {
|
2022-08-18 21:09:50 +02:00
|
|
|
unsafe { self.regs().ctrl_trig().read().en() }
|
2022-08-18 20:30:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_waker(&self, waker: &Waker) {
|
|
|
|
STATE.channels[self.number() as usize].waker.register(waker);
|
|
|
|
}
|
|
|
|
|
2022-08-18 21:14:57 +02:00
|
|
|
fn on_irq() {
|
|
|
|
// FIXME:
|
|
|
|
}
|
2022-08-18 21:09:50 +02:00
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
fn degrade(self) -> AnyChannel {
|
2022-08-18 20:30:24 +02:00
|
|
|
AnyChannel { number: self.number() }
|
2021-03-29 04:11:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
2021-03-29 04:11:32 +02:00
|
|
|
|
|
|
|
pub struct AnyChannel {
|
|
|
|
number: u8,
|
|
|
|
}
|
|
|
|
|
2022-08-18 19:39:13 +02:00
|
|
|
impl_peripheral!(AnyChannel);
|
|
|
|
|
|
|
|
impl sealed::Channel for AnyChannel {}
|
|
|
|
impl Channel for AnyChannel {
|
2021-03-29 04:11:32 +02:00
|
|
|
fn number(&self) -> u8 {
|
|
|
|
self.number
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! channel {
|
2022-08-18 19:39:13 +02:00
|
|
|
($name:ident, $num:expr) => {
|
|
|
|
impl sealed::Channel for peripherals::$name {}
|
|
|
|
impl Channel for peripherals::$name {
|
2021-03-29 04:11:32 +02:00
|
|
|
fn number(&self) -> u8 {
|
|
|
|
$num
|
|
|
|
}
|
|
|
|
}
|
2022-08-18 19:39:13 +02:00
|
|
|
|
|
|
|
impl From<peripherals::$name> for crate::dma::AnyChannel {
|
|
|
|
fn from(val: peripherals::$name) -> Self {
|
|
|
|
crate::dma::Channel::degrade(val)
|
|
|
|
}
|
|
|
|
}
|
2021-03-29 04:11:32 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-08-18 21:09:50 +02:00
|
|
|
// TODO: replace transmutes with core::ptr::metadata once it's stable
|
|
|
|
#[allow(unused)]
|
|
|
|
pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (usize, usize) {
|
|
|
|
unsafe { core::mem::transmute(slice) }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
|
|
|
|
unsafe { core::mem::transmute(slice) }
|
|
|
|
}
|
|
|
|
|
2021-03-29 04:11:32 +02:00
|
|
|
channel!(DMA_CH0, 0);
|
|
|
|
channel!(DMA_CH1, 1);
|
|
|
|
channel!(DMA_CH2, 2);
|
|
|
|
channel!(DMA_CH3, 3);
|
|
|
|
channel!(DMA_CH4, 4);
|
|
|
|
channel!(DMA_CH5, 5);
|
|
|
|
channel!(DMA_CH6, 6);
|
|
|
|
channel!(DMA_CH7, 7);
|
|
|
|
channel!(DMA_CH8, 8);
|
|
|
|
channel!(DMA_CH9, 9);
|
|
|
|
channel!(DMA_CH10, 10);
|
|
|
|
channel!(DMA_CH11, 11);
|