use core::marker::PhantomData;
use crate::{
dma::*,
handler,
interrupt::Priority,
peripherals::{DMA, Interrupt, pac},
};
#[cfg_attr(dma_gdma_version = "1", path = "ahb_v1.rs")]
#[cfg_attr(dma_gdma_version = "2", path = "ahb_v2.rs")]
mod implementation;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AnyGdmaChannel<'d> {
channel: u8,
_lifetime: PhantomData<&'d mut ()>,
}
impl AnyGdmaChannel<'_> {
#[cfg_attr(any(esp32c2, esp32c61), expect(unused))]
pub(crate) unsafe fn clone_unchecked(&self) -> Self {
Self {
channel: self.channel,
_lifetime: PhantomData,
}
}
}
impl crate::private::Sealed for AnyGdmaChannel<'_> {}
impl<'d> DmaChannel for AnyGdmaChannel<'d> {
type Rx = AnyGdmaRxChannel<'d>;
type Tx = AnyGdmaTxChannel<'d>;
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
(
AnyGdmaRxChannel {
channel: self.channel,
_lifetime: PhantomData,
},
AnyGdmaTxChannel {
channel: self.channel,
_lifetime: PhantomData,
},
)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AnyGdmaRxChannel<'d> {
channel: u8,
_lifetime: PhantomData<&'d mut ()>,
}
impl<'d> DmaChannelConvert<AnyGdmaRxChannel<'d>> for AnyGdmaRxChannel<'d> {
fn degrade(self) -> AnyGdmaRxChannel<'d> {
self
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AnyGdmaTxChannel<'d> {
channel: u8,
_lifetime: PhantomData<&'d mut ()>,
}
impl<'d> DmaChannelConvert<AnyGdmaTxChannel<'d>> for AnyGdmaTxChannel<'d> {
fn degrade(self) -> AnyGdmaTxChannel<'d> {
self
}
}
use crate::asynch::AtomicWaker;
static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
static RX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3))] {
use portable_atomic::AtomicBool;
static TX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
static RX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
}
}
impl crate::private::Sealed for AnyGdmaTxChannel<'_> {}
impl DmaTxChannel for AnyGdmaTxChannel<'_> {}
impl crate::private::Sealed for AnyGdmaRxChannel<'_> {}
impl DmaRxChannel for AnyGdmaRxChannel<'_> {}
impl<CH: DmaChannel, Dm: DriverMode> Channel<Dm, CH> {
pub fn runtime_ensure_compatible<P: DmaEligible>(&self, _peripheral: &P) {
}
}
macro_rules! impl_channel {
($num:literal, $interrupt_in:ident $(, $interrupt_out:ident)? ) => {
paste::paste! {
use $crate::peripherals::[<DMA_CH $num>];
impl [<DMA_CH $num>]<'_> {
fn handler_in() -> Option<InterruptHandler> {
$crate::if_set! {
$({
#[handler(priority = Priority::max())]
fn interrupt_handler_in() {
$crate::ignore!($interrupt_out);
super::asynch::handle_in_interrupt::<[< DMA_CH $num >]<'static>>();
}
Some(interrupt_handler_in)
})?,
{
#[handler(priority = Priority::max())]
fn interrupt_handler() {
super::asynch::handle_in_interrupt::<[< DMA_CH $num >]<'static>>();
super::asynch::handle_out_interrupt::<[< DMA_CH $num >]<'static>>();
}
Some(interrupt_handler)
}
}
}
fn isr_in() -> Option<Interrupt> {
Some(Interrupt::$interrupt_in)
}
fn handler_out() -> Option<InterruptHandler> {
$crate::if_set! {
$({
#[handler(priority = Priority::max())]
fn interrupt_handler_out() {
$crate::ignore!($interrupt_out);
super::asynch::handle_out_interrupt::<[< DMA_CH $num >]<'static>>();
}
Some(interrupt_handler_out)
})?,
None
}
}
fn isr_out() -> Option<Interrupt> {
$crate::if_set! { $(Some(Interrupt::$interrupt_out))?, None }
}
}
impl<'d> DmaChannel for [<DMA_CH $num>]<'d> {
type Rx = AnyGdmaRxChannel<'d>;
type Tx = AnyGdmaTxChannel<'d>;
unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
(
AnyGdmaRxChannel {
channel: $num,
_lifetime: core::marker::PhantomData,
},
AnyGdmaTxChannel {
channel: $num,
_lifetime: core::marker::PhantomData,
},
)
}
}
impl<'d> DmaChannelConvert<AnyGdmaChannel<'d>> for [<DMA_CH $num>]<'d> {
fn degrade(self) -> AnyGdmaChannel<'d> {
AnyGdmaChannel {
channel: $num,
_lifetime: core::marker::PhantomData,
}
}
}
impl<'d> DmaChannelConvert<AnyGdmaRxChannel<'d>> for [<DMA_CH $num>]<'d> {
fn degrade(self) -> AnyGdmaRxChannel<'d> {
AnyGdmaRxChannel {
channel: $num,
_lifetime: core::marker::PhantomData,
}
}
}
impl<'d> DmaChannelConvert<AnyGdmaTxChannel<'d>> for [<DMA_CH $num>]<'d> {
fn degrade(self) -> AnyGdmaTxChannel<'d> {
AnyGdmaTxChannel {
channel: $num,
_lifetime: core::marker::PhantomData,
}
}
}
impl DmaChannelExt for [<DMA_CH $num>]<'_> {
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
AnyGdmaRxChannel {
channel: $num,
_lifetime: core::marker::PhantomData,
}
}
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
AnyGdmaTxChannel {
channel: $num,
_lifetime: core::marker::PhantomData,
}
}
}
}
};
}
const CHANNEL_COUNT: usize = cfg!(soc_has_dma_ch0) as usize
+ cfg!(soc_has_dma_ch1) as usize
+ cfg!(soc_has_dma_ch2) as usize
+ cfg!(soc_has_dma_ch3) as usize
+ cfg!(soc_has_dma_ch4) as usize;
cfg_if::cfg_if! {
if #[cfg(dma_separate_in_out_interrupts)] {
#[cfg(soc_has_dma_ch0)]
impl_channel!(0, DMA_IN_CH0, DMA_OUT_CH0);
#[cfg(soc_has_dma_ch1)]
impl_channel!(1, DMA_IN_CH1, DMA_OUT_CH1);
#[cfg(soc_has_dma_ch2)]
impl_channel!(2, DMA_IN_CH2, DMA_OUT_CH2);
#[cfg(soc_has_dma_ch3)]
impl_channel!(3, DMA_IN_CH3, DMA_OUT_CH3);
#[cfg(soc_has_dma_ch4)]
impl_channel!(4, DMA_IN_CH4, DMA_OUT_CH4);
} else {
#[cfg(soc_has_dma_ch0)]
impl_channel!(0, DMA_CH0);
#[cfg(soc_has_dma_ch1)]
impl_channel!(1, DMA_CH1);
#[cfg(soc_has_dma_ch2)]
impl_channel!(2, DMA_CH2);
#[cfg(soc_has_dma_ch3)]
impl_channel!(3, DMA_CH3);
#[cfg(soc_has_dma_ch4)]
impl_channel!(4, DMA_CH4);
}
}
for_each_peripheral! {
(dma_eligible $(( $peri:ident, $name:ident, $id:literal )),*) => {
crate::dma::impl_dma_eligible! {
AnyGdmaChannel {
$($peri => $name,)*
}
}
};
}
pub(super) fn init_dma_racey() {
DMA::regs()
.misc_conf()
.modify(|_, w| w.ahbm_rst_inter().set_bit());
DMA::regs()
.misc_conf()
.modify(|_, w| w.ahbm_rst_inter().clear_bit());
DMA::regs().misc_conf().modify(|_, w| w.clk_en().set_bit());
implementation::setup();
}