2021-07-15 05:42:06 +02:00
|
|
|
#[cfg(bdma)]
|
2022-02-05 03:03:32 +01:00
|
|
|
pub(crate) mod bdma;
|
2021-07-15 05:42:06 +02:00
|
|
|
#[cfg(dma)]
|
2022-02-05 03:03:32 +01:00
|
|
|
pub(crate) mod dma;
|
2021-07-15 05:42:06 +02:00
|
|
|
#[cfg(dmamux)]
|
|
|
|
mod dmamux;
|
2022-04-26 23:57:26 +02:00
|
|
|
#[cfg(gpdma)]
|
|
|
|
mod gpdma;
|
2021-05-16 02:57:46 +02:00
|
|
|
|
2021-12-08 03:04:39 +01:00
|
|
|
use core::future::Future;
|
2022-01-19 15:59:25 +01:00
|
|
|
use core::mem;
|
2021-12-08 03:04:39 +01:00
|
|
|
use core::pin::Pin;
|
2022-06-12 22:15:44 +02:00
|
|
|
use core::task::{Context, Poll, Waker};
|
|
|
|
|
2022-07-23 14:00:19 +02:00
|
|
|
use embassy_hal_common::{impl_peripheral, into_ref};
|
2021-05-25 04:17:24 +02:00
|
|
|
|
2022-07-22 22:00:12 +02:00
|
|
|
#[cfg(dmamux)]
|
|
|
|
pub use self::dmamux::*;
|
2022-07-23 14:00:19 +02:00
|
|
|
use crate::Peripheral;
|
2022-06-12 22:15:44 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
#[cfg(feature = "unstable-pac")]
|
2022-02-10 21:38:03 +01:00
|
|
|
pub mod low_level {
|
|
|
|
pub use super::transfers::*;
|
|
|
|
}
|
2021-11-19 19:15:55 +01:00
|
|
|
|
|
|
|
pub(crate) use transfers::*;
|
|
|
|
|
2022-04-26 23:57:26 +02:00
|
|
|
#[cfg(any(bdma_v2, dma_v2, dmamux, gpdma))]
|
2021-07-15 05:42:06 +02:00
|
|
|
pub type Request = u8;
|
2022-04-26 23:57:26 +02:00
|
|
|
#[cfg(not(any(bdma_v2, dma_v2, dmamux, gpdma)))]
|
2021-07-15 05:42:06 +02:00
|
|
|
pub type Request = ();
|
|
|
|
|
|
|
|
pub(crate) mod sealed {
|
2021-11-19 19:15:55 +01:00
|
|
|
use super::*;
|
2021-12-08 03:04:39 +01:00
|
|
|
|
2021-12-08 03:18:15 +01:00
|
|
|
pub trait Word {}
|
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
pub trait Channel {
|
|
|
|
/// Starts this channel for writing a stream of words.
|
2021-12-08 03:18:15 +01:00
|
|
|
///
|
|
|
|
/// Safety:
|
2022-01-19 15:59:25 +01:00
|
|
|
/// - `buf` must point to a valid buffer for DMA reading.
|
2021-12-08 03:18:15 +01:00
|
|
|
/// - `buf` must be alive for the entire duration of the DMA transfer.
|
|
|
|
/// - `reg_addr` must be a valid peripheral register address to write to.
|
|
|
|
unsafe fn start_write<W: super::Word>(
|
|
|
|
&mut self,
|
|
|
|
request: Request,
|
2022-01-19 15:59:25 +01:00
|
|
|
buf: *const [W],
|
2021-12-08 03:18:15 +01:00
|
|
|
reg_addr: *mut W,
|
2022-03-16 17:52:06 +01:00
|
|
|
options: TransferOptions,
|
2021-12-08 03:18:15 +01:00
|
|
|
);
|
2021-11-19 19:15:55 +01:00
|
|
|
|
|
|
|
/// Starts this channel for writing a word repeatedly.
|
2021-12-08 03:18:15 +01:00
|
|
|
///
|
|
|
|
/// Safety:
|
|
|
|
/// - `reg_addr` must be a valid peripheral register address to write to.
|
|
|
|
unsafe fn start_write_repeated<W: super::Word>(
|
2021-11-19 19:15:55 +01:00
|
|
|
&mut self,
|
|
|
|
request: Request,
|
|
|
|
repeated: W,
|
|
|
|
count: usize,
|
2021-12-08 03:18:15 +01:00
|
|
|
reg_addr: *mut W,
|
2022-03-16 17:52:06 +01:00
|
|
|
options: TransferOptions,
|
2021-11-19 19:15:55 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
/// Starts this channel for reading a stream of words.
|
2021-12-08 03:18:15 +01:00
|
|
|
///
|
|
|
|
/// Safety:
|
2022-01-19 15:59:25 +01:00
|
|
|
/// - `buf` must point to a valid buffer for DMA writing.
|
2021-12-08 03:18:15 +01:00
|
|
|
/// - `buf` must be alive for the entire duration of the DMA transfer.
|
2022-01-19 15:59:25 +01:00
|
|
|
/// - `reg_addr` must be a valid peripheral register address to read from.
|
2021-12-08 03:18:15 +01:00
|
|
|
unsafe fn start_read<W: super::Word>(
|
2021-11-19 19:15:55 +01:00
|
|
|
&mut self,
|
|
|
|
request: Request,
|
2022-01-19 15:59:25 +01:00
|
|
|
reg_addr: *const W,
|
|
|
|
buf: *mut [W],
|
2022-03-16 17:52:06 +01:00
|
|
|
options: TransferOptions,
|
2021-11-19 19:15:55 +01:00
|
|
|
);
|
|
|
|
|
2022-04-12 14:06:53 +02:00
|
|
|
/// DMA double-buffered mode is unsafe as UB can happen when the hardware writes to a buffer currently owned by the software
|
|
|
|
/// more information can be found here: https://github.com/embassy-rs/embassy/issues/702
|
|
|
|
/// This feature is now used solely for the purposes of implementing giant DMA transfers required for DCMI
|
|
|
|
unsafe fn start_double_buffered_read<W: super::Word>(
|
|
|
|
&mut self,
|
|
|
|
request: Request,
|
|
|
|
reg_addr: *const W,
|
|
|
|
buffer0: *mut W,
|
|
|
|
buffer1: *mut W,
|
|
|
|
buffer_len: usize,
|
|
|
|
options: TransferOptions,
|
|
|
|
);
|
|
|
|
|
|
|
|
unsafe fn set_buffer0<W: super::Word>(&mut self, buffer: *mut W);
|
|
|
|
|
|
|
|
unsafe fn set_buffer1<W: super::Word>(&mut self, buffer: *mut W);
|
|
|
|
|
|
|
|
unsafe fn is_buffer0_accessible(&mut self) -> bool;
|
|
|
|
|
2021-12-08 03:18:15 +01:00
|
|
|
/// Requests the channel to stop.
|
|
|
|
/// NOTE: The channel does not immediately stop, you have to wait
|
|
|
|
/// for `is_running() = false`.
|
2021-11-19 19:15:55 +01:00
|
|
|
fn request_stop(&mut self);
|
|
|
|
|
2021-12-08 03:18:15 +01:00
|
|
|
/// Returns whether this channel is running or stopped.
|
|
|
|
///
|
|
|
|
/// The channel stops running when it either completes or is manually 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;
|
|
|
|
|
2021-12-08 03:18:15 +01:00
|
|
|
/// Sets the waker that is called when this channel stops (either completed or manually stopped)
|
2021-11-19 19:15:55 +01:00
|
|
|
fn set_waker(&mut self, waker: &Waker);
|
2022-03-08 20:52:33 +01:00
|
|
|
|
|
|
|
/// This is called when this channel triggers an interrupt.
|
|
|
|
/// Note: Because some channels share an interrupt, this function might be
|
|
|
|
/// called for a channel that didn't trigger an interrupt.
|
|
|
|
fn on_irq();
|
2021-11-19 19:15:55 +01:00
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
}
|
|
|
|
|
2022-04-26 23:57:26 +02:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
2021-11-19 19:15:55 +01:00
|
|
|
pub enum WordSize {
|
|
|
|
OneByte,
|
|
|
|
TwoBytes,
|
|
|
|
FourBytes,
|
|
|
|
}
|
2022-04-26 23:57:26 +02:00
|
|
|
|
|
|
|
impl WordSize {
|
|
|
|
pub fn bytes(&self) -> usize {
|
|
|
|
match self {
|
|
|
|
Self::OneByte => 1,
|
|
|
|
Self::TwoBytes => 2,
|
|
|
|
Self::FourBytes => 4,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 03:18:15 +01:00
|
|
|
pub trait Word: sealed::Word {
|
2021-11-19 19:15:55 +01:00
|
|
|
fn bits() -> WordSize;
|
|
|
|
}
|
|
|
|
|
2021-12-08 03:18:15 +01:00
|
|
|
impl sealed::Word for u8 {}
|
2021-11-19 19:15:55 +01:00
|
|
|
impl Word for u8 {
|
|
|
|
fn bits() -> WordSize {
|
|
|
|
WordSize::OneByte
|
|
|
|
}
|
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
|
2021-12-08 03:18:15 +01:00
|
|
|
impl sealed::Word for u16 {}
|
2021-11-19 19:15:55 +01:00
|
|
|
impl Word for u16 {
|
|
|
|
fn bits() -> WordSize {
|
|
|
|
WordSize::TwoBytes
|
|
|
|
}
|
|
|
|
}
|
2021-12-08 03:18:15 +01:00
|
|
|
|
|
|
|
impl sealed::Word for u32 {}
|
2021-11-19 19:15:55 +01:00
|
|
|
impl Word for u32 {
|
|
|
|
fn bits() -> WordSize {
|
|
|
|
WordSize::FourBytes
|
|
|
|
}
|
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
|
2022-04-26 23:57:26 +02:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
2022-03-16 17:52:06 +01:00
|
|
|
pub enum Burst {
|
|
|
|
/// Single transfer
|
|
|
|
Single,
|
|
|
|
/// Incremental burst of 4 beats
|
|
|
|
Incr4,
|
|
|
|
/// Incremental burst of 8 beats
|
|
|
|
Incr8,
|
|
|
|
/// Incremental burst of 16 beats
|
|
|
|
Incr16,
|
|
|
|
}
|
|
|
|
|
2022-04-26 23:57:26 +02:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
2022-03-16 17:52:06 +01:00
|
|
|
pub enum FlowControl {
|
|
|
|
/// Flow control by DMA
|
|
|
|
Dma,
|
|
|
|
/// Flow control by peripheral
|
|
|
|
Peripheral,
|
|
|
|
}
|
|
|
|
|
2022-04-26 23:57:26 +02:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
2022-03-16 17:52:06 +01:00
|
|
|
pub struct TransferOptions {
|
|
|
|
/// Peripheral burst transfer configuration
|
|
|
|
pub pburst: Burst,
|
|
|
|
/// Memory burst transfer configuration
|
|
|
|
pub mburst: Burst,
|
|
|
|
/// Flow control configuration
|
|
|
|
pub flow_ctrl: FlowControl,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for TransferOptions {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
pburst: Burst::Single,
|
|
|
|
mburst: Burst::Single,
|
|
|
|
flow_ctrl: FlowControl::Dma,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
mod transfers {
|
2022-07-23 14:00:19 +02:00
|
|
|
use embassy_hal_common::PeripheralRef;
|
2022-07-23 01:29:35 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[allow(unused)]
|
2021-12-08 03:04:39 +01:00
|
|
|
pub fn read<'a, W: Word>(
|
2022-07-23 14:00:19 +02:00
|
|
|
channel: impl Peripheral<P = impl Channel> + 'a,
|
2021-07-15 05:42:06 +02:00
|
|
|
request: Request,
|
2021-12-08 03:18:15 +01:00
|
|
|
reg_addr: *mut W,
|
2021-11-19 19:15:55 +01:00
|
|
|
buf: &'a mut [W],
|
2021-12-08 03:04:39 +01:00
|
|
|
) -> impl Future<Output = ()> + 'a {
|
2022-01-25 16:28:49 +01:00
|
|
|
assert!(buf.len() > 0 && buf.len() <= 0xFFFF);
|
2022-07-23 14:00:19 +02:00
|
|
|
into_ref!(channel);
|
2021-07-15 05:42:06 +02:00
|
|
|
|
2022-03-16 17:52:06 +01:00
|
|
|
unsafe { channel.start_read::<W>(request, reg_addr, buf, Default::default()) };
|
2021-12-08 03:04:39 +01:00
|
|
|
|
2022-01-19 15:59:25 +01:00
|
|
|
Transfer::new(channel)
|
2021-11-19 19:15:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(unused)]
|
2021-12-08 03:04:39 +01:00
|
|
|
pub fn write<'a, W: Word>(
|
2022-07-23 14:00:19 +02:00
|
|
|
channel: impl Peripheral<P = impl Channel> + 'a,
|
2021-07-15 05:42:06 +02:00
|
|
|
request: Request,
|
2021-11-19 19:15:55 +01:00
|
|
|
buf: &'a [W],
|
2021-12-08 03:18:15 +01:00
|
|
|
reg_addr: *mut W,
|
2021-12-08 03:04:39 +01:00
|
|
|
) -> impl Future<Output = ()> + 'a {
|
2022-01-25 16:28:49 +01:00
|
|
|
assert!(buf.len() > 0 && buf.len() <= 0xFFFF);
|
2022-07-23 14:00:19 +02:00
|
|
|
into_ref!(channel);
|
2021-11-19 19:15:55 +01:00
|
|
|
|
2022-03-16 17:52:06 +01:00
|
|
|
unsafe { channel.start_write::<W>(request, buf, reg_addr, Default::default()) };
|
2021-12-08 03:04:39 +01:00
|
|
|
|
2022-01-19 15:59:25 +01:00
|
|
|
Transfer::new(channel)
|
2021-11-19 19:15:55 +01:00
|
|
|
}
|
2021-07-20 21:20:16 +02:00
|
|
|
|
2021-11-19 19:15:55 +01:00
|
|
|
#[allow(unused)]
|
2021-12-08 03:04:39 +01:00
|
|
|
pub fn write_repeated<'a, W: Word>(
|
2022-07-23 14:00:19 +02:00
|
|
|
channel: impl Peripheral<P = impl Channel> + 'a,
|
2021-07-20 21:20:16 +02:00
|
|
|
request: Request,
|
2021-11-19 19:15:55 +01:00
|
|
|
repeated: W,
|
|
|
|
count: usize,
|
2021-12-08 03:18:15 +01:00
|
|
|
reg_addr: *mut W,
|
2021-12-08 03:04:39 +01:00
|
|
|
) -> impl Future<Output = ()> + 'a {
|
2022-07-23 14:00:19 +02:00
|
|
|
into_ref!(channel);
|
2021-11-19 19:15:55 +01:00
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
unsafe { channel.start_write_repeated::<W>(request, repeated, count, reg_addr, Default::default()) };
|
2021-12-08 03:04:39 +01:00
|
|
|
|
2022-01-19 15:59:25 +01:00
|
|
|
Transfer::new(channel)
|
2021-11-19 19:15:55 +01:00
|
|
|
}
|
|
|
|
|
2022-01-19 15:59:25 +01:00
|
|
|
pub(crate) struct Transfer<'a, C: Channel> {
|
2022-07-23 14:00:19 +02:00
|
|
|
channel: PeripheralRef<'a, C>,
|
2021-12-08 03:04:39 +01:00
|
|
|
}
|
2021-11-19 19:15:55 +01:00
|
|
|
|
2022-01-19 15:59:25 +01:00
|
|
|
impl<'a, C: Channel> Transfer<'a, C> {
|
2022-07-23 14:00:19 +02:00
|
|
|
pub(crate) fn new(channel: impl Peripheral<P = C> + 'a) -> Self {
|
|
|
|
into_ref!(channel);
|
2022-07-23 01:29:35 +02:00
|
|
|
Self { channel }
|
2022-01-19 15:59:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 03:04:39 +01:00
|
|
|
impl<'a, C: Channel> Drop for Transfer<'a, C> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.channel.request_stop();
|
|
|
|
while self.channel.is_running() {}
|
|
|
|
}
|
|
|
|
}
|
2021-11-19 19:15:55 +01:00
|
|
|
|
2021-12-08 03:04:39 +01:00
|
|
|
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() {
|
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
|
|
|
}
|
2021-12-08 03:04:39 +01:00
|
|
|
}
|
2021-11-19 19:15:55 +01:00
|
|
|
}
|
2021-07-15 05:42:06 +02:00
|
|
|
}
|
|
|
|
|
2022-07-23 14:00:19 +02:00
|
|
|
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
|
2021-11-19 19:15:55 +01:00
|
|
|
|
2021-07-15 05:42:06 +02:00
|
|
|
pub struct NoDma;
|
|
|
|
|
2022-07-23 14:00:19 +02:00
|
|
|
impl_peripheral!(NoDma);
|
2021-07-15 05:42:06 +02:00
|
|
|
|
|
|
|
// 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();
|
2022-04-26 23:57:26 +02:00
|
|
|
#[cfg(gpdma)]
|
|
|
|
gpdma::init();
|
2021-07-15 05:42:06 +02:00
|
|
|
}
|
2022-01-19 15:59:25 +01: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 { mem::transmute(slice) }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
|
|
|
|
unsafe { mem::transmute(slice) }
|
|
|
|
}
|