use core::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
mem,
ops::Not,
ptr,
sync::atomic::{compiler_fence, Ordering},
};
use embedded_dma::StaticWriteBuffer;
pub mod traits;
use traits::{
sealed::{Bits, Sealed},
Channel, DMASet, Direction, Instance, PeriAddress, RccEnable, Stream,
};
#[derive(PartialEq)]
pub enum DMAError<T> {
NotReady(T),
SmallBuffer(T),
Overrun(T),
}
impl<T> Debug for DMAError<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
DMAError::NotReady(_) => f.debug_tuple("NotReady").finish(),
DMAError::SmallBuffer(_) => f.debug_tuple("SmalBuffer").finish(),
DMAError::Overrun(_) => f.debug_tuple("Overrun").finish(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DmaDirection {
MemoryToMemory,
PeripheralToMemory,
MemoryToPeripheral,
}
#[derive(Debug, Clone, Copy)]
pub struct PeripheralToMemory;
impl Bits<u8> for PeripheralToMemory {
#[inline(always)]
fn bits(self) -> u8 {
0
}
}
impl Direction for PeripheralToMemory {
fn new() -> Self {
PeripheralToMemory
}
#[inline(always)]
fn direction() -> DmaDirection {
DmaDirection::PeripheralToMemory
}
}
#[derive(Debug, Clone, Copy)]
pub struct MemoryToMemory<T> {
_data: PhantomData<T>,
}
impl<T> Bits<u8> for MemoryToMemory<T> {
#[inline(always)]
fn bits(self) -> u8 {
2
}
}
impl<T> Direction for MemoryToMemory<T> {
fn new() -> Self {
Self { _data: PhantomData }
}
#[inline(always)]
fn direction() -> DmaDirection {
DmaDirection::MemoryToMemory
}
}
#[derive(Debug, Clone, Copy)]
pub struct MemoryToPeripheral;
impl Bits<u8> for MemoryToPeripheral {
#[inline(always)]
fn bits(self) -> u8 {
1
}
}
impl Direction for MemoryToPeripheral {
fn new() -> Self {
MemoryToPeripheral
}
fn direction() -> DmaDirection {
DmaDirection::MemoryToPeripheral
}
}
unsafe impl PeriAddress for MemoryToMemory<u8> {
fn address(&self) -> u32 {
unimplemented!()
}
type MemSize = u8;
}
unsafe impl PeriAddress for MemoryToMemory<u16> {
fn address(&self) -> u32 {
unimplemented!()
}
type MemSize = u16;
}
unsafe impl PeriAddress for MemoryToMemory<u32> {
fn address(&self) -> u32 {
unimplemented!()
}
type MemSize = u32;
}
#[derive(Debug, Clone, Copy)]
pub enum FifoLevel {
GtZeroLtQuarter,
GteQuarterLtHalf,
GteHalfLtThreeQuarter,
GteThreeQuarterLtFull,
Empty,
Full,
Invalid,
}
impl From<u8> for FifoLevel {
fn from(value: u8) -> Self {
match value {
0 => FifoLevel::GtZeroLtQuarter,
1 => FifoLevel::GteQuarterLtHalf,
2 => FifoLevel::GteHalfLtThreeQuarter,
3 => FifoLevel::GteThreeQuarterLtFull,
4 => FifoLevel::Empty,
5 => FifoLevel::Full,
_ => FifoLevel::Invalid,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CurrentBuffer {
FirstBuffer,
DoubleBuffer,
}
impl Not for CurrentBuffer {
type Output = CurrentBuffer;
fn not(self) -> Self::Output {
if self == CurrentBuffer::FirstBuffer {
CurrentBuffer::DoubleBuffer
} else {
CurrentBuffer::FirstBuffer
}
}
}
pub struct Stream0<DMA> {
_dma: PhantomData<DMA>,
}
pub struct Stream1<DMA> {
_dma: PhantomData<DMA>,
}
pub struct Stream2<DMA> {
_dma: PhantomData<DMA>,
}
pub struct Stream3<DMA> {
_dma: PhantomData<DMA>,
}
pub struct Stream4<DMA> {
_dma: PhantomData<DMA>,
}
pub struct Stream5<DMA> {
_dma: PhantomData<DMA>,
}
pub struct Stream6<DMA> {
_dma: PhantomData<DMA>,
}
pub struct Stream7<DMA> {
_dma: PhantomData<DMA>,
}
impl<DMA> Sealed for Stream0<DMA> {}
impl<DMA> Sealed for Stream1<DMA> {}
impl<DMA> Sealed for Stream2<DMA> {}
impl<DMA> Sealed for Stream3<DMA> {}
impl<DMA> Sealed for Stream4<DMA> {}
impl<DMA> Sealed for Stream5<DMA> {}
impl<DMA> Sealed for Stream6<DMA> {}
impl<DMA> Sealed for Stream7<DMA> {}
pub struct StreamsTuple<T>(
pub Stream0<T>,
pub Stream1<T>,
pub Stream2<T>,
pub Stream3<T>,
pub Stream4<T>,
pub Stream5<T>,
pub Stream6<T>,
pub Stream7<T>,
);
impl<T: RccEnable> StreamsTuple<T> {
pub fn new(regs: T) -> Self {
regs.rcc_enable();
Self(
Stream0 { _dma: PhantomData },
Stream1 { _dma: PhantomData },
Stream2 { _dma: PhantomData },
Stream3 { _dma: PhantomData },
Stream4 { _dma: PhantomData },
Stream5 { _dma: PhantomData },
Stream6 { _dma: PhantomData },
Stream7 { _dma: PhantomData },
)
}
}
macro_rules! dma_stream {
($(($name:ident, $number:expr ,$ifcr:ident, $tcif:ident, $htif:ident, $teif:ident, $dmeif:ident,
$feif:ident, $isr:ident, $tcisr:ident, $htisr:ident)),+ $(,)*) => {
$(
impl<I: Instance> Stream for $name<I> {
const NUMBER: usize = $number;
#[inline(always)]
fn clear_interrupts(&mut self) {
let dma = unsafe { &*I::ptr() };
dma.$ifcr.write(|w| w
.$tcif().set_bit()
.$htif().set_bit()
.$teif().set_bit()
.$dmeif().set_bit()
.$feif().set_bit()
);
}
#[inline(always)]
fn clear_transfer_complete_interrupt(&mut self) {
let dma = unsafe { &*I::ptr() };
dma.$ifcr.write(|w| w.$tcif().set_bit());
}
#[inline(always)]
fn clear_half_transfer_interrupt(&mut self) {
let dma = unsafe { &*I::ptr() };
dma.$ifcr.write(|w| w.$htif().set_bit());
}
#[inline(always)]
fn clear_transfer_error_interrupt(&mut self) {
let dma = unsafe { &*I::ptr() };
dma.$ifcr.write(|w| w.$teif().set_bit());
}
#[inline(always)]
fn clear_direct_mode_error_interrupt(&mut self) {
let dma = unsafe { &*I::ptr() };
dma.$ifcr.write(|w| w.$dmeif().set_bit());
}
#[inline(always)]
fn clear_fifo_error_interrupt(&mut self) {
let dma = unsafe { &*I::ptr() };
dma.$ifcr.write(|w| w.$feif().set_bit());
}
#[inline(always)]
fn get_transfer_complete_flag() -> bool {
let dma = unsafe { &*I::ptr() };
dma.$isr.read().$tcisr().bit_is_set()
}
#[inline(always)]
fn get_half_transfer_flag() -> bool {
let dma = unsafe { &*I::ptr() };
dma.$isr.read().$htisr().bit_is_set()
}
#[inline(always)]
fn set_peripheral_address(&mut self, value: u32) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].par.write(|w| unsafe { w.pa().bits(value) });
}
#[inline(always)]
fn set_memory_address(&mut self, value: u32) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].m0ar.write(|w| unsafe { w.m0a().bits(value) });
}
#[inline(always)]
fn get_memory_address(&self) -> u32 {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].m0ar.read().m0a().bits()
}
#[inline(always)]
fn set_memory_double_buffer_address(&mut self, value: u32) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].m1ar.write(|w| unsafe { w.m1a().bits(value) });
}
#[inline(always)]
fn get_memory_double_buffer_address(&self) -> u32 {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].m1ar.read().m1a().bits()
}
#[inline(always)]
fn set_number_of_transfers(&mut self, value: u16) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].ndtr.write(|w| w.ndt().bits(value));
}
#[inline(always)]
fn get_number_of_transfers() -> u16 {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].ndtr.read().ndt().bits()
}
#[inline(always)]
unsafe fn enable(&mut self) {
let dma = &*I::ptr();
dma.st[Self::NUMBER].cr.modify(|_, w| w.en().set_bit());
}
#[inline(always)]
fn is_enabled() -> bool {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.read().en().bit_is_set()
}
fn disable(&mut self) {
if Self::is_enabled() {
let dma = unsafe { &*I::ptr() };
let (tc, ht, te, dm) = Self::get_interrupts_enable();
self
.set_interrupts_enable(false, false, false, false);
dma.st[Self::NUMBER].cr.modify(|_, w| w.en().clear_bit());
while Self::is_enabled() {}
self.clear_interrupts();
self.set_interrupts_enable(tc, ht, te, dm);
}
}
#[inline(always)]
fn set_channel<C: Channel>(&mut self, channel: C) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.chsel().bits(channel.bits()));
}
#[inline(always)]
fn set_priority(&mut self, priority: config::Priority) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.pl().bits(priority.bits()));
}
#[inline(always)]
unsafe fn set_memory_size(&mut self, size: u8) {
let dma = &*I::ptr();
dma.st[Self::NUMBER].cr.modify(|_, w| w.msize().bits(size));
}
#[inline(always)]
unsafe fn set_peripheral_size(&mut self, size: u8) {
let dma = &*I::ptr();
dma.st[Self::NUMBER].cr.modify(|_, w| w.psize().bits(size));
}
#[inline(always)]
fn set_memory_increment(&mut self, increment: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.minc().bit(increment));
}
#[inline(always)]
fn set_peripheral_increment(&mut self, increment: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.pinc().bit(increment));
}
#[inline(always)]
fn set_direction<D: Direction>(&mut self, direction: D) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| unsafe { w.dir().bits(direction.bits()) });
}
#[inline(always)]
fn set_interrupts_enable(
&mut self,
transfer_complete: bool,
half_transfer: bool,
transfer_error: bool,
direct_mode_error: bool,
)
{
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w
.tcie().bit(transfer_complete)
.htie().bit(half_transfer)
.teie().bit(transfer_error)
.dmeie().bit(direct_mode_error)
);
}
#[inline(always)]
fn get_interrupts_enable() -> (bool, bool, bool, bool) {
let dma = unsafe { &*I::ptr() };
let cr = dma.st[Self::NUMBER].cr.read();
(cr.tcie().bit_is_set(), cr.htie().bit_is_set(),
cr.teie().bit_is_set(), cr.dmeie().bit_is_set())
}
#[inline(always)]
fn set_transfer_complete_interrupt_enable(&mut self, transfer_complete_interrupt: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.tcie().bit(transfer_complete_interrupt));
}
#[inline(always)]
fn set_half_transfer_interrupt_enable(&mut self, half_transfer_interrupt: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.htie().bit(half_transfer_interrupt));
}
#[inline(always)]
fn set_transfer_error_interrupt_enable(&mut self, transfer_error_interrupt: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.teie().bit(transfer_error_interrupt));
}
#[inline(always)]
fn set_direct_mode_error_interrupt_enable(&mut self, direct_mode_error_interrupt: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.dmeie().bit(direct_mode_error_interrupt));
}
#[inline(always)]
fn set_fifo_error_interrupt_enable(&mut self, fifo_error_interrupt: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].fcr.modify(|_, w| w.feie().bit(fifo_error_interrupt));
}
#[inline(always)]
fn set_double_buffer(&mut self, double_buffer: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.dbm().bit(double_buffer));
}
#[inline(always)]
fn set_fifo_threshold(&mut self, fifo_threshold: config::FifoThreshold) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].fcr.modify(|_, w| w.fth().bits(fifo_threshold.bits()));
}
#[inline(always)]
fn set_fifo_enable(&mut self, fifo_enable: bool) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].fcr.modify(|_, w| w.dmdis().bit(fifo_enable));
}
#[inline(always)]
fn set_memory_burst(&mut self, memory_burst: config::BurstMode) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.mburst().bits(memory_burst.bits()));
}
#[inline(always)]
fn set_peripheral_burst(&mut self, peripheral_burst: config::BurstMode) {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].cr.modify(|_, w| w.pburst().bits(peripheral_burst.bits()));
}
#[inline(always)]
fn fifo_level() -> FifoLevel {
let dma = unsafe { &*I::ptr() };
dma.st[Self::NUMBER].fcr.read().fs().bits().into()
}
fn current_buffer() -> CurrentBuffer {
let dma = unsafe { &*I::ptr() };
if dma.st[Self::NUMBER].cr.read().ct().bit_is_set() {
CurrentBuffer::DoubleBuffer
} else {
CurrentBuffer::FirstBuffer
}
}
}
)+
};
}
dma_stream!(
(Stream0, 0, lifcr, ctcif0, chtif0, cteif0, cdmeif0, cfeif0, lisr, tcif0, htif0),
(Stream1, 1, lifcr, ctcif1, chtif1, cteif1, cdmeif1, cfeif1, lisr, tcif1, htif1),
(Stream2, 2, lifcr, ctcif2, chtif2, cteif2, cdmeif2, cfeif2, lisr, tcif2, htif2),
(Stream3, 3, lifcr, ctcif3, chtif3, cteif3, cdmeif3, cfeif3, lisr, tcif3, htif3),
(Stream4, 4, hifcr, ctcif4, chtif4, cteif4, cdmeif4, cfeif4, hisr, tcif4, htif4),
(Stream5, 5, hifcr, ctcif5, chtif5, cteif5, cdmeif5, cfeif5, hisr, tcif5, htif5),
(Stream6, 6, hifcr, ctcif6, chtif6, cteif6, cdmeif6, cfeif6, hisr, tcif6, htif6),
(Stream7, 7, hifcr, ctcif7, chtif7, cteif7, cdmeif7, cfeif7, hisr, tcif7, htif7),
);
macro_rules! dma_channel {
($(($name:ident, $value:expr)),+ $(,)*) => {
$(
#[derive(Debug, Clone, Copy)]
pub struct $name;
impl Bits<u8> for $name {
fn bits(self) -> u8 { $value }
}
impl Channel for $name {
fn new() -> Self {
$name
}
}
)+
};
}
dma_channel!(
(Channel0, 0),
(Channel1, 1),
(Channel2, 2),
(Channel3, 3),
(Channel4, 4),
(Channel5, 5),
(Channel6, 6),
(Channel7, 7),
);
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
dma_channel!((Channel8, 8), (Channel9, 9),);
pub mod config {
use super::Bits;
#[derive(Debug, Clone, Copy)]
pub enum Priority {
Low,
Medium,
High,
VeryHigh,
}
impl Bits<u8> for Priority {
fn bits(self) -> u8 {
match self {
Priority::Low => 0,
Priority::Medium => 1,
Priority::High => 2,
Priority::VeryHigh => 3,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum FifoThreshold {
QuarterFull,
HalfFull,
ThreeQuarterFull,
Full,
}
impl Bits<u8> for FifoThreshold {
fn bits(self) -> u8 {
match self {
FifoThreshold::QuarterFull => 0,
FifoThreshold::HalfFull => 1,
FifoThreshold::ThreeQuarterFull => 2,
FifoThreshold::Full => 3,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum BurstMode {
NoBurst,
Burst4,
Burst8,
Burst16,
}
impl Bits<u8> for BurstMode {
fn bits(self) -> u8 {
match self {
BurstMode::NoBurst => 0,
BurstMode::Burst4 => 1,
BurstMode::Burst8 => 2,
BurstMode::Burst16 => 3,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct DmaConfig {
pub(crate) priority: Priority,
pub(crate) memory_increment: bool,
pub(crate) peripheral_increment: bool,
pub(crate) transfer_complete_interrupt: bool,
pub(crate) half_transfer_interrupt: bool,
pub(crate) transfer_error_interrupt: bool,
pub(crate) direct_mode_error_interrupt: bool,
pub(crate) fifo_error_interrupt: bool,
pub(crate) double_buffer: bool,
pub(crate) fifo_threshold: FifoThreshold,
pub(crate) fifo_enable: bool,
pub(crate) memory_burst: BurstMode,
pub(crate) peripheral_burst: BurstMode,
}
impl Default for DmaConfig {
fn default() -> Self {
Self {
priority: Priority::Medium,
memory_increment: false,
peripheral_increment: false,
transfer_complete_interrupt: false,
half_transfer_interrupt: false,
transfer_error_interrupt: false,
direct_mode_error_interrupt: false,
fifo_error_interrupt: false,
double_buffer: false,
fifo_threshold: FifoThreshold::QuarterFull,
fifo_enable: false,
memory_burst: BurstMode::NoBurst,
peripheral_burst: BurstMode::NoBurst,
}
}
}
impl DmaConfig {
#[inline(always)]
pub fn priority(mut self, priority: Priority) -> Self {
self.priority = priority;
self
}
#[inline(always)]
pub fn memory_increment(mut self, memory_increment: bool) -> Self {
self.memory_increment = memory_increment;
self
}
#[inline(always)]
pub fn peripheral_increment(mut self, peripheral_increment: bool) -> Self {
self.peripheral_increment = peripheral_increment;
self
}
#[inline(always)]
pub fn transfer_complete_interrupt(mut self, transfer_complete_interrupt: bool) -> Self {
self.transfer_complete_interrupt = transfer_complete_interrupt;
self
}
#[inline(always)]
pub fn half_transfer_interrupt(mut self, half_transfer_interrupt: bool) -> Self {
self.half_transfer_interrupt = half_transfer_interrupt;
self
}
#[inline(always)]
pub fn transfer_error_interrupt(mut self, transfer_error_interrupt: bool) -> Self {
self.transfer_error_interrupt = transfer_error_interrupt;
self
}
#[inline(always)]
pub fn direct_mode_error_interrupt(mut self, direct_mode_error_interrupt: bool) -> Self {
self.direct_mode_error_interrupt = direct_mode_error_interrupt;
self
}
#[inline(always)]
pub fn fifo_error_interrupt(mut self, fifo_error_interrupt: bool) -> Self {
self.fifo_error_interrupt = fifo_error_interrupt;
self
}
#[inline(always)]
pub fn double_buffer(mut self, double_buffer: bool) -> Self {
self.double_buffer = double_buffer;
self
}
#[inline(always)]
pub fn fifo_threshold(mut self, fifo_threshold: FifoThreshold) -> Self {
self.fifo_threshold = fifo_threshold;
self
}
#[inline(always)]
pub fn fifo_enable(mut self, fifo_enable: bool) -> Self {
self.fifo_enable = fifo_enable;
self
}
#[inline(always)]
pub fn memory_burst(mut self, memory_burst: BurstMode) -> Self {
self.memory_burst = memory_burst;
self
}
#[inline(always)]
pub fn peripheral_burst(mut self, peripheral_burst: BurstMode) -> Self {
self.peripheral_burst = peripheral_burst;
self
}
}
}
pub struct Transfer<STREAM, CHANNEL, PERIPHERAL, DIRECTION, BUF>
where
STREAM: Stream,
PERIPHERAL: PeriAddress,
BUF: StaticWriteBuffer<Word = <PERIPHERAL as PeriAddress>::MemSize>,
{
stream: STREAM,
_channel: PhantomData<CHANNEL>,
peripheral: PERIPHERAL,
_direction: PhantomData<DIRECTION>,
buf: Option<BUF>,
double_buf: Option<BUF>,
transfer_length: u16,
}
impl<STREAM, CHANNEL, PERIPHERAL, DIR, BUF> Transfer<STREAM, CHANNEL, PERIPHERAL, DIR, BUF>
where
STREAM: Stream,
CHANNEL: Channel,
DIR: Direction,
PERIPHERAL: PeriAddress + DMASet<STREAM, CHANNEL, DIR>,
BUF: StaticWriteBuffer<Word = <PERIPHERAL as PeriAddress>::MemSize>,
{
fn apply_config(&mut self, config: config::DmaConfig) {
let msize = mem::size_of::<<PERIPHERAL as PeriAddress>::MemSize>() / 2;
self.stream.clear_interrupts();
self.stream.set_priority(config.priority);
unsafe {
self.stream.set_memory_size(msize as u8);
self.stream.set_peripheral_size(msize as u8);
}
self.stream.set_memory_increment(config.memory_increment);
self.stream
.set_peripheral_increment(config.peripheral_increment);
self.stream
.set_transfer_complete_interrupt_enable(config.transfer_complete_interrupt);
self.stream
.set_half_transfer_interrupt_enable(config.half_transfer_interrupt);
self.stream
.set_transfer_error_interrupt_enable(config.transfer_error_interrupt);
self.stream
.set_direct_mode_error_interrupt_enable(config.direct_mode_error_interrupt);
self.stream
.set_fifo_error_interrupt_enable(config.fifo_error_interrupt);
self.stream.set_double_buffer(config.double_buffer);
self.stream.set_fifo_threshold(config.fifo_threshold);
self.stream.set_fifo_enable(config.fifo_enable);
self.stream.set_memory_burst(config.memory_burst);
self.stream.set_peripheral_burst(config.peripheral_burst);
}
pub fn init(
mut stream: STREAM,
peripheral: PERIPHERAL,
mut memory: BUF,
mut double_buf: Option<BUF>,
config: config::DmaConfig,
) -> Self {
stream.disable();
stream.set_channel(CHANNEL::new());
stream.set_direction(DIR::new());
let (buf_ptr, buf_len) = unsafe { memory.write_buffer() };
stream.set_memory_address(buf_ptr as u32);
let is_mem2mem = DIR::direction() == DmaDirection::MemoryToMemory;
if is_mem2mem {
if !config.fifo_enable {
panic!("Fifo disabled.");
} else if config.double_buffer {
panic!("Double buffering enabled.");
}
} else {
stream.set_peripheral_address(peripheral.address());
}
let db_len = if let Some(ref mut db) = double_buf {
let (db_ptr, db_len) = unsafe { db.write_buffer() };
if is_mem2mem {
stream.set_peripheral_address(db_ptr as u32);
} else {
stream.set_memory_double_buffer_address(db_ptr as u32);
}
Some(db_len)
} else {
if config.double_buffer {
panic!("No second buffer.");
}
None
};
let n_transfers = if let Some(db) = db_len {
buf_len.min(db) as u16
} else {
buf_len as u16
};
stream.set_number_of_transfers(n_transfers);
let mut transfer = Self {
stream,
_channel: PhantomData,
peripheral,
_direction: PhantomData,
buf: Some(memory),
double_buf,
transfer_length: n_transfers,
};
transfer.apply_config(config);
transfer
}
pub fn start<F>(&mut self, f: F)
where
F: FnOnce(&mut PERIPHERAL),
{
compiler_fence(Ordering::Release);
unsafe {
self.stream.enable();
}
f(&mut self.peripheral);
}
pub fn pause<F>(&mut self, f: F)
where
F: FnOnce(&mut PERIPHERAL),
{
f(&mut self.peripheral);
self.stream.disable()
}
pub fn next_transfer(
&mut self,
mut new_buf: BUF,
) -> Result<(BUF, CurrentBuffer), DMAError<BUF>> {
if self.double_buf.is_some() && DIR::direction() != DmaDirection::MemoryToMemory {
if !STREAM::get_transfer_complete_flag() {
return Err(DMAError::NotReady(new_buf));
}
self.stream.clear_transfer_complete_interrupt();
let (new_buf_ptr, new_buf_len) = unsafe { new_buf.write_buffer() };
if new_buf_len < usize::from(self.transfer_length) {
return Err(DMAError::SmallBuffer(new_buf));
}
if STREAM::current_buffer() == CurrentBuffer::DoubleBuffer {
compiler_fence(Ordering::Release);
self.stream.set_memory_address(new_buf_ptr as u32);
if self.stream.get_memory_address() != new_buf_ptr as u32 {
self.stream.clear_transfer_complete_interrupt();
return Err(DMAError::Overrun(new_buf));
}
compiler_fence(Ordering::Acquire);
let old_buf = self.buf.replace(new_buf);
return Ok((old_buf.unwrap(), CurrentBuffer::FirstBuffer));
} else {
compiler_fence(Ordering::Release);
self.stream
.set_memory_double_buffer_address(new_buf_ptr as u32);
if self.stream.get_memory_double_buffer_address() != new_buf_ptr as u32 {
self.stream.clear_transfer_complete_interrupt();
return Err(DMAError::Overrun(new_buf));
}
compiler_fence(Ordering::Acquire);
let old_buf = self.double_buf.replace(new_buf);
return Ok((old_buf.unwrap(), CurrentBuffer::DoubleBuffer));
}
}
self.stream.disable();
self.stream.clear_transfer_complete_interrupt();
compiler_fence(Ordering::SeqCst);
let (buf_ptr, buf_len) = unsafe { new_buf.write_buffer() };
self.stream.set_memory_address(buf_ptr as u32);
self.stream.set_number_of_transfers(buf_len as u16);
let old_buf = self.buf.replace(new_buf);
unsafe {
self.stream.enable();
}
Ok((old_buf.unwrap(), CurrentBuffer::FirstBuffer))
}
pub fn free(mut self) -> (STREAM, PERIPHERAL, BUF, Option<BUF>) {
self.stream.disable();
compiler_fence(Ordering::SeqCst);
self.stream.clear_interrupts();
unsafe {
let stream = ptr::read(&self.stream);
let peripheral = ptr::read(&self.peripheral);
let buf = ptr::read(&self.buf);
let double_buf = ptr::read(&self.double_buf);
mem::forget(self);
(stream, peripheral, buf.unwrap(), double_buf)
}
}
#[inline(always)]
pub fn clear_interrupts(&mut self) {
self.stream.clear_interrupts();
}
#[inline(always)]
pub fn clear_transfer_complete_interrupt(&mut self) {
self.stream.clear_transfer_complete_interrupt();
}
#[inline(always)]
pub fn clear_half_transfer_interrupt(&mut self) {
self.stream.clear_half_transfer_interrupt();
}
#[inline(always)]
pub fn clear_transfer_error_interrupt(&mut self) {
self.stream.clear_transfer_error_interrupt();
}
#[inline(always)]
pub fn clear_direct_mode_error_interrupt(&mut self) {
self.stream.clear_direct_mode_error_interrupt();
}
#[inline(always)]
pub fn clear_fifo_error_interrupt(&mut self) {
self.stream.clear_fifo_error_interrupt();
}
pub unsafe fn get_stream(&mut self) -> &mut STREAM {
&mut self.stream
}
pub unsafe fn next_transfer_with<F, T>(&mut self, f: F) -> Result<T, DMAError<()>>
where
F: FnOnce(BUF, CurrentBuffer) -> (BUF, T),
{
if self.double_buf.is_some() && DIR::direction() != DmaDirection::MemoryToMemory {
if !STREAM::get_transfer_complete_flag() {
return Err(DMAError::NotReady(()));
}
self.stream.clear_transfer_complete_interrupt();
let current_buffer = STREAM::current_buffer();
let db = if current_buffer == CurrentBuffer::DoubleBuffer {
self.buf.take().unwrap()
} else {
self.double_buf.take().unwrap()
};
let r = f(db, !current_buffer);
let mut new_buf = r.0;
let (new_buf_ptr, new_buf_len) = new_buf.write_buffer();
assert!(
new_buf_len >= usize::from(self.transfer_length),
"Second Buffer not big enough"
);
if STREAM::get_transfer_complete_flag() {
panic!("Overrun");
}
if current_buffer == CurrentBuffer::DoubleBuffer {
compiler_fence(Ordering::Release);
self.stream.set_memory_address(new_buf_ptr as u32);
if self.stream.get_memory_address() != new_buf_ptr as u32 {
panic!("Overrun");
}
compiler_fence(Ordering::Acquire);
self.buf.replace(new_buf);
return Ok(r.1);
} else {
compiler_fence(Ordering::Release);
self.stream
.set_memory_double_buffer_address(new_buf_ptr as u32);
if self.stream.get_memory_double_buffer_address() != new_buf_ptr as u32 {
panic!("Overrun");
}
compiler_fence(Ordering::Acquire);
self.double_buf.replace(new_buf);
return Ok(r.1);
}
}
self.stream.disable();
self.stream.clear_transfer_complete_interrupt();
compiler_fence(Ordering::SeqCst);
let old_buf = self.buf.take().unwrap();
let r = f(old_buf, CurrentBuffer::FirstBuffer);
let mut new_buf = r.0;
let (buf_ptr, buf_len) = new_buf.write_buffer();
self.stream.set_memory_address(buf_ptr as u32);
self.stream.set_number_of_transfers(buf_len as u16);
self.buf.replace(new_buf);
self.stream.enable();
Ok(r.1)
}
}
impl<STREAM, CHANNEL, PERIPHERAL, DIR, BUF> Drop for Transfer<STREAM, CHANNEL, PERIPHERAL, DIR, BUF>
where
STREAM: Stream,
PERIPHERAL: PeriAddress,
BUF: StaticWriteBuffer<Word = <PERIPHERAL as PeriAddress>::MemSize>,
{
fn drop(&mut self) {
self.stream.disable();
compiler_fence(Ordering::SeqCst);
}
}