#![allow(dead_code)]
use core::marker::PhantomData;
use core::ops;
use crate::rcc::AHB;
#[derive(Debug)]
pub enum Error {
Overrun,
#[doc(hidden)]
_Extensible,
}
pub enum Event {
HalfTransfer,
TransferComplete,
}
#[derive(Clone, Copy, PartialEq)]
pub enum Half {
First,
Second,
}
pub struct CircBuffer<BUFFER, CHANNEL>
where
BUFFER: 'static,
{
buffer: &'static mut [BUFFER; 2],
channel: CHANNEL,
readable_half: Half,
}
impl<BUFFER, CHANNEL> CircBuffer<BUFFER, CHANNEL> {
pub(crate) fn new(buf: &'static mut [BUFFER; 2], chan: CHANNEL) -> Self {
CircBuffer {
buffer: buf,
channel: chan,
readable_half: Half::Second,
}
}
}
pub trait Static<B> {
fn borrow(&self) -> &B;
}
impl<B> Static<B> for &'static B {
fn borrow(&self) -> &B {
*self
}
}
impl<B> Static<B> for &'static mut B {
fn borrow(&self) -> &B {
*self
}
}
pub trait DmaExt {
type Channels;
fn split(self, ahb: &mut AHB) -> Self::Channels;
}
pub struct Transfer<MODE, BUFFER, PAYLOAD> {
_mode: PhantomData<MODE>,
buffer: BUFFER,
payload: PAYLOAD,
}
impl<BUFFER, PAYLOAD> Transfer<R, BUFFER, PAYLOAD> {
pub(crate) fn r(buffer: BUFFER, payload: PAYLOAD) -> Self {
Transfer {
_mode: PhantomData,
buffer,
payload,
}
}
}
impl<BUFFER, PAYLOAD> Transfer<W, BUFFER, PAYLOAD> {
pub(crate) fn w(buffer: BUFFER, payload: PAYLOAD) -> Self {
Transfer {
_mode: PhantomData,
buffer,
payload,
}
}
}
impl<BUFFER, PAYLOAD> ops::Deref for Transfer<R, BUFFER, PAYLOAD> {
type Target = BUFFER;
fn deref(&self) -> &BUFFER {
&self.buffer
}
}
pub struct R;
pub struct W;
macro_rules! dma {
($($DMAX:ident: ($dmaX:ident, $dmaXen:ident, $dmaXrst:ident, {
$($CX:ident: (
$chX:ident,
$htifX:ident,
$tcifX:ident,
$chtifX:ident,
$ctcifX:ident,
$cgifX:ident
),)+
}),)+) => {
$(
pub mod $dmaX {
use core::sync::atomic::{self, Ordering};
use core::ptr;
use crate::pac::{$DMAX, dma1};
use crate::dma::{CircBuffer, DmaExt, Error, Event, Half, Transfer, W, RxDma, TxDma};
use crate::rcc::AHB;
pub struct Channels((), $(pub $CX),+);
$(
pub struct $CX { _0: () }
impl $CX {
pub fn set_peripheral_address(&mut self, address: u32, inc: bool) {
self.ch().par.write(|w| w.pa().bits(address) );
self.ch().cr.modify(|_, w| w.pinc().bit(inc) );
}
pub fn set_memory_address(&mut self, address: u32, inc: bool) {
self.ch().mar.write(|w| w.ma().bits(address) );
self.ch().cr.modify(|_, w| w.minc().bit(inc) );
}
pub fn set_transfer_length(&mut self, len: usize) {
self.ch().ndtr.write(|w| w.ndt().bits(cast::u16(len).unwrap()));
}
pub fn start(&mut self) {
self.ch().cr.modify(|_, w| w.en().set_bit() );
}
pub fn stop(&mut self) {
self.ifcr().write(|w| w.$cgifX().set_bit());
self.ch().cr.modify(|_, w| w.en().clear_bit() );
}
fn in_progress(&self) -> bool {
self.isr().$tcifX().bit_is_clear()
}
}
impl $CX {
pub fn listen(&mut self, event: Event) {
match event {
Event::HalfTransfer => self.ch().cr.modify(|_, w| w.htie().set_bit()),
Event::TransferComplete => {
self.ch().cr.modify(|_, w| w.tcie().set_bit())
}
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::HalfTransfer => {
self.ch().cr.modify(|_, w| w.htie().clear_bit())
},
Event::TransferComplete => {
self.ch().cr.modify(|_, w| w.tcie().clear_bit())
}
}
}
pub fn ch(&mut self) -> &dma1::CH {
unsafe { &(*$DMAX::ptr()).$chX }
}
pub fn isr(&self) -> dma1::isr::R {
unsafe { (*$DMAX::ptr()).isr.read() }
}
pub fn ifcr(&self) -> &dma1::IFCR {
unsafe { &(*$DMAX::ptr()).ifcr }
}
pub fn get_ndtr(&self) -> u32 {
unsafe { &(*$DMAX::ptr())}.$chX.ndtr.read().bits()
}
}
impl<B> CircBuffer<B, $CX> {
pub fn peek<R, F>(&mut self, f: F) -> Result<R, Error>
where
F: FnOnce(&B, Half) -> R,
{
let half_being_read = self.readable_half()?;
let buf = match half_being_read {
Half::First => &self.buffer[0],
Half::Second => &self.buffer[1],
};
let ret = f(buf, half_being_read);
let isr = self.channel.isr();
let first_half_is_done = isr.$htifX().bit_is_set();
let second_half_is_done = isr.$tcifX().bit_is_set();
if (half_being_read == Half::First && second_half_is_done) ||
(half_being_read == Half::Second && first_half_is_done) {
Err(Error::Overrun)
} else {
Ok(ret)
}
}
pub fn readable_half(&mut self) -> Result<Half, Error> {
let isr = self.channel.isr();
let first_half_is_done = isr.$htifX().bit_is_set();
let second_half_is_done = isr.$tcifX().bit_is_set();
if first_half_is_done && second_half_is_done {
return Err(Error::Overrun);
}
let last_read_half = self.readable_half;
Ok(match last_read_half {
Half::First => {
if second_half_is_done {
self.channel.ifcr().write(|w| w.$ctcifX().set_bit());
self.readable_half = Half::Second;
Half::Second
} else {
last_read_half
}
}
Half::Second => {
if first_half_is_done {
self.channel.ifcr().write(|w| w.$chtifX().set_bit());
self.readable_half = Half::First;
Half::First
} else {
last_read_half
}
}
})
}
}
impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, RxDma<PAYLOAD, $CX>> {
pub fn is_done(&self) -> bool {
!self.payload.channel.in_progress()
}
pub fn wait(mut self) -> (BUFFER, RxDma<PAYLOAD, $CX>) {
while !self.is_done() {}
atomic::compiler_fence(Ordering::Acquire);
self.payload.stop();
unsafe { ptr::read_volatile(&0); }
atomic::compiler_fence(Ordering::Acquire);
(self.buffer, self.payload)
}
}
impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, TxDma<PAYLOAD, $CX>> {
pub fn is_done(&self) -> bool {
!self.payload.channel.in_progress()
}
pub fn wait(mut self) -> (BUFFER, TxDma<PAYLOAD, $CX>) {
while !self.is_done() {}
atomic::compiler_fence(Ordering::Acquire);
self.payload.stop();
unsafe { ptr::read_volatile(&0); }
atomic::compiler_fence(Ordering::Acquire);
(self.buffer, self.payload)
}
}
impl<BUFFER, PAYLOAD> Transfer<W, &'static mut BUFFER, RxDma<PAYLOAD, $CX>> {
pub fn peek<T>(&self) -> &[T]
where
BUFFER: AsRef<[T]>,
{
let pending = self.payload.channel.get_ndtr() as usize;
let slice = self.buffer.as_ref();
let capacity = slice.len();
&slice[..(capacity - pending)]
}
}
impl<PAYLOAD> RxDma<PAYLOAD, $CX> {
pub fn start(&mut self) {
self.channel.start()
}
pub fn stop(&mut self) {
self.channel.stop()
}
}
impl<PAYLOAD> TxDma<PAYLOAD, $CX> {
pub fn start(&mut self) {
self.channel.start()
}
pub fn stop(&mut self) {
self.channel.stop()
}
}
)+
impl DmaExt for $DMAX {
type Channels = Channels;
fn split(self, ahb: &mut AHB) -> Channels {
ahb.enr().modify(|_, w| w.$dmaXen().set_bit());
$(
self.$chX.cr.reset();
)+
Channels((), $($CX { _0: () }),+)
}
}
}
)+
}
}
dma! {
DMA1: (dma1, dma1en, dma1rst, {
C1: (
ch1,
htif1, tcif1,
chtif1, ctcif1, cgif1
),
C2: (
ch2,
htif2, tcif2,
chtif2, ctcif2, cgif2
),
C3: (
ch3,
htif3, tcif3,
chtif3, ctcif3, cgif3
),
C4: (
ch4,
htif4, tcif4,
chtif4, ctcif4, cgif4
),
C5: (
ch5,
htif5, tcif5,
chtif5, ctcif5, cgif5
),
C6: (
ch6,
htif6, tcif6,
chtif6, ctcif6, cgif6
),
C7: (
ch7,
htif7, tcif7,
chtif7, ctcif7, cgif7
),
}),
DMA2: (dma2, dma2en, dma2rst, {
C1: (
ch1,
htif1, tcif1,
chtif1, ctcif1, cgif1
),
C2: (
ch2,
htif2, tcif2,
chtif2, ctcif2, cgif2
),
C3: (
ch3,
htif3, tcif3,
chtif3, ctcif3, cgif3
),
C4: (
ch4,
htif4, tcif4,
chtif4, ctcif4, cgif4
),
C5: (
ch5,
htif5, tcif5,
chtif5, ctcif5, cgif5
),
}),
}
pub struct RxDma<PAYLOAD, RXCH> {
pub(crate) _payload: PhantomData<PAYLOAD>,
pub(crate) channel: RXCH,
}
pub struct TxDma<PAYLOAD, TXCH> {
pub(crate) _payload: PhantomData<PAYLOAD>,
pub(crate) channel: TXCH,
}
pub struct RxTxDma<PAYLOAD, RXCH, TXCH> {
pub(crate) _payload: PhantomData<PAYLOAD>,
pub(crate) rxchannel: RXCH,
pub(crate) txchannel: TXCH,
}
pub trait Receive {
type RxChannel;
type TransmittedWord;
}
pub trait Transmit {
type TxChannel;
type ReceivedWord;
}
pub trait CircReadDma<B, RS>: Receive
where
B: AsMut<[RS]>,
Self: core::marker::Sized,
{
fn circ_read(self, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self::RxChannel>;
}
pub trait ReadDma<B, RS>: Receive
where
B: AsMut<[RS]>,
Self: core::marker::Sized,
{
fn read(
self,
buffer: &'static mut B,
) -> Transfer<W, &'static mut B, Self>;
}
pub trait WriteDma<A, B, TS>: Transmit
where
A: AsRef<[TS]>,
B: Static<A>,
Self: core::marker::Sized,
{
fn write(self, buffer: B) -> Transfer<R, B, Self>;
}