2021-07-15 05:42:06 +02:00
|
|
|
#[cfg(bdma)]
|
|
|
|
mod bdma;
|
|
|
|
#[cfg(dma)]
|
|
|
|
mod dma;
|
|
|
|
#[cfg(dmamux)]
|
|
|
|
mod dmamux;
|
2021-05-16 02:57:46 +02:00
|
|
|
|
2021-07-17 07:49:49 +02:00
|
|
|
#[cfg(dmamux)]
|
|
|
|
pub use dmamux::*;
|
|
|
|
|
2021-07-15 05:42:06 +02:00
|
|
|
use embassy::util::Unborrow;
|
2021-05-25 04:17:24 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
#[cfg(feature = "unstable-pac")]
|
|
|
|
pub use transfers::*;
|
|
|
|
|
|
|
|
#[cfg(not(feature = "unstable-pac"))]
|
|
|
|
pub(crate) use transfers::*;
|
|
|
|
|
2021-07-15 05:42:06 +02:00
|
|
|
#[cfg(any(bdma_v2, dma_v2, dmamux))]
|
|
|
|
pub type Request = u8;
|
|
|
|
#[cfg(not(any(bdma_v2, dma_v2, dmamux)))]
|
|
|
|
pub type Request = ();
|
|
|
|
|
|
|
|
pub(crate) mod sealed {
|
2021-11-19 19:15:55 +01:00
|
|
|
use super::*;
|
|
|
|
use core::task::Waker;
|
|
|
|
pub trait Channel {
|
|
|
|
/// Starts this channel for writing a stream of words.
|
|
|
|
unsafe fn start_write<W: Word>(&mut self, request: Request, buf: &[W], reg_addr: *mut u32);
|
|
|
|
|
|
|
|
/// Starts this channel for writing a word repeatedly.
|
|
|
|
unsafe fn start_write_repeated<W: Word>(
|
|
|
|
&mut self,
|
|
|
|
request: Request,
|
|
|
|
repeated: W,
|
|
|
|
count: usize,
|
|
|
|
reg_addr: *mut u32,
|
|
|
|
);
|
|
|
|
|
|
|
|
/// Starts this channel for reading a stream of words.
|
|
|
|
unsafe fn start_read<W: Word>(
|
|
|
|
&mut self,
|
|
|
|
request: Request,
|
|
|
|
reg_addr: *mut u32,
|
|
|
|
buf: &mut [W],
|
|
|
|
);
|
|
|
|
|
|
|
|
/// Stops this channel.
|
|
|
|
fn request_stop(&mut self);
|
|
|
|
|
|
|
|
/// Returns whether this channel is active or stopped.
|
2021-12-08 01:51:39 +01:00
|
|
|
fn is_running(&self) -> bool;
|
2021-11-19 19:15:55 +01:00
|
|
|
|
|
|
|
/// Returns the total number of remaining transfers.
|
|
|
|
fn remaining_transfers(&mut self) -> u16;
|
|
|
|
|
|
|
|
/// Sets the waker that is called when this channel completes.
|
|
|
|
fn set_waker(&mut self, waker: &Waker);
|
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
}
|
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
pub enum WordSize {
|
|
|
|
OneByte,
|
|
|
|
TwoBytes,
|
|
|
|
FourBytes,
|
|
|
|
}
|
|
|
|
pub trait Word {
|
|
|
|
fn bits() -> WordSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Word for u8 {
|
|
|
|
fn bits() -> WordSize {
|
|
|
|
WordSize::OneByte
|
|
|
|
}
|
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
impl Word for u16 {
|
|
|
|
fn bits() -> WordSize {
|
|
|
|
WordSize::TwoBytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Word for u32 {
|
|
|
|
fn bits() -> WordSize {
|
|
|
|
WordSize::FourBytes
|
|
|
|
}
|
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
mod transfers {
|
|
|
|
use core::task::Poll;
|
|
|
|
|
|
|
|
use super::Channel;
|
|
|
|
use embassy_hal_common::{drop::OnDrop, unborrow};
|
|
|
|
use futures::future::poll_fn;
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
pub async fn read<'a, W: Word>(
|
|
|
|
channel: &mut impl Unborrow<Target = impl Channel>,
|
2021-07-15 05:42:06 +02:00
|
|
|
request: Request,
|
2021-11-19 19:15:55 +01:00
|
|
|
reg_addr: *mut u32,
|
|
|
|
buf: &'a mut [W],
|
|
|
|
) {
|
|
|
|
assert!(buf.len() <= 0xFFFF);
|
|
|
|
let drop_clone = unsafe { channel.unborrow() };
|
|
|
|
unborrow!(channel);
|
2021-07-15 05:42:06 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
channel.request_stop();
|
|
|
|
let on_drop = OnDrop::new({
|
|
|
|
let mut channel = drop_clone;
|
|
|
|
move || {
|
|
|
|
channel.request_stop();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
unsafe { channel.start_read::<W>(request, reg_addr, buf) };
|
|
|
|
wait_for_stopped(&mut channel).await;
|
|
|
|
drop(on_drop)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
pub async fn write<'a, W: Word>(
|
|
|
|
channel: &mut impl Unborrow<Target = impl Channel>,
|
2021-07-15 05:42:06 +02:00
|
|
|
request: Request,
|
2021-11-19 19:15:55 +01:00
|
|
|
buf: &'a [W],
|
|
|
|
reg_addr: *mut u32,
|
|
|
|
) {
|
|
|
|
assert!(buf.len() <= 0xFFFF);
|
|
|
|
let drop_clone = unsafe { channel.unborrow() };
|
|
|
|
unborrow!(channel);
|
|
|
|
|
|
|
|
channel.request_stop();
|
|
|
|
let on_drop = OnDrop::new({
|
|
|
|
let mut channel = drop_clone;
|
|
|
|
move || {
|
|
|
|
channel.request_stop();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
unsafe { channel.start_write::<W>(request, buf, reg_addr) };
|
|
|
|
wait_for_stopped(&mut channel).await;
|
|
|
|
drop(on_drop)
|
|
|
|
}
|
2021-07-20 21:20:16 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
#[allow(unused)]
|
|
|
|
pub async fn write_repeated<W: Word>(
|
|
|
|
channel: &mut impl Unborrow<Target = impl Channel>,
|
2021-07-20 21:20:16 +02:00
|
|
|
request: Request,
|
2021-11-19 19:15:55 +01:00
|
|
|
repeated: W,
|
|
|
|
count: usize,
|
|
|
|
reg_addr: *mut u32,
|
|
|
|
) {
|
|
|
|
let drop_clone = unsafe { channel.unborrow() };
|
|
|
|
unborrow!(channel);
|
|
|
|
|
|
|
|
channel.request_stop();
|
|
|
|
let on_drop = OnDrop::new({
|
|
|
|
let mut channel = drop_clone;
|
|
|
|
move || {
|
|
|
|
channel.request_stop();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
unsafe { channel.start_write_repeated::<W>(request, repeated, count, reg_addr) };
|
|
|
|
wait_for_stopped(&mut channel).await;
|
|
|
|
drop(on_drop)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn wait_for_stopped(channel: &mut impl Unborrow<Target = impl Channel>) {
|
|
|
|
unborrow!(channel);
|
|
|
|
poll_fn(move |cx| {
|
|
|
|
channel.set_waker(cx.waker());
|
|
|
|
|
|
|
|
// TODO in the future, error checking could be added so that this function returns an error
|
|
|
|
|
2021-12-08 01:51:39 +01:00
|
|
|
if channel.is_running() {
|
2021-11-19 19:15:55 +01:00
|
|
|
Poll::Pending
|
2021-12-08 01:51:39 +01:00
|
|
|
} else {
|
|
|
|
Poll::Ready(())
|
2021-11-19 19:15:55 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
}
|
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
pub trait Channel: sealed::Channel + Unborrow<Target = Self> {}
|
|
|
|
|
2021-07-15 05:42:06 +02:00
|
|
|
pub struct NoDma;
|
|
|
|
|
|
|
|
unsafe impl Unborrow for NoDma {
|
|
|
|
type Target = NoDma;
|
|
|
|
|
|
|
|
unsafe fn unborrow(self) -> Self::Target {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// safety: must be called only once at startup
|
|
|
|
pub(crate) unsafe fn init() {
|
|
|
|
#[cfg(bdma)]
|
|
|
|
bdma::init();
|
|
|
|
#[cfg(dma)]
|
|
|
|
dma::init();
|
|
|
|
#[cfg(dmamux)]
|
|
|
|
dmamux::init();
|
|
|
|
}
|