use core::{
ops::Deref,
sync::atomic::{self, Ordering},
};
use cfg_if::cfg_if;
use crate::{
error::{Error, Result},
pac::RCC,
util::bounded_loop,
};
cfg_if! {
if #[cfg(any(
feature = "f3x4",
feature = "f301",
all(feature = "g0", not(any(feature = "g0b0", feature = "g0b1", feature = "g0c1")))
))] {
use crate::{pac::{dma1, DMA1}, util::rcc_en_reset};
} else if #[cfg(feature = "c0")] { use crate::{pac::{dma as dma1, DMA as DMA1}, util::rcc_en_reset};
} else {
use crate::{pac::{dma1, dma2, DMA1, DMA2}, util::rcc_en_reset};
}
}
#[cfg(any(feature = "g0", feature = "g4", feature = "wl"))]
use crate::pac::DMAMUX;
#[cfg(any(feature = "l5", feature = "wb", feature = "h7"))]
use crate::pac::DMAMUX1 as DMAMUX;
#[cfg(feature = "h7")]
use crate::pac::DMAMUX2;
#[non_exhaustive]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum DmaError {
TransferError,
#[cfg(any(feature = "h7", feature = "f4"))]
FifoError,
#[cfg(any(feature = "h7", feature = "f4"))]
DirectModeError,
}
#[derive(Clone, Copy)]
pub enum DmaPeriph {
Dma1,
#[cfg(dma2)]
Dma2,
}
#[derive(Copy, Clone)]
#[repr(usize)]
#[cfg(not(any(feature = "h7", feature = "wl", feature = "wb", feature = "g0")))]
pub enum DmaInput {
Adc1 = 5,
Dac1Ch1 = 6,
Dac1Ch2 = 7,
Tim6Up = 8,
Tim7Up = 9,
Spi1Rx = 10,
Spi1Tx = 11,
Spi2Rx = 12,
Spi2Tx = 13,
Spi3Rx = 14,
Spi3Tx = 15,
I2c1Rx = 16,
I2c1Tx = 17,
I2c2Rx = 18,
I2c2Tx = 19,
I2c3Rx = 20,
I2c3Tx = 21,
I2c4Rx = 22,
I2c4Tx = 23,
Usart1Rx = 24,
Usart1Tx = 25,
Usart2Rx = 26,
Usart2Tx = 27,
Usart3Rx = 28,
Usart3Tx = 29,
Uart4Rx = 30,
Uart4Tx = 31,
Uart5Rx = 32,
Uart5Tx = 33,
Lpuart1Rx = 34,
Lpuart1Tx = 35,
Adc2 = 36,
Adc3 = 37,
Adc4 = 38,
Adc5 = 39,
Quadspi = 40,
Dac2Ch1 = 41,
Tim1Ch1 = 42,
Tim1Ch2 = 43,
Tim1Ch3 = 44,
Tim1Ch4 = 45,
TimUp = 46,
Tim1Trig = 47,
Tim1Com = 48,
Tim8Ch1 = 49,
Tim8Ch2 = 50,
Tim8Ch3 = 51,
Tim8Ch4 = 52,
Tim8Up = 53,
Tim8Trig = 54,
Tim8Com = 55,
Tim2Ch1 = 56,
Tim2Ch2 = 57,
Tim2Ch3 = 58,
Tim2Ch4 = 59,
Tim2Up = 60,
Tim3Ch1 = 61,
Tim3Ch2 = 62,
Tim3Ch3 = 63,
Tim3Ch4 = 64,
Tim3Up = 65,
Tim3Trig = 66,
Tim4Ch1 = 67,
Tim4Ch2 = 68,
Tim4Ch3 = 69,
Tim4Ch4 = 70,
Tim4Up = 71,
Sai1A = 108,
Sai1B = 109,
Sai2A = 203,
Sai2B = 204,
Dfsdm1F0 = 200,
Dfsdm1F1 = 201,
Dfsdm1F2 = 205,
Dfsdm1F3 = 206,
}
#[derive(Copy, Clone)]
#[repr(usize)]
#[cfg(feature = "g0")]
pub enum DmaInput {
Adc = 5,
AesIn = 6,
AesOut = 7,
Dac1Ch1 = 8,
Dac1Ch2 = 9,
I2c1Rx = 10,
I2c1Tx = 11,
I2c2Rx = 12,
I2c2Tx = 13,
Lpuart1Rx = 14,
Lpuart1Tx = 15,
Spi1Rx = 16,
Spi1Tx = 17,
Spi2Rx = 18,
Spi2Tx = 19,
Tim1Ch1 = 20,
Tim1Ch2 = 21,
Tim1Ch3 = 22,
Tim1Ch4 = 23,
Tim1TrigCom = 24,
Tim1Up = 25,
Tim2Ch1 = 26,
Tim2Ch2 = 27,
Tim2Ch3 = 28,
Tim2Ch4 = 29,
Tim2Trig = 30,
Tim2Up = 31,
Tim3Ch1 = 32,
Tim3Ch2 = 33,
Tim3Ch3 = 34,
Tim3Ch4 = 35,
Tim3Trig = 36,
Tim3Up = 37,
Tim6Up = 38,
Tim7Up = 39,
Tim15Ch1 = 40,
Tim15Ch2 = 41,
Tim15TrigCom = 42,
Tim15Up = 43,
Tim16Ch1 = 44,
Tim16Com = 45,
Tim16Up = 46,
Tim17Ch1 = 47,
Tim17Com = 48,
Tim17Up = 49,
Usart1Rx = 50,
Usart1Tx = 51,
Usart2Rx = 52,
Usart2Tx = 53,
Usart3Rx = 54,
Usart3Tx = 55,
Usart4Rx = 56,
Usart4Tx = 57,
Ucpd1Rx = 58,
Ucpd1Tx = 59,
Ucpd2Rx = 60,
Ucpd2Tx = 61,
I2c3Rx = 62,
I2c3Tx = 63,
Lpuart2Rx = 64,
Lpuart2Tx = 65,
Spi3Rx = 66,
Spi3Tx = 67,
Tim4Ch1 = 68,
Tim4Ch2 = 69,
Tim4Ch3 = 70,
Tim4Ch4 = 71,
Tim4Trig = 72,
Tim4Up = 73,
Usart5Rx = 74,
Usart5Tx = 75,
Usart6Rx = 76,
Usart6Tx = 77,
}
#[derive(Copy, Clone)]
#[repr(usize)]
#[cfg(feature = "wl")]
pub enum DmaInput {
Adc = 5,
DacOut1 = 6,
Spi1Rx = 7,
Spi1Tx = 8,
Spi2Rx = 9,
Spi2Tx = 10,
I2c1Rx = 11,
I2c1Tx = 12,
I2c2Rx = 13,
I2c2Tx = 14,
I2c3Rx = 15,
I2c3Tx = 16,
Usart1Rx = 17,
Usart1Tx = 18,
Usart2Rx = 19,
Usart2Tx = 20,
Lpuart1Rx = 21,
Lpuart1Tx = 22,
Tim1Ch1 = 23,
Tim1Ch2 = 24,
Tim1Ch3 = 25,
Tim1Ch4 = 26,
TimUp = 27,
Tim1Trig = 28,
Tim1Com = 29,
Tim2Ch1 = 30,
Tim2Ch2 = 31,
Tim2Ch3 = 32,
Tim2Ch4 = 33,
Tim2Up = 34,
Tim16Ch1 = 35,
Tim16Up = 36,
Tim17Ch1 = 37,
Tim17Up = 38,
AesIn = 39,
AesOut = 40,
SubghzSpiRx = 41,
SubghzSpiTx = 42,
}
#[derive(Copy, Clone)]
#[repr(usize)]
#[cfg(feature = "wb")]
pub enum DmaInput {
Adc1 = 5,
Spi1Rx = 6,
Spi1Tx = 7,
Spi2Rx = 8,
Spi2Tx = 9,
I2c1Rx = 10,
I2c1Tx = 11,
I2c3Rx = 12,
I2c3Tx = 13,
Usart1Rx = 14,
Usart1Tx = 15,
Lpuart1Rx = 16,
Lpuart1Tx = 17,
Sai1A = 18,
Sai1B = 19,
Quadspi = 20,
Tim1Ch1 = 21,
Tim1Ch2 = 22,
Tim1Ch3 = 23,
Tim1Ch4 = 24,
TimUp = 25,
Tim1Trig = 26,
Tim1Com = 27,
Tim2Ch1 = 28,
Tim2Ch2 = 29,
Tim2Ch3 = 30,
Tim2Ch4 = 31,
Tim2Up = 32,
Tim16Ch1 = 33,
Tim16Up = 34,
Tim17Ch1 = 35,
Tim17Up = 36,
Aes1In = 37,
Aes1Out = 38,
Aes2In = 39,
Aes2Out = 40,
}
#[derive(Copy, Clone)]
#[repr(usize)]
#[cfg(feature = "h7")]
pub enum DmaInput {
Adc1 = 9,
Adc2 = 10,
Tim1Ch1 = 11,
Tim1Ch2 = 12,
Tim1Ch3 = 13,
Tim1Ch4 = 14,
Tim1Up = 15,
Tim1Trig = 16,
Tim1Com = 17,
Tim2Ch1 = 18,
Tim2Ch2 = 19,
Tim2Ch3 = 20,
Tim2Ch4 = 21,
Tim2Up = 22,
Tim3Ch1 = 23,
Tim3Ch2 = 24,
Tim3Ch3 = 25,
Tim3Ch4 = 26,
Tim3Up = 27,
Tim3Trig = 28,
Tim4Ch1 = 29,
Tim4Ch2 = 30,
Tim4Ch3 = 31,
Tim4Up = 32,
I2c1Rx = 33,
I2c1Tx = 34,
I2c2Rx = 35,
I2c2Tx = 36,
Spi1Rx = 37,
Spi1Tx = 38,
Spi2Rx = 39,
Spi2Tx = 40,
Usart1Rx = 41,
Usart1Tx = 42,
Usart2Rx = 43,
Usart2Tx = 44,
Usart3Rx = 45,
Usart3Tx = 46,
Tim8Ch1 = 47,
Tim8Ch2 = 48,
Tim8Ch3 = 49,
Tim8Ch4 = 50,
Tim8Up = 51,
Tim8Trig = 52,
Tim8Com = 53,
Tim5Ch1 = 55,
Tim5Ch2 = 56,
Tim5Ch3 = 57,
Tim5Ch4 = 58,
Tim5Up = 59,
Tim5Trig = 60,
Spi3Rx = 61,
Spi3Tx = 62,
Uart4Rx = 63,
Uart4Tx = 64,
Uart5Rx = 65,
Uart5Tx = 66,
DacCh1 = 67,
DacCh2 = 68,
Tim6Up = 69,
Tim7Up = 70,
Uart6Rx = 71,
Uart6Tx = 72,
I2c3Rx = 73,
I2c3Tx = 74,
Dcmi = 75,
CrypIn = 76,
CrypOut = 77,
HashIn = 78,
Uart7Rx = 79,
Uart7Tx = 80,
Uart8Rx = 81,
Uart8Tx = 82,
Sai1A = 87,
Sai1B = 88,
Sai2A = 89,
Sai2B = 90,
Dfsdm1F0 = 101,
Dfsdm1F1 = 102,
Dfsdm1F2 = 103,
Dfsdm1F3 = 104,
Sai3A = 113,
Sai3B = 114,
Adc3 = 115,
Uart9Rx = 116,
Uart9Tx = 117,
Uart10Rx = 118,
Uart10Tx = 119,
}
#[derive(Copy, Clone)]
#[repr(usize)]
#[cfg(feature = "h7")]
pub enum DmaInput2 {
Lpuart1Rx = 9,
Lpuart1Tx = 10,
Spi6Rx = 11,
Spi6Tx = 12,
I2c4Rx = 13,
I3crTx = 14,
Sai4A = 15,
Sai4B = 16,
}
impl DmaInput {
#[cfg(any(feature = "f3", feature = "l4"))]
pub fn dma1_channel(&self) -> DmaChannel {
match self {
Self::Adc1 => DmaChannel::C1,
Self::Dac1Ch1 => DmaChannel::C3,
Self::Dac1Ch2 => DmaChannel::C4,
Self::Spi1Rx => DmaChannel::C2,
Self::Spi1Tx => DmaChannel::C3,
Self::Spi2Rx => DmaChannel::C4,
Self::Spi2Tx => DmaChannel::C5,
Self::I2c1Rx => DmaChannel::C7,
Self::I2c1Tx => DmaChannel::C6,
Self::I2c2Rx => DmaChannel::C5,
Self::I2c2Tx => DmaChannel::C4,
Self::I2c3Rx => DmaChannel::C3,
Self::Usart1Rx => DmaChannel::C5,
Self::Usart1Tx => DmaChannel::C4,
Self::Usart2Rx => DmaChannel::C6,
Self::Usart2Tx => DmaChannel::C7,
Self::Usart3Rx => DmaChannel::C3,
Self::Usart3Tx => DmaChannel::C2,
Self::Adc2 => DmaChannel::C2,
Self::Sai2A => DmaChannel::C6,
Self::Sai2B => DmaChannel::C7,
Self::Dfsdm1F0 => DmaChannel::C4,
Self::Dfsdm1F1 => DmaChannel::C5,
Self::Dfsdm1F2 => DmaChannel::C6,
Self::Dfsdm1F3 => DmaChannel::C7,
_ => unimplemented!(),
}
}
#[cfg(feature = "l4")]
pub fn dma1_channel_select(&self) -> u8 {
match self {
Self::Adc1 => 0b000,
Self::Dac1Ch1 => 0b0110,
Self::Dac1Ch2 => 0b0101,
Self::Spi1Rx => 0b001,
Self::Spi1Tx => 0b001,
Self::Spi2Rx => 0b001,
Self::Spi2Tx => 0b001,
Self::I2c1Rx => 0b011,
Self::I2c1Tx => 0b011,
Self::I2c2Rx => 0b011,
Self::I2c2Tx => 0b011,
Self::I2c3Rx => 0b011,
Self::Usart1Rx => 0b010,
Self::Usart1Tx => 0b010,
Self::Usart2Rx => 0b010,
Self::Usart2Tx => 0b010,
Self::Usart3Rx => 0b010,
Self::Usart3Tx => 0b010,
Self::Adc2 => 0b000,
Self::Dfsdm1F0 => 0b0000,
Self::Dfsdm1F1 => 0b0000,
Self::Dfsdm1F2 => 0b0000, Self::Dfsdm1F3 => 0b0000,
_ => unimplemented!(),
}
}
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum Priority {
Low = 0b00,
Medium = 0b01,
High = 0b10,
VeryHigh = 0b11,
}
#[derive(Copy, Clone)]
#[repr(u8)]
#[cfg(feature = "h7")]
pub enum DmaChannel {
#[cfg(feature = "h7")]
C0 = 0,
C1 = 1,
C2 = 2,
C3 = 3,
#[cfg(not(any(feature = "c011", feature = "c031")))]
C4 = 4,
#[cfg(not(any(feature = "c011", feature = "c031")))]
C5 = 5,
#[cfg(not(any(feature = "g0", feature = "c0")))]
C6 = 6,
#[cfg(not(any(feature = "g0", feature = "c0")))]
C7 = 7,
}
#[derive(Copy, Clone)]
#[repr(u8)]
#[cfg(not(feature = "h7"))]
pub enum DmaChannel {
C1 = 0,
C2 = 1,
C3 = 2,
#[cfg(not(any(feature = "c011", feature = "c031")))]
C4 = 3,
#[cfg(not(any(feature = "c011", feature = "c031")))]
C5 = 4,
#[cfg(not(any(feature = "g0", feature = "c0")))]
C6 = 5,
#[cfg(not(any(feature = "g0", feature = "c0")))]
C7 = 6,
#[cfg(any(feature = "l5", feature = "g4"))]
C8 = 7,
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum Direction {
ReadFromPeriph = 0,
ReadFromMem = 1,
MemToMem = 2,
}
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum Circular {
Disabled = 0,
Enabled = 1,
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum IncrMode {
Disabled = 0,
Enabled = 1,
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum DataSize {
S8 = 0b00, S16 = 0b01,
S32 = 0b10,
}
#[derive(Copy, Clone)]
pub enum DmaInterrupt {
TransferError,
HalfTransfer,
TransferComplete,
#[cfg(feature = "h7")]
DirectModeError,
#[cfg(feature = "h7")]
FifoError,
}
#[cfg(not(feature = "h7"))]
macro_rules! set_ccr {
($ccr:expr, $priority:expr, $direction:expr, $circular:expr, $periph_incr:expr, $mem_incr:expr, $periph_size:expr, $mem_size:expr) => {
let originally_enabled = $ccr().read().en().bit_is_set();
if originally_enabled {
$ccr().modify(|_, w| w.en().clear_bit());
bounded_loop!(
$ccr().read().en().bit_is_set(),
Error::RegisterUnchanged
);
}
if let Circular::Enabled = $circular {
$ccr().modify(|_, w| w.mem2mem().clear_bit());
}
$ccr().modify(|_, w| unsafe {
w.pl().bits($priority as u8);
w.dir().bit($direction as u8 != 0);
w.circ().bit($circular as u8 != 0);
w.pinc().bit($periph_incr as u8 != 0);
w.minc().bit($mem_incr as u8 != 0);
w.psize().bits($periph_size as u8);
w.msize().bits($mem_size as u8);
w.tcie().bit(true);
w.en().bit(true)
});
if originally_enabled {
$ccr().modify(|_, w| w.en().bit(true));
bounded_loop!($ccr().read().en().bit_is_clear(), Error::RegisterUnchanged);
}
};
}
#[cfg(not(feature = "h7"))]
macro_rules! enable_interrupt {
($ccr:expr, $interrupt_type:expr) => {
let originally_enabled = $ccr().read().en().bit_is_set();
if originally_enabled {
$ccr().modify(|_, w| w.en().clear_bit());
bounded_loop!($ccr().read().en().bit_is_set(), Error::RegisterUnchanged);
}
$ccr().modify(|_, w| match $interrupt_type {
DmaInterrupt::TransferError => w.teie().bit(true),
DmaInterrupt::HalfTransfer => w.htie().bit(true),
DmaInterrupt::TransferComplete => w.tcie().bit(true),
});
if originally_enabled {
$ccr().modify(|_, w| w.en().bit(true));
bounded_loop!($ccr().read().en().bit_is_clear(), Error::RegisterUnchanged);
}
};
}
#[cfg(not(feature = "h7"))]
macro_rules! disable_interrupt {
($ccr:expr, $interrupt_type:expr) => {
let originally_disabled = $ccr().read().en().bit_is_set();
if originally_disabled {
$ccr().modify(|_, w| w.en().clear_bit());
bounded_loop!($ccr().read().en().bit_is_set(), Error::RegisterUnchanged);
}
$ccr().modify(|_, w| match $interrupt_type {
DmaInterrupt::TransferError => w.teie().clear_bit(),
DmaInterrupt::HalfTransfer => w.htie().clear_bit(),
DmaInterrupt::TransferComplete => w.tcie().clear_bit(),
});
if originally_disabled {
$ccr().modify(|_, w| w.en().bit(true));
bounded_loop!($ccr().read().en().bit_is_clear(), Error::RegisterUnchanged);
}
};
}
#[derive(Clone)]
pub struct ChannelCfg {
pub priority: Priority,
pub circular: Circular,
pub periph_incr: IncrMode,
pub mem_incr: IncrMode,
}
impl Default for ChannelCfg {
fn default() -> Self {
Self {
priority: Priority::Medium,
circular: Circular::Disabled,
periph_incr: IncrMode::Disabled,
mem_incr: IncrMode::Enabled,
}
}
}
pub struct Dma<D> {
pub regs: D,
}
impl<D> Deref for Dma<D>
where
D: Deref<Target = dma1::RegisterBlock>,
{
type Target = dma1::RegisterBlock;
fn deref(&self) -> &Self::Target {
&self.regs
}
}
impl<D> Dma<D>
where
D: Deref<Target = dma1::RegisterBlock>,
{
pub fn new(regs: D) -> Self {
let rcc = unsafe { &(*RCC::ptr()) };
cfg_if! {
if #[cfg(feature = "f3")] {
rcc.ahbenr().modify(|_, w| w.dma1en().bit(true)); } else if #[cfg(any(feature = "g031", feature = "g041", feature = "g051", feature = "g061", feature = "g071", feature = "g081"))] {
rcc_en_reset!(ahb1, dma, rcc);
} else {
rcc_en_reset!(ahb1, dma1, rcc);
}
}
Self { regs }
}
pub fn cfg_channel(
&mut self,
channel: DmaChannel,
periph_addr: u32,
mem_addr: u32,
num_data: u32,
direction: Direction,
periph_size: DataSize,
mem_size: DataSize,
cfg: ChannelCfg,
) -> Result<()> {
cfg_channel(
&mut self.regs,
channel,
periph_addr,
mem_addr,
num_data,
direction,
periph_size,
mem_size,
cfg,
)
}
#[cfg(feature = "l4")]
pub(crate) fn channel_select(&mut self, input: DmaInput) {
channel_select(&mut self.regs, input);
}
pub fn stop(&mut self, channel: DmaChannel) -> Result<()> {
stop_internal(&mut self.regs, channel)
}
pub fn clear_interrupt(&mut self, channel: DmaChannel, interrupt: DmaInterrupt) -> Result<()> {
clear_interrupt_internal(&mut self.regs, channel, interrupt)
}
#[cfg(not(any(feature = "h7")))]
pub fn transfer_is_complete(&mut self, channel: DmaChannel) -> bool {
let isr_val = self.regs.isr().read();
match channel {
DmaChannel::C1 => isr_val.tcif1().bit_is_set(),
DmaChannel::C2 => isr_val.tcif2().bit_is_set(),
DmaChannel::C3 => isr_val.tcif3().bit_is_set(),
#[cfg(not(any(feature = "c011", feature = "c031")))]
DmaChannel::C4 => isr_val.tcif4().bit_is_set(),
#[cfg(not(any(feature = "c011", feature = "c031")))]
DmaChannel::C5 => isr_val.tcif5().bit_is_set(),
#[cfg(not(any(feature = "g0", feature = "c0")))]
DmaChannel::C6 => isr_val.tcif6().bit_is_set(),
#[cfg(not(any(feature = "g0", feature = "c0")))]
DmaChannel::C7 => isr_val.tcif7().bit_is_set(),
#[cfg(any(feature = "l5", feature = "g4"))]
DmaChannel::C8 => isr_val.tcif8().bit_is_set(),
}
}
#[cfg(feature = "h7")]
pub fn transfer_is_complete(&mut self, channel: DmaChannel) -> bool {
match channel {
DmaChannel::C0 => self.regs.lisr().read().tcif0().bit_is_set(),
DmaChannel::C1 => self.regs.lisr().read().tcif1().bit_is_set(),
DmaChannel::C2 => self.regs.lisr().read().tcif2().bit_is_set(),
DmaChannel::C3 => self.regs.lisr().read().tcif3().bit_is_set(),
DmaChannel::C4 => self.regs.hisr().read().tcif4().bit_is_set(),
DmaChannel::C5 => self.regs.hisr().read().tcif5().bit_is_set(),
DmaChannel::C6 => self.regs.hisr().read().tcif6().bit_is_set(),
DmaChannel::C7 => self.regs.hisr().read().tcif7().bit_is_set(),
}
}
pub fn enable_interrupt(&mut self, channel: DmaChannel, interrupt: DmaInterrupt) -> Result<()> {
enable_interrupt_internal(&mut self.regs, channel, interrupt)
}
pub fn disable_interrupt(
&mut self,
channel: DmaChannel,
interrupt: DmaInterrupt,
) -> Result<()> {
#[cfg(feature = "h7")]
let cr = &self.regs.st(channel as usize).cr();
#[cfg(not(feature = "h7"))]
let cr = &self.regs.ch(channel as usize).cr();
let originally_enabled = cr.read().en().bit_is_set();
if originally_enabled {
cr.modify(|_, w| w.en().clear_bit());
bounded_loop!(cr.read().en().bit_is_set(), Error::RegisterUnchanged);
}
match interrupt {
DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().clear_bit()),
DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().clear_bit()),
DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().clear_bit()),
#[cfg(feature = "h7")]
DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().clear_bit()),
#[cfg(feature = "h7")]
DmaInterrupt::FifoError => self
.regs
.st(channel as usize)
.fcr()
.modify(|_, w| w.feie().clear_bit()),
};
if originally_enabled {
cr.modify(|_, w| w.en().bit(true));
bounded_loop!(cr.read().en().bit_is_clear(), Error::RegisterUnchanged);
}
Ok(())
}
}
pub fn cfg_channel<D>(
regs: &mut D,
channel: DmaChannel,
periph_addr: u32,
mem_addr: u32,
num_data: u32,
direction: Direction,
periph_size: DataSize,
mem_size: DataSize,
cfg: ChannelCfg,
) -> Result<()>
where
D: Deref<Target = dma1::RegisterBlock>,
{
cfg_if! {
if #[cfg(feature = "h7")] {
let mut channel = regs.st(channel as usize);
} else {
let mut channel = regs.ch(channel as usize);
}
}
let originally_enabled = channel.cr().read().en().bit_is_set();
channel.cr().modify(|_, w| w.en().clear_bit());
bounded_loop!(
channel.cr().read().en().bit_is_set(),
Error::RegisterUnchanged
);
channel.par().write(|w| unsafe { w.bits(periph_addr) });
atomic::compiler_fence(Ordering::SeqCst);
#[cfg(any(feature = "h7", feature = "l5"))]
channel.m0ar().write(|w| unsafe { w.bits(mem_addr) });
#[cfg(not(any(feature = "h7", feature = "l5")))]
channel.mar().write(|w| unsafe { w.bits(mem_addr) });
channel.ndtr().write(|w| unsafe { w.bits(num_data) });
if originally_enabled {
channel.cr().modify(|_, w| w.en().clear_bit());
bounded_loop!(
channel.cr().read().en().bit_is_set(),
Error::RegisterUnchanged
);
}
channel.cr().modify(|_, w| unsafe {
w.pl().bits(cfg.priority as u8);
#[cfg(feature = "h7")]
w.dir().bits(direction as u8);
#[cfg(not(feature = "h7"))]
w.dir().bit((direction as u8) != 0);
w.circ().bit(cfg.circular as u8 != 0);
w.pinc().bit(cfg.periph_incr as u8 != 0);
w.minc().bit(cfg.mem_incr as u8 != 0);
w.psize().bits(periph_size as u8);
w.msize().bits(mem_size as u8);
w.tcie().bit(true);
w.en().bit(true)
});
if originally_enabled {
channel.cr().modify(|_, w| w.en().set_bit());
bounded_loop!(
channel.cr().read().en().bit_is_clear(),
Error::RegisterUnchanged
);
}
Ok(())
}
fn stop_internal<D>(regs: &mut D, channel: DmaChannel) -> Result<()>
where
D: Deref<Target = dma1::RegisterBlock>,
{
#[cfg(feature = "h7")]
let cr = ®s.st(channel as usize).cr();
#[cfg(not(feature = "h7"))]
let cr = ®s.ch(channel as usize).cr();
cr.modify(|_, w| w.en().clear_bit());
bounded_loop!(cr.read().en().bit_is_set(), Error::RegisterUnchanged);
Ok(())
}
pub fn stop(periph: DmaPeriph, channel: DmaChannel) -> Result<()> {
match periph {
DmaPeriph::Dma1 => {
let mut regs = unsafe { &(*DMA1::ptr()) };
stop_internal(&mut regs, channel)
}
#[cfg(dma2)]
DmaPeriph::Dma2 => {
let mut regs = unsafe { &(*DMA2::ptr()) };
stop_internal(&mut regs, channel)
}
}
}
fn clear_interrupt_internal<D>(
regs: &mut D,
channel: DmaChannel,
interrupt: DmaInterrupt,
) -> Result<()>
where
D: Deref<Target = dma1::RegisterBlock>,
{
cfg_if! {
if #[cfg(any(feature = "g4", feature = "wl"))] {
regs.ifcr().write(|w| match channel {
DmaChannel::C1 => match interrupt {
DmaInterrupt::TransferError => w.cteif1().bit(true),
DmaInterrupt::HalfTransfer => w.chtif1().bit(true),
DmaInterrupt::TransferComplete => w.ctcif1().bit(true),
}
DmaChannel::C2 => match interrupt {
DmaInterrupt::TransferError => w.cteif2().bit(true),
DmaInterrupt::HalfTransfer => w.chtif2().bit(true),
DmaInterrupt::TransferComplete => w.ctcif2().bit(true),
}
DmaChannel::C3 => match interrupt {
DmaInterrupt::TransferError => w.cteif3().bit(true),
DmaInterrupt::HalfTransfer => w.chtif3().bit(true),
DmaInterrupt::TransferComplete => w.ctcif3().bit(true),
}
DmaChannel::C4 => match interrupt {
DmaInterrupt::TransferError => w.cteif4().bit(true),
DmaInterrupt::HalfTransfer => w.chtif4().bit(true),
DmaInterrupt::TransferComplete => w.ctcif4().bit(true),
}
DmaChannel::C5 => match interrupt {
DmaInterrupt::TransferError => w.cteif5().bit(true),
DmaInterrupt::HalfTransfer => w.chtif5().bit(true),
DmaInterrupt::TransferComplete => w.ctcif5().bit(true),
}
DmaChannel::C6 => match interrupt {
DmaInterrupt::TransferError => w.cteif6().bit(true),
DmaInterrupt::HalfTransfer => w.chtif6().bit(true),
DmaInterrupt::TransferComplete => w.ctcif6().bit(true),
}
DmaChannel::C7 => match interrupt {
DmaInterrupt::TransferError => w.cteif7().bit(true),
DmaInterrupt::HalfTransfer => w.chtif7().bit(true),
DmaInterrupt::TransferComplete => w.ctcif7().bit(true),
}
#[cfg(not(feature = "wl"))]
DmaChannel::C8 => match interrupt {
DmaInterrupt::TransferError => w.cteif8().bit(true),
DmaInterrupt::HalfTransfer => w.chtif8().bit(true),
DmaInterrupt::TransferComplete => w.ctcif8().bit(true),
}
});
} else if #[cfg(feature = "h7")] {
match channel {
DmaChannel::C0 => match interrupt {
DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif0().bit(true)),
DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif0().bit(true)),
DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif0().bit(true)),
DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif0().bit(true)),
DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif0().bit(true)),
}
DmaChannel::C1 => match interrupt {
DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif1().bit(true)),
DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif1().bit(true)),
DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif1().bit(true)),
DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif1().bit(true)),
DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif1().bit(true)),
}
DmaChannel::C2 => match interrupt {
DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif2().bit(true)),
DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif2().bit(true)),
DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif2().bit(true)),
DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif2().bit(true)),
DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif2().bit(true)),
}
DmaChannel::C3 => match interrupt {
DmaInterrupt::TransferError => regs.lifcr().write(|w| w.cteif3().bit(true)),
DmaInterrupt::HalfTransfer => regs.lifcr().write(|w| w.chtif3().bit(true)),
DmaInterrupt::TransferComplete => regs.lifcr().write(|w| w.ctcif3().bit(true)),
DmaInterrupt::DirectModeError => regs.lifcr().write(|w| w.cdmeif3().bit(true)),
DmaInterrupt::FifoError => regs.lifcr().write(|w| w.cfeif3().bit(true)),
}
DmaChannel::C4 => match interrupt {
DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif4().bit(true)),
DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif4().bit(true)),
DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif4().bit(true)),
DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif4().bit(true)),
DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif4().bit(true)),
}
DmaChannel::C5 => match interrupt {
DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif5().bit(true)),
DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif5().bit(true)),
DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif5().bit(true)),
DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif5().bit(true)),
DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif5().bit(true)),
}
DmaChannel::C6 => match interrupt {
DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif6().bit(true)),
DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif6().bit(true)),
DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif6().bit(true)),
DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif6().bit(true)),
DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif6().bit(true)),
}
DmaChannel::C7 => match interrupt {
DmaInterrupt::TransferError => regs.hifcr().write(|w| w.cteif7().bit(true)),
DmaInterrupt::HalfTransfer => regs.hifcr().write(|w| w.chtif7().bit(true)),
DmaInterrupt::TransferComplete => regs.hifcr().write(|w| w.ctcif7().bit(true)),
DmaInterrupt::DirectModeError => regs.hifcr().write(|w| w.cdmeif7().bit(true)),
DmaInterrupt::FifoError => regs.hifcr().write(|w| w.cfeif7().bit(true)),
}
};
} else if #[cfg(not(feature = "g0"))] {
regs.ifcr().write(|w| match channel {
DmaChannel::C1 => match interrupt {
DmaInterrupt::TransferError => w.cteif1().bit(true),
DmaInterrupt::HalfTransfer => w.chtif1().bit(true),
DmaInterrupt::TransferComplete => w.ctcif1().bit(true),
}
DmaChannel::C2 => match interrupt {
DmaInterrupt::TransferError => w.cteif2().bit(true),
DmaInterrupt::HalfTransfer => w.chtif2().bit(true),
DmaInterrupt::TransferComplete => w.ctcif2().bit(true),
}
DmaChannel::C3 => match interrupt {
DmaInterrupt::TransferError => w.cteif3().bit(true),
DmaInterrupt::HalfTransfer => w.chtif3().bit(true),
DmaInterrupt::TransferComplete => w.ctcif3().bit(true),
}
#[cfg(not(any(feature = "c011", feature = "c031")))]
DmaChannel::C4 => match interrupt {
DmaInterrupt::TransferError => w.cteif4().bit(true),
DmaInterrupt::HalfTransfer => w.chtif4().bit(true),
DmaInterrupt::TransferComplete => w.ctcif4().bit(true),
}
#[cfg(not(any(feature = "c011", feature = "c031")))]
DmaChannel::C5 => match interrupt {
DmaInterrupt::TransferError => w.cteif5().bit(true),
DmaInterrupt::HalfTransfer => w.chtif5().bit(true),
DmaInterrupt::TransferComplete => w.ctcif5().bit(true),
}
#[cfg(not(any(feature = "g0", feature = "c0")))]
DmaChannel::C6 => match interrupt {
DmaInterrupt::TransferError => w.cteif6().bit(true),
DmaInterrupt::HalfTransfer => w.chtif6().bit(true),
DmaInterrupt::TransferComplete => w.ctcif6().bit(true),
}
#[cfg(not(any(feature = "g0", feature = "c0")))]
DmaChannel::C7 => match interrupt {
DmaInterrupt::TransferError => w.cteif7().bit(true),
DmaInterrupt::HalfTransfer => w.chtif7().bit(true),
DmaInterrupt::TransferComplete => w.ctcif7().bit(true),
}
#[cfg(any(feature = "l5", feature = "g4"))]
DmaChannel::C8 => match interrupt {
DmaInterrupt::TransferError => w.cteif8().bit(true),
DmaInterrupt::HalfTransfer => w.chtif8().bit(true),
DmaInterrupt::TransferComplete => w.ctcif8().bit(true),
}
});
}
}
Ok(())
}
fn enable_interrupt_internal<D>(
regs: &mut D,
channel: DmaChannel,
interrupt: DmaInterrupt,
) -> Result<()>
where
D: Deref<Target = dma1::RegisterBlock>,
{
#[cfg(feature = "h7")]
let cr = ®s.st(channel as usize).cr();
#[cfg(not(feature = "h7"))]
let cr = ®s.ch(channel as usize).cr();
match interrupt {
DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().bit(true)),
DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().bit(true)),
DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().bit(true)),
#[cfg(feature = "h7")]
DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().bit(true)),
#[cfg(feature = "h7")]
DmaInterrupt::FifoError => regs
.st(channel as usize)
.fcr()
.modify(|_, w| w.feie().bit(true)),
};
Ok(())
}
fn disable_interrupt_internal<D>(
regs: &mut D,
channel: DmaChannel,
interrupt: DmaInterrupt,
) -> Result<()>
where
D: Deref<Target = dma1::RegisterBlock>,
{
#[cfg(feature = "h7")]
let cr = ®s.st(channel as usize).cr();
#[cfg(not(feature = "h7"))]
let cr = ®s.ch(channel as usize).cr();
match interrupt {
DmaInterrupt::TransferError => cr.modify(|_, w| w.teie().clear_bit()),
DmaInterrupt::HalfTransfer => cr.modify(|_, w| w.htie().clear_bit()),
DmaInterrupt::TransferComplete => cr.modify(|_, w| w.tcie().clear_bit()),
#[cfg(feature = "h7")]
DmaInterrupt::DirectModeError => cr.modify(|_, w| w.dmeie().clear_bit()),
#[cfg(feature = "h7")]
DmaInterrupt::FifoError => regs
.st(channel as usize)
.fcr()
.modify(|_, w| w.feie().clear_bit()),
};
Ok(())
}
pub fn enable_interrupt(
periph: DmaPeriph,
channel: DmaChannel,
interrupt: DmaInterrupt,
) -> Result<()> {
match periph {
DmaPeriph::Dma1 => {
let mut regs = unsafe { &(*DMA1::ptr()) };
enable_interrupt_internal(&mut regs, channel, interrupt)
}
#[cfg(dma2)]
DmaPeriph::Dma2 => {
let mut regs = unsafe { &(*DMA2::ptr()) };
enable_interrupt_internal(&mut regs, channel, interrupt)
}
}
}
pub fn disable_interrupt(
periph: DmaPeriph,
channel: DmaChannel,
interrupt: DmaInterrupt,
) -> Result<()> {
match periph {
DmaPeriph::Dma1 => {
let mut regs = unsafe { &(*DMA1::ptr()) };
disable_interrupt_internal(&mut regs, channel, interrupt)
}
#[cfg(dma2)]
DmaPeriph::Dma2 => {
let mut regs = unsafe { &(*DMA2::ptr()) };
disable_interrupt_internal(&mut regs, channel, interrupt)
}
}
}
pub fn clear_interrupt(
periph: DmaPeriph,
channel: DmaChannel,
interrupt: DmaInterrupt,
) -> Result<()> {
match periph {
DmaPeriph::Dma1 => {
let mut regs = unsafe { &(*DMA1::ptr()) };
clear_interrupt_internal(&mut regs, channel, interrupt)
}
#[cfg(dma2)]
DmaPeriph::Dma2 => {
let mut regs = unsafe { &(*DMA2::ptr()) };
clear_interrupt_internal(&mut regs, channel, interrupt)
}
}
}
#[cfg(any(
feature = "l5",
feature = "g0",
feature = "g4",
feature = "h7",
feature = "wb",
feature = "wl",
))]
pub fn mux(periph: DmaPeriph, channel: DmaChannel, input: DmaInput) {
unsafe {
let mux = unsafe { &(*DMAMUX::ptr()) };
#[cfg(feature = "g4")]
let rcc = unsafe { &(*RCC::ptr()) };
#[cfg(feature = "g4")]
rcc.ahb1enr().modify(|_, w| w.dmamux1en().bit(true));
#[cfg(feature = "g431")]
let dma2_offset = 8;
#[cfg(not(feature = "g431"))]
let dma2_offset = 8;
match periph {
DmaPeriph::Dma1 => {
mux.ccr(channel as usize)
.modify(|_, w| w.dmareq_id().bits(input as u8));
}
#[cfg(dma2)]
DmaPeriph::Dma2 => {
mux.ccr(channel as usize + dma2_offset)
.modify(|_, w| w.dmareq_id().bits(input as u8));
}
}
}
}
#[cfg(feature = "h7")]
pub fn mux2(periph: DmaPeriph, channel: DmaChannel, input: DmaInput2, mux: &mut DMAMUX2) {
mux.ccr(channel as usize)
.modify(|_, w| unsafe { w.dmareq_id().bits(input as u8) });
}
#[cfg(any(feature = "g4", feature = "wb"))]
pub fn enable_mux1() {
let rcc = unsafe { &(*RCC::ptr()) };
cfg_if! {
if #[cfg(feature = "g4")] {
rcc.ahb1enr().modify(|_, w| w.dmamux1en().bit(true));
rcc.ahb1rstr().modify(|_, w| w.dmamux1rst().bit(true));
rcc.ahb1rstr().modify(|_, w| w.dmamux1rst().clear_bit());
} else {
rcc_en_reset!(ahb1, dmamux, rcc);
}
}
}
#[cfg(feature = "l4")] pub(crate) fn channel_select<D>(regs: &mut D, input: DmaInput)
where
D: Deref<Target = dma1::RegisterBlock>,
{
let val = input.dma1_channel_select();
unsafe {
regs.cselr().modify(|_, w| match input.dma1_channel() {
DmaChannel::C1 => w.c1s().bits(val),
DmaChannel::C2 => w.c2s().bits(val),
DmaChannel::C3 => w.c3s().bits(val),
DmaChannel::C4 => w.c4s().bits(val),
DmaChannel::C5 => w.c5s().bits(val),
DmaChannel::C6 => w.c6s().bits(val),
DmaChannel::C7 => w.c7s().bits(val),
});
}
}
macro_rules! make_chan_struct {
($periph: expr, $ch:expr) => {
paste::paste! {
pub struct [<Dma $periph Ch $ch>] {
}
impl [<Dma $periph Ch $ch>] {
pub fn new() -> Self {
let rcc = unsafe { &(*RCC::ptr()) };
cfg_if! {
if #[cfg(feature = "f3")] {
rcc.ahbenr().modify(|_, w| w.dma1en().bit(true)); } else if #[cfg(feature = "g0")] {
rcc_en_reset!(ahb1, dma, rcc);
} else {
rcc_en_reset!(ahb1, [<dma $periph>], rcc);
}
}
Self { }
}
fn regs(&self) -> &[<dma $periph>]::RegisterBlock {
unsafe { &(*[<DMA $periph>]::ptr())}
}
pub fn cfg_channel(
&mut self,
periph_addr: u32,
mem_addr: u32,
num_data: u32,
direction: Direction,
periph_size: DataSize,
mem_size: DataSize,
cfg: ChannelCfg,
) -> Result<()> {
cfg_channel(
&mut self.regs(),
DmaChannel::[<C $ch>],
periph_addr,
mem_addr,
num_data,
direction,
periph_size,
mem_size,
cfg,
)
}
pub fn stop(&mut self) -> Result<()> {
#[cfg(feature = "h7")]
let ccr = self.regs().st($ch).cr();
#[cfg(not(feature = "h7"))]
let ccr = self.regs().ch($ch).cr();
ccr.modify(|_, w| w.en().clear_bit());
bounded_loop!(ccr.read().en().bit_is_set(), Error::RegisterUnchanged);
Ok(())
}
pub fn enable_interrupt(&mut self, interrupt: DmaInterrupt) {
enable_interrupt_internal(&mut self.regs(), DmaChannel::[<C $ch>], interrupt).unwrap()
}
pub fn clear_interrupt(&mut self, interrupt: DmaInterrupt) {
clear_interrupt_internal(&mut self.regs(), DmaChannel::[<C $ch>], interrupt).unwrap()
}
}
}
};
}
cfg_if! {
if #[cfg(not(any(feature = "f3", feature = "g0")))] {
#[cfg(feature = "h7")]
make_chan_struct!(1, 0);
make_chan_struct!(1, 1);
make_chan_struct!(1, 2);
make_chan_struct!(1, 3);
#[cfg(not(any(feature = "c011", feature = "c031")))]
make_chan_struct!(1, 4);
#[cfg(not(any(feature = "c011", feature = "c031")))]
make_chan_struct!(1, 5);
#[cfg(not(any(feature = "g0", feature = "c0")))]
make_chan_struct!(1, 6);
#[cfg(not(any(feature = "g0", feature = "c0")))]
make_chan_struct!(1, 7);
#[cfg(any(feature = "l5", feature = "g4"))]
make_chan_struct!(1, 8);
#[cfg(feature = "h7")]
make_chan_struct!(2, 0);
#[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
make_chan_struct!(2, 1);
#[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
make_chan_struct!(2, 2);
#[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
make_chan_struct!(2, 3);
#[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
make_chan_struct!(2, 4);
#[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
make_chan_struct!(2, 5);
#[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
make_chan_struct!(2, 6);
#[cfg(not(any(feature = "g0", feature = "wb", feature = "c0")))]
make_chan_struct!(2, 7);
#[cfg(any(feature = "l5", feature = "g4"))]
make_chan_struct!(2, 8);
}
}