Split DMA RegisterAccess trait into RX/TX (#2249)

* Reduce macro usage in PDMA

* Split DMA RegisterAccess trait into RX/TX

* Move set_isr to Ext trait

---------

Co-authored-by: Dominic Fischer <git@dominicfischer.me>
This commit is contained in:
Dominic Fischer 2024-09-30 14:32:18 +01:00 committed by GitHub
parent 487de0ff22
commit f1bedbe3dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 1192 additions and 1070 deletions

View File

@ -21,11 +21,17 @@ use crate::{
};
#[non_exhaustive]
pub struct Channel<const N: u8> {}
#[doc(hidden)]
pub struct ChannelTxImpl<const N: u8> {}
impl<const N: u8> crate::private::Sealed for Channel<N> {}
use embassy_sync::waitqueue::AtomicWaker;
impl<const N: u8> Channel<N> {
static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
static RX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
impl<const N: u8> crate::private::Sealed for ChannelTxImpl<N> {}
impl<const N: u8> ChannelTxImpl<N> {
#[inline(always)]
fn ch() -> &'static crate::peripherals::dma::ch::CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
@ -34,74 +40,77 @@ impl<const N: u8> Channel<N> {
#[cfg(any(esp32c2, esp32c3))]
#[inline(always)]
fn in_int() -> &'static crate::peripherals::dma::int_ch::INT_CH {
fn int() -> &'static crate::peripherals::dma::int_ch::INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.int_ch(N as usize)
}
#[inline(always)]
#[cfg(any(esp32c6, esp32h2))]
fn in_int() -> &'static crate::peripherals::dma::in_int_ch::IN_INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.in_int_ch(N as usize)
}
#[cfg(esp32s3)]
#[inline(always)]
fn in_int() -> &'static crate::peripherals::dma::ch::in_int::IN_INT {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(N as usize).in_int()
}
#[cfg(any(esp32c2, esp32c3))]
#[inline(always)]
fn out_int() -> &'static crate::peripherals::dma::int_ch::INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.int_ch(N as usize)
}
#[inline(always)]
#[cfg(any(esp32c6, esp32h2))]
fn out_int() -> &'static crate::peripherals::dma::out_int_ch::OUT_INT_CH {
fn int() -> &'static crate::peripherals::dma::out_int_ch::OUT_INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.out_int_ch(N as usize)
}
#[cfg(esp32s3)]
#[inline(always)]
fn out_int() -> &'static crate::peripherals::dma::ch::out_int::OUT_INT {
fn int() -> &'static crate::peripherals::dma::ch::out_int::OUT_INT {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(N as usize).out_int()
}
}
impl<const N: u8> RegisterAccess for Channel<N> {
#[cfg(gdma)]
fn set_mem2mem_mode(value: bool) {
Self::ch()
.in_conf0()
.modify(|_, w| w.mem_trans_en().bit(value));
impl<const N: u8> RegisterAccess for ChannelTxImpl<N> {
fn reset(&self) {
let conf0 = Self::ch().out_conf0();
conf0.modify(|_, w| w.out_rst().set_bit());
conf0.modify(|_, w| w.out_rst().clear_bit());
}
#[cfg(esp32s3)]
fn set_out_ext_mem_block_size(size: DmaExtMemBKSize) {
Self::ch()
.out_conf1()
.modify(|_, w| unsafe { w.out_ext_mem_bk_size().bits(size as u8) });
}
fn set_out_burstmode(burst_mode: bool) {
fn set_burst_mode(&self, burst_mode: bool) {
Self::ch().out_conf0().modify(|_, w| {
w.out_data_burst_en().bit(burst_mode);
w.outdscr_burst_en().bit(burst_mode)
});
}
fn set_out_priority(priority: DmaPriority) {
fn set_priority(&self, priority: DmaPriority) {
Self::ch()
.out_pri()
.write(|w| unsafe { w.tx_pri().bits(priority as u8) });
}
fn clear_out_interrupts() {
fn set_peripheral(&self, peripheral: u8) {
Self::ch()
.out_peri_sel()
.modify(|_, w| unsafe { w.peri_out_sel().bits(peripheral) });
}
fn set_link_addr(&self, address: u32) {
Self::ch()
.out_link()
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
}
fn start(&self) {
Self::ch()
.out_link()
.modify(|_, w| w.outlink_start().set_bit());
}
fn stop(&self) {
Self::ch()
.out_link()
.modify(|_, w| w.outlink_stop().set_bit());
}
fn restart(&self) {
Self::ch()
.out_link()
.modify(|_, w| w.outlink_restart().set_bit());
}
fn clear_interrupts(&self) {
#[cfg(not(esp32s3))]
Self::out_int().clr().write(|w| {
Self::int().clr().write(|w| {
w.out_eof().clear_bit_by_one();
w.out_dscr_err().clear_bit_by_one();
w.out_done().clear_bit_by_one();
@ -111,7 +120,7 @@ impl<const N: u8> RegisterAccess for Channel<N> {
});
#[cfg(esp32s3)]
Self::out_int().clr().write(|w| {
Self::int().clr().write(|w| {
w.out_eof().clear_bit_by_one();
w.out_dscr_err().clear_bit_by_one();
w.out_done().clear_bit_by_one();
@ -123,122 +132,27 @@ impl<const N: u8> RegisterAccess for Channel<N> {
});
}
fn reset_out() {
let conf0 = Self::ch().out_conf0();
conf0.modify(|_, w| w.out_rst().set_bit());
conf0.modify(|_, w| w.out_rst().clear_bit());
}
fn set_out_descriptors(address: u32) {
#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
Self::ch()
.out_link()
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
.out_conf1()
.modify(|_, w| unsafe { w.out_ext_mem_bk_size().bits(size as u8) });
}
}
fn set_out_peripheral(peripheral: u8) {
Self::ch()
.out_peri_sel()
.modify(|_, w| unsafe { w.peri_out_sel().bits(peripheral) });
}
fn start_out() {
Self::ch()
.out_link()
.modify(|_, w| w.outlink_start().set_bit());
}
fn stop_out() {
Self::ch()
.out_link()
.modify(|_, w| w.outlink_stop().set_bit());
}
fn last_out_dscr_address() -> usize {
impl<const N: u8> TxRegisterAccess for ChannelTxImpl<N> {
fn last_dscr_address(&self) -> usize {
Self::ch()
.out_eof_des_addr()
.read()
.out_eof_des_addr()
.bits() as _
}
#[cfg(esp32s3)]
fn set_in_ext_mem_block_size(size: DmaExtMemBKSize) {
Self::ch()
.in_conf1()
.modify(|_, w| unsafe { w.in_ext_mem_bk_size().bits(size as u8) });
}
fn set_in_burstmode(burst_mode: bool) {
Self::ch().in_conf0().modify(|_, w| {
w.in_data_burst_en().bit(burst_mode);
w.indscr_burst_en().bit(burst_mode)
});
}
fn set_in_priority(priority: DmaPriority) {
Self::ch()
.in_pri()
.write(|w| unsafe { w.rx_pri().bits(priority as u8) });
}
fn clear_in_interrupts() {
#[cfg(not(esp32s3))]
Self::in_int().clr().write(|w| {
w.in_suc_eof().clear_bit_by_one();
w.in_err_eof().clear_bit_by_one();
w.in_dscr_err().clear_bit_by_one();
w.in_dscr_empty().clear_bit_by_one();
w.in_done().clear_bit_by_one();
w.infifo_ovf().clear_bit_by_one();
w.infifo_udf().clear_bit_by_one()
});
#[cfg(esp32s3)]
Self::in_int().clr().write(|w| {
w.in_suc_eof().clear_bit_by_one();
w.in_err_eof().clear_bit_by_one();
w.in_dscr_err().clear_bit_by_one();
w.in_dscr_empty().clear_bit_by_one();
w.in_done().clear_bit_by_one();
w.infifo_ovf_l1().clear_bit_by_one();
w.infifo_ovf_l3().clear_bit_by_one();
w.infifo_udf_l1().clear_bit_by_one();
w.infifo_udf_l3().clear_bit_by_one()
});
}
fn reset_in() {
let conf0 = Self::ch().in_conf0();
conf0.modify(|_, w| w.in_rst().set_bit());
conf0.modify(|_, w| w.in_rst().clear_bit());
}
fn set_in_descriptors(address: u32) {
Self::ch()
.in_link()
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn set_in_peripheral(peripheral: u8) {
Self::ch()
.in_peri_sel()
.modify(|_, w| unsafe { w.peri_in_sel().bits(peripheral) });
}
fn start_in() {
Self::ch()
.in_link()
.modify(|_, w| w.inlink_start().set_bit());
}
fn stop_in() {
Self::ch()
.in_link()
.modify(|_, w| w.inlink_stop().set_bit());
}
fn listen_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
Self::out_int().ena().modify(|_, w| {
impl<const N: u8> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<N> {
fn listen(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
Self::int().ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
DmaTxInterrupt::TotalEof => w.out_total_eof().set_bit(),
@ -251,8 +165,8 @@ impl<const N: u8> RegisterAccess for Channel<N> {
})
}
fn unlisten_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
Self::out_int().ena().modify(|_, w| {
fn unlisten(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
Self::int().ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit(),
@ -265,10 +179,10 @@ impl<const N: u8> RegisterAccess for Channel<N> {
})
}
fn is_listening_out() -> EnumSet<DmaTxInterrupt> {
fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let int_ena = Self::out_int().ena().read();
let int_ena = Self::int().ena().read();
if int_ena.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
}
@ -285,10 +199,24 @@ impl<const N: u8> RegisterAccess for Channel<N> {
result
}
fn pending_out_interrupts() -> EnumSet<DmaTxInterrupt> {
fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
Self::int().clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
};
}
w
})
}
fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let int_raw = Self::out_int().raw().read();
let int_raw = Self::int().raw().read();
if int_raw.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
}
@ -305,22 +233,141 @@ impl<const N: u8> RegisterAccess for Channel<N> {
result
}
fn clear_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
Self::out_int().clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
};
fn waker(&self) -> &'static AtomicWaker {
&TX_WAKERS[N as usize]
}
w
})
}
fn listen_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
Self::in_int().ena().modify(|_, w| {
#[non_exhaustive]
#[doc(hidden)]
pub struct ChannelRxImpl<const N: u8> {}
impl<const N: u8> crate::private::Sealed for ChannelRxImpl<N> {}
impl<const N: u8> ChannelRxImpl<N> {
#[inline(always)]
fn ch() -> &'static crate::peripherals::dma::ch::CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(N as usize)
}
#[cfg(any(esp32c2, esp32c3))]
#[inline(always)]
fn int() -> &'static crate::peripherals::dma::int_ch::INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.int_ch(N as usize)
}
#[inline(always)]
#[cfg(any(esp32c6, esp32h2))]
fn int() -> &'static crate::peripherals::dma::in_int_ch::IN_INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.in_int_ch(N as usize)
}
#[cfg(esp32s3)]
#[inline(always)]
fn int() -> &'static crate::peripherals::dma::ch::in_int::IN_INT {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(N as usize).in_int()
}
}
impl<const N: u8> RegisterAccess for ChannelRxImpl<N> {
fn reset(&self) {
let conf0 = Self::ch().in_conf0();
conf0.modify(|_, w| w.in_rst().set_bit());
conf0.modify(|_, w| w.in_rst().clear_bit());
}
fn set_burst_mode(&self, burst_mode: bool) {
Self::ch().in_conf0().modify(|_, w| {
w.in_data_burst_en().bit(burst_mode);
w.indscr_burst_en().bit(burst_mode)
});
}
fn set_priority(&self, priority: DmaPriority) {
Self::ch()
.in_pri()
.write(|w| unsafe { w.rx_pri().bits(priority as u8) });
}
fn set_peripheral(&self, peripheral: u8) {
Self::ch()
.in_peri_sel()
.modify(|_, w| unsafe { w.peri_in_sel().bits(peripheral) });
}
fn set_link_addr(&self, address: u32) {
Self::ch()
.in_link()
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn start(&self) {
Self::ch()
.in_link()
.modify(|_, w| w.inlink_start().set_bit());
}
fn stop(&self) {
Self::ch()
.in_link()
.modify(|_, w| w.inlink_stop().set_bit());
}
fn restart(&self) {
Self::ch()
.in_link()
.modify(|_, w| w.inlink_restart().set_bit());
}
fn clear_interrupts(&self) {
#[cfg(not(esp32s3))]
Self::int().clr().write(|w| {
w.in_suc_eof().clear_bit_by_one();
w.in_err_eof().clear_bit_by_one();
w.in_dscr_err().clear_bit_by_one();
w.in_dscr_empty().clear_bit_by_one();
w.in_done().clear_bit_by_one();
w.infifo_ovf().clear_bit_by_one();
w.infifo_udf().clear_bit_by_one()
});
#[cfg(esp32s3)]
Self::int().clr().write(|w| {
w.in_suc_eof().clear_bit_by_one();
w.in_err_eof().clear_bit_by_one();
w.in_dscr_err().clear_bit_by_one();
w.in_dscr_empty().clear_bit_by_one();
w.in_done().clear_bit_by_one();
w.infifo_ovf_l1().clear_bit_by_one();
w.infifo_ovf_l3().clear_bit_by_one();
w.infifo_udf_l1().clear_bit_by_one();
w.infifo_udf_l3().clear_bit_by_one()
});
}
#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
Self::ch()
.in_conf1()
.modify(|_, w| unsafe { w.in_ext_mem_bk_size().bits(size as u8) });
}
}
impl<const N: u8> RxRegisterAccess for ChannelRxImpl<N> {
fn set_mem2mem_mode(&self, value: bool) {
Self::ch()
.in_conf0()
.modify(|_, w| w.mem_trans_en().bit(value));
}
}
impl<const N: u8> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<N> {
fn listen(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
Self::int().ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().set_bit(),
@ -331,11 +378,11 @@ impl<const N: u8> RegisterAccess for Channel<N> {
};
}
w
})
});
}
fn unlisten_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
Self::in_int().ena().modify(|_, w| {
fn unlisten(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
Self::int().ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit(),
@ -349,10 +396,10 @@ impl<const N: u8> RegisterAccess for Channel<N> {
})
}
fn is_listening_in() -> EnumSet<DmaRxInterrupt> {
fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let int_ena = Self::in_int().ena().read();
let int_ena = Self::int().ena().read();
if int_ena.in_dscr_err().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
}
@ -372,10 +419,25 @@ impl<const N: u8> RegisterAccess for Channel<N> {
result
}
fn pending_in_interrupts() -> EnumSet<DmaRxInterrupt> {
fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
Self::int().clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
};
}
w
})
}
fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let int_raw = Self::in_int().raw().read();
let int_raw = Self::int().raw().read();
if int_raw.in_dscr_err().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
}
@ -395,47 +457,7 @@ impl<const N: u8> RegisterAccess for Channel<N> {
result
}
fn clear_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
Self::in_int().clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
};
}
w
})
}
}
#[non_exhaustive]
#[doc(hidden)]
pub struct ChannelTxImpl<const N: u8> {}
use embassy_sync::waitqueue::AtomicWaker;
static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
static RX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
impl<const N: u8> crate::private::Sealed for ChannelTxImpl<N> {}
impl<const N: u8> TxChannel<Channel<N>> for ChannelTxImpl<N> {
fn waker() -> &'static AtomicWaker {
&TX_WAKERS[N as usize]
}
}
#[non_exhaustive]
#[doc(hidden)]
pub struct ChannelRxImpl<const N: u8> {}
impl<const N: u8> crate::private::Sealed for ChannelRxImpl<N> {}
impl<const N: u8> RxChannel<Channel<N>> for ChannelRxImpl<N> {
fn waker() -> &'static AtomicWaker {
fn waker(&self) -> &'static AtomicWaker {
&RX_WAKERS[N as usize]
}
}
@ -477,10 +499,19 @@ macro_rules! impl_channel {
impl crate::private::Sealed for [<DmaChannel $num>] {}
impl DmaChannel for [<DmaChannel $num>] {
type Channel = Channel<$num>;
type Rx = ChannelRxImpl<$num>;
type Tx = ChannelTxImpl<$num>;
type P = SuitablePeripheral<$num>;
}
impl DmaChannelExt for [<DmaChannel $num>] {
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
ChannelRxImpl::<$num> {}
}
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
ChannelTxImpl::<$num> {}
}
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
let mut dma = unsafe { crate::peripherals::DMA::steal() };
@ -497,11 +528,17 @@ macro_rules! impl_channel {
burst_mode: bool,
priority: DmaPriority,
) -> crate::dma::Channel<'a, [<DmaChannel $num>], M> {
let mut tx_impl = ChannelTxImpl {};
tx_impl.init(burst_mode, priority);
let tx_impl = ChannelTxImpl {};
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let mut rx_impl = ChannelRxImpl {};
rx_impl.init(burst_mode, priority);
let rx_impl = ChannelRxImpl {};
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
// clear the mem2mem mode to avoid failed DMA if this
// channel was previously used for a mem2mem transfer.
#[cfg(gdma)]
rx_impl.set_mem2mem_mode(false);
crate::dma::Channel {
tx: ChannelTx::new(tx_impl, burst_mode),

View File

@ -1497,17 +1497,20 @@ impl RxCircularState {
/// A description of a DMA Channel.
pub trait DmaChannel: crate::private::Sealed {
#[doc(hidden)]
type Channel: RegisterAccess;
/// A description of the RX half of a DMA Channel.
type Rx: RxChannel<Self::Channel>;
type Rx: RxRegisterAccess + InterruptAccess<DmaRxInterrupt>;
/// A description of the TX half of a DMA Channel.
type Tx: TxChannel<Self::Channel>;
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>;
/// A suitable peripheral for this DMA channel.
type P: PeripheralMarker;
}
#[doc(hidden)]
pub trait DmaChannelExt: DmaChannel {
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt>;
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt>;
#[doc(hidden)]
fn set_isr(handler: InterruptHandler);
@ -1516,8 +1519,6 @@ pub trait DmaChannel: crate::private::Sealed {
/// The functions here are not meant to be used outside the HAL
#[doc(hidden)]
pub trait Rx: crate::private::Sealed {
fn init(&mut self, burst_mode: bool, priority: DmaPriority);
unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
@ -1569,53 +1570,7 @@ pub trait Rx: crate::private::Sealed {
fn clear_interrupts(&self);
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker;
}
#[doc(hidden)]
pub trait RxChannel<R>: crate::private::Sealed
where
R: RegisterAccess,
{
fn init(&mut self, burst_mode: bool, priority: DmaPriority) {
R::set_in_burstmode(burst_mode);
R::set_in_priority(priority);
// clear the mem2mem mode to avoid failed DMA if this
// channel was previously used for a mem2mem transfer.
#[cfg(gdma)]
R::set_mem2mem_mode(false);
}
unsafe fn prepare_transfer_without_start(
&mut self,
first_desc: *mut DmaDescriptor,
peri: DmaPeripheral,
) -> Result<(), DmaError> {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
R::clear_in_interrupts();
R::reset_in();
R::set_in_descriptors(first_desc as u32);
R::set_in_peripheral(peri as u8);
Ok(())
}
fn start_transfer(&mut self) -> Result<(), DmaError> {
R::start_in();
if R::pending_in_interrupts().contains(DmaRxInterrupt::DescriptorError) {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
fn stop_transfer(&mut self) {
R::stop_in();
}
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker;
fn waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker;
}
// DMA receive channel
@ -1649,10 +1604,6 @@ impl<'a, CH> Rx for ChannelRx<'a, CH>
where
CH: DmaChannel,
{
fn init(&mut self, burst_mode: bool, priority: DmaPriority) {
self.rx_impl.init(burst_mode, priority);
}
unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
@ -1685,8 +1636,14 @@ where
}
}
self.rx_impl
.prepare_transfer_without_start(chain.first() as _, peri)
compiler_fence(core::sync::atomic::Ordering::SeqCst);
self.rx_impl.clear_interrupts();
self.rx_impl.reset();
self.rx_impl.set_link_addr(chain.first() as u32);
self.rx_impl.set_peripheral(peri as u8);
Ok(())
}
unsafe fn prepare_transfer<BUF: DmaRxBuffer>(
@ -1701,46 +1658,61 @@ where
return Err(DmaError::InvalidAlignment);
}
self.rx_impl
.prepare_transfer_without_start(preparation.start, peri)
compiler_fence(core::sync::atomic::Ordering::SeqCst);
self.rx_impl.clear_interrupts();
self.rx_impl.reset();
self.rx_impl.set_link_addr(preparation.start as u32);
self.rx_impl.set_peripheral(peri as u8);
Ok(())
}
fn start_transfer(&mut self) -> Result<(), DmaError> {
self.rx_impl.start_transfer()
self.rx_impl.start();
if self
.pending_in_interrupts()
.contains(DmaRxInterrupt::DescriptorError)
{
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
fn stop_transfer(&mut self) {
self.rx_impl.stop_transfer()
self.rx_impl.stop()
}
#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
CH::Channel::set_in_ext_mem_block_size(size);
self.rx_impl.set_ext_mem_block_size(size);
}
#[cfg(gdma)]
fn set_mem2mem_mode(&mut self, value: bool) {
CH::Channel::set_mem2mem_mode(value);
self.rx_impl.set_mem2mem_mode(value);
}
fn listen_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
CH::Channel::listen_in(interrupts);
self.rx_impl.listen(interrupts);
}
fn unlisten_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
CH::Channel::unlisten_in(interrupts);
self.rx_impl.unlisten(interrupts);
}
fn is_listening_in(&self) -> EnumSet<DmaRxInterrupt> {
CH::Channel::is_listening_in()
self.rx_impl.is_listening()
}
fn clear_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
CH::Channel::clear_in(interrupts);
self.rx_impl.clear(interrupts);
}
fn pending_in_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
CH::Channel::pending_in_interrupts()
self.rx_impl.pending_interrupts()
}
fn is_done(&self) -> bool {
@ -1749,19 +1721,17 @@ where
}
fn clear_interrupts(&self) {
CH::Channel::clear_in_interrupts();
self.rx_impl.clear_interrupts();
}
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
CH::Rx::waker()
fn waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker {
self.rx_impl.waker()
}
}
/// The functions here are not meant to be used outside the HAL
#[doc(hidden)]
pub trait Tx: crate::private::Sealed {
fn init(&mut self, burst_mode: bool, priority: DmaPriority);
unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
@ -1803,69 +1773,11 @@ pub trait Tx: crate::private::Sealed {
fn clear_interrupts(&self);
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker;
fn waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker;
fn last_out_dscr_address(&self) -> usize;
}
#[doc(hidden)]
pub trait TxChannel<R>: crate::private::Sealed
where
R: RegisterAccess,
{
fn init(&mut self, burst_mode: bool, priority: DmaPriority) {
R::set_out_burstmode(burst_mode);
R::set_out_priority(priority);
}
unsafe fn prepare_transfer_without_start(
&mut self,
first_desc: *mut DmaDescriptor,
peri: DmaPeripheral,
) -> Result<(), DmaError> {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
R::clear_out_interrupts();
R::reset_out();
R::set_out_descriptors(first_desc as u32);
R::set_out_peripheral(peri as u8);
Ok(())
}
fn start_transfer(&mut self) -> Result<(), DmaError> {
R::start_out();
if R::pending_out_interrupts().contains(DmaTxInterrupt::DescriptorError) {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
fn stop_transfer(&mut self) {
R::stop_out();
}
fn listen_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
R::listen_out(interrupts)
}
fn unlisten_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
R::unlisten_out(interrupts)
}
fn is_listening_out(&self) -> EnumSet<DmaTxInterrupt> {
R::is_listening_out()
}
fn clear_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
R::clear_out(interrupts)
}
fn pending_out_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
R::pending_out_interrupts()
}
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker;
}
/// DMA transmit channel
#[doc(hidden)]
pub struct ChannelTx<'a, CH>
@ -1897,10 +1809,6 @@ impl<'a, CH> Tx for ChannelTx<'a, CH>
where
CH: DmaChannel,
{
fn init(&mut self, burst_mode: bool, priority: DmaPriority) {
self.tx_impl.init(burst_mode, priority);
}
unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
@ -1922,8 +1830,15 @@ where
crate::soc::cache_writeback_addr(des.buffer as u32, des.size() as u32);
}
}
self.tx_impl
.prepare_transfer_without_start(chain.first() as _, peri)
compiler_fence(core::sync::atomic::Ordering::SeqCst);
self.tx_impl.clear_interrupts();
self.tx_impl.reset();
self.tx_impl.set_link_addr(chain.first() as u32);
self.tx_impl.set_peripheral(peri as u8);
Ok(())
}
unsafe fn prepare_transfer<BUF: DmaTxBuffer>(
@ -1945,95 +1860,127 @@ where
}
);
// TODO: Get burst mode from DmaBuf.
self.tx_impl
.prepare_transfer_without_start(preparation.start, peri)
compiler_fence(core::sync::atomic::Ordering::SeqCst);
self.tx_impl.clear_interrupts();
self.tx_impl.reset();
self.tx_impl.set_link_addr(preparation.start as u32);
self.tx_impl.set_peripheral(peri as u8);
Ok(())
}
fn start_transfer(&mut self) -> Result<(), DmaError> {
self.tx_impl.start_transfer()
self.tx_impl.start();
if self
.pending_out_interrupts()
.contains(DmaTxInterrupt::DescriptorError)
{
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
fn stop_transfer(&mut self) {
self.tx_impl.stop_transfer()
self.tx_impl.stop()
}
#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
CH::Channel::set_out_ext_mem_block_size(size);
self.tx_impl.set_ext_mem_block_size(size);
}
fn listen_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
CH::Channel::listen_out(interrupts);
self.tx_impl.listen(interrupts);
}
fn unlisten_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
CH::Channel::unlisten_out(interrupts);
self.tx_impl.unlisten(interrupts);
}
fn is_listening_out(&self) -> EnumSet<DmaTxInterrupt> {
CH::Channel::is_listening_out()
self.tx_impl.is_listening()
}
fn clear_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
CH::Channel::clear_out(interrupts);
self.tx_impl.clear(interrupts);
}
fn pending_out_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
CH::Channel::pending_out_interrupts()
self.tx_impl.pending_interrupts()
}
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
CH::Tx::waker()
fn waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker {
self.tx_impl.waker()
}
fn clear_interrupts(&self) {
CH::Channel::clear_out_interrupts();
self.tx_impl.clear_interrupts();
}
fn last_out_dscr_address(&self) -> usize {
CH::Channel::last_out_dscr_address()
self.tx_impl.last_dscr_address()
}
}
#[doc(hidden)]
pub trait RegisterAccess: crate::private::Sealed {
/// Reset the state machine of the channel and FIFO pointer.
fn reset(&self);
/// Enable/Disable INCR burst transfer for channel reading
/// descriptor and accessing data in internal RAM.
fn set_burst_mode(&self, burst_mode: bool);
/// The priority of the channel. The larger the value, the higher the
/// priority.
fn set_priority(&self, priority: DmaPriority);
/// Select a peripheral for the channel.
fn set_peripheral(&self, peripheral: u8);
/// Set the address of the first descriptor.
fn set_link_addr(&self, address: u32);
/// Enable the channel for data transfer.
fn start(&self);
/// Stop the channel from transferring data.
fn stop(&self);
/// Mount a new descriptor.
fn restart(&self);
/// Clear all interrupt bits
fn clear_interrupts(&self);
#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize);
}
#[doc(hidden)]
pub trait RxRegisterAccess: RegisterAccess {
#[cfg(gdma)]
fn set_mem2mem_mode(value: bool);
#[cfg(esp32s3)]
fn set_out_ext_mem_block_size(size: DmaExtMemBKSize);
fn set_out_burstmode(burst_mode: bool);
fn set_out_priority(priority: DmaPriority);
fn clear_out_interrupts();
fn reset_out();
fn set_out_descriptors(address: u32);
fn set_out_peripheral(peripheral: u8);
fn start_out();
fn stop_out();
fn set_mem2mem_mode(&self, value: bool);
}
fn listen_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>);
fn unlisten_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>);
fn is_listening_out() -> EnumSet<DmaTxInterrupt>;
fn clear_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>);
fn pending_out_interrupts() -> EnumSet<DmaTxInterrupt>;
#[doc(hidden)]
pub trait TxRegisterAccess: RegisterAccess {
/// Outlink descriptor address when EOF occurs of Tx channel.
fn last_dscr_address(&self) -> usize;
}
fn listen_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>);
fn unlisten_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>);
fn is_listening_in() -> EnumSet<DmaRxInterrupt>;
fn clear_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>);
fn pending_in_interrupts() -> EnumSet<DmaRxInterrupt>;
fn last_out_dscr_address() -> usize;
#[cfg(esp32s3)]
fn set_in_ext_mem_block_size(size: DmaExtMemBKSize);
fn set_in_burstmode(burst_mode: bool);
fn set_in_priority(priority: DmaPriority);
fn clear_in_interrupts();
fn reset_in();
fn set_in_descriptors(address: u32);
fn set_in_peripheral(peripheral: u8);
fn start_in();
fn stop_in();
#[doc(hidden)]
pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
fn listen(&self, interrupts: impl Into<EnumSet<T>>);
fn unlisten(&self, interrupts: impl Into<EnumSet<T>>);
fn is_listening(&self) -> EnumSet<T>;
fn clear(&self, interrupts: impl Into<EnumSet<T>>);
fn pending_interrupts(&self) -> EnumSet<T>;
fn waker(&self) -> &'static embassy_sync::waitqueue::AtomicWaker;
}
/// DMA Channel
@ -2057,7 +2004,10 @@ where
/// with [crate::interrupt::Priority::max()]
///
/// Interrupts are not enabled at the peripheral level here.
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where
C: DmaChannelExt,
{
C::set_isr(handler);
}
@ -3001,7 +2951,7 @@ pub(crate) mod asynch {
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
TX::waker().register(cx.waker());
self.tx.waker().register(cx.waker());
if self.tx.is_done() {
self.tx.clear_interrupts();
Poll::Ready(Ok(()))
@ -3057,7 +3007,7 @@ pub(crate) mod asynch {
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
RX::waker().register(cx.waker());
self.rx.waker().register(cx.waker());
if self.rx.is_done() {
self.rx.clear_interrupts();
Poll::Ready(Ok(()))
@ -3123,7 +3073,7 @@ pub(crate) mod asynch {
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
TX::waker().register(cx.waker());
self.tx.waker().register(cx.waker());
if self
.tx
.pending_out_interrupts()
@ -3187,7 +3137,7 @@ pub(crate) mod asynch {
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
RX::waker().register(cx.waker());
self.rx.waker().register(cx.waker());
if self
.rx
.pending_in_interrupts()
@ -3229,49 +3179,58 @@ pub(crate) mod asynch {
}
}
fn handle_interrupt<CH: DmaChannel>() {
if CH::Channel::pending_in_interrupts().is_disjoint(
fn handle_interrupt<CH: DmaChannelExt>() {
let rx = CH::get_rx_interrupts();
let tx = CH::get_tx_interrupts();
if rx.pending_interrupts().is_disjoint(
DmaRxInterrupt::DescriptorError
| DmaRxInterrupt::DescriptorEmpty
| DmaRxInterrupt::ErrorEof,
) {
CH::Channel::unlisten_in(
rx.unlisten(
DmaRxInterrupt::DescriptorError
| DmaRxInterrupt::DescriptorEmpty
| DmaRxInterrupt::ErrorEof
| DmaRxInterrupt::SuccessfulEof
| DmaRxInterrupt::Done,
);
CH::Rx::waker().wake()
rx.waker().wake()
}
if CH::Channel::pending_out_interrupts().contains(DmaTxInterrupt::DescriptorError) {
CH::Channel::unlisten_out(
if tx
.pending_interrupts()
.contains(DmaTxInterrupt::DescriptorError)
{
tx.unlisten(
DmaTxInterrupt::DescriptorError | DmaTxInterrupt::TotalEof | DmaTxInterrupt::Done,
);
CH::Tx::waker().wake()
tx.waker().wake()
}
if CH::Channel::pending_in_interrupts().contains(DmaRxInterrupt::SuccessfulEof) {
CH::Channel::unlisten_in(DmaRxInterrupt::SuccessfulEof);
CH::Rx::waker().wake()
}
if CH::Channel::pending_in_interrupts().contains(DmaRxInterrupt::Done) {
CH::Channel::unlisten_in(DmaRxInterrupt::Done);
CH::Rx::waker().wake()
}
if CH::Channel::pending_out_interrupts().contains(DmaTxInterrupt::TotalEof)
&& CH::Channel::is_listening_out().contains(DmaTxInterrupt::TotalEof)
if rx
.pending_interrupts()
.contains(DmaRxInterrupt::SuccessfulEof)
{
CH::Channel::unlisten_out(DmaTxInterrupt::TotalEof);
CH::Tx::waker().wake()
rx.unlisten(DmaRxInterrupt::SuccessfulEof);
rx.waker().wake()
}
if CH::Channel::pending_out_interrupts().contains(DmaTxInterrupt::Done) {
CH::Channel::unlisten_out(DmaTxInterrupt::Done);
CH::Tx::waker().wake()
if rx.pending_interrupts().contains(DmaRxInterrupt::Done) {
rx.unlisten(DmaRxInterrupt::Done);
rx.waker().wake()
}
if tx.pending_interrupts().contains(DmaTxInterrupt::TotalEof)
&& tx.is_listening().contains(DmaTxInterrupt::TotalEof)
{
tx.unlisten(DmaTxInterrupt::TotalEof);
tx.waker().wake()
}
if tx.pending_interrupts().contains(DmaTxInterrupt::Done) {
tx.unlisten(DmaTxInterrupt::Done);
tx.waker().wake()
}
}

View File

@ -11,45 +11,78 @@
//! [SPI]: ../spi/index.html
//! [I2S]: ../i2s/index.html
use embassy_sync::waitqueue::AtomicWaker;
use crate::{
dma::*,
peripheral::PeripheralRef,
system::{Peripheral, PeripheralClockControl},
};
macro_rules! ImplSpiChannel {
($num: literal) => {
paste::paste! {
#[doc = concat!("DMA channel suitable for SPI", $num)]
#[non_exhaustive]
pub struct [<Spi $num DmaChannel>] {}
type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock;
type I2sRegisterBlock = crate::peripherals::i2s0::RegisterBlock;
impl DmaChannel for [<Spi $num DmaChannel>] {
type Channel = [<Spi $num DmaChannel>];
type Rx = [<Spi $num DmaChannelRxImpl>];
type Tx = [<Spi $num DmaChannelTxImpl>];
type P = [<Spi $num DmaSuitablePeripheral>];
#[doc(hidden)]
pub trait PdmaChannel: crate::private::Sealed {
type RegisterBlock;
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
let mut spi = unsafe { $crate::peripherals::[< SPI $num >]::steal() };
spi.[< bind_spi $num _dma_interrupt>](handler.handler());
$crate::interrupt::enable($crate::peripherals::Interrupt::[< SPI $num _DMA >], handler.priority()).unwrap();
}
fn register_block() -> &'static Self::RegisterBlock;
fn tx_waker() -> &'static AtomicWaker;
fn rx_waker() -> &'static AtomicWaker;
}
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
#[doc(hidden)]
pub struct SpiDmaTxChannelImpl<C>(PhantomData<C>);
#[doc(hidden)]
pub struct SpiDmaRxChannelImpl<C>(PhantomData<C>);
impl RegisterAccess for [<Spi $num DmaChannel>] {
fn set_out_burstmode(burst_mode: bool) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
impl<C> crate::private::Sealed for SpiDmaTxChannelImpl<C> {}
impl<C> crate::private::Sealed for SpiDmaRxChannelImpl<C> {}
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDmaTxChannelImpl<C> {
fn reset(&self) {
let spi = C::register_block();
spi.dma_conf().modify(|_, w| w.out_rst().set_bit());
spi.dma_conf().modify(|_, w| w.out_rst().clear_bit());
}
fn set_burst_mode(&self, burst_mode: bool) {
let spi = C::register_block();
spi.dma_conf()
.modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
}
fn set_out_priority(_priority: DmaPriority) {}
fn set_priority(&self, _priority: DmaPriority) {}
fn clear_out_interrupts() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
fn set_peripheral(&self, _peripheral: u8) {
// no-op
}
fn set_link_addr(&self, address: u32) {
let spi = C::register_block();
spi.dma_out_link()
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
}
fn start(&self) {
let spi = C::register_block();
spi.dma_out_link()
.modify(|_, w| w.outlink_start().set_bit());
}
fn stop(&self) {
let spi = C::register_block();
spi.dma_out_link().modify(|_, w| w.outlink_stop().set_bit());
}
fn restart(&self) {
let spi = C::register_block();
spi.dma_out_link()
.modify(|_, w| w.outlink_restart().set_bit());
}
fn clear_interrupts(&self) {
let spi = C::register_block();
spi.dma_int_clr().write(|w| {
w.out_done().clear_bit_by_one();
w.out_eof().clear_bit_by_one();
@ -57,84 +90,20 @@ macro_rules! ImplSpiChannel {
w.outlink_dscr_error().clear_bit_by_one()
});
}
fn reset_out() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_conf().modify(|_, w| w.out_rst().set_bit());
spi.dma_conf().modify(|_, w| w.out_rst().clear_bit());
}
fn set_out_descriptors(address: u32) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_out_link()
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
}
fn set_out_peripheral(_peripheral: u8) {
// no-op
}
fn start_out() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_out_link().modify(|_, w| w.outlink_start().set_bit());
}
fn stop_out() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_out_link().modify(|_, w| w.outlink_stop().set_bit());
}
fn last_out_dscr_address() -> usize {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> TxRegisterAccess for SpiDmaTxChannelImpl<C> {
fn last_dscr_address(&self) -> usize {
let spi = C::register_block();
spi.out_eof_des_addr().read().dma_out_eof_des_addr().bits() as usize
}
fn set_in_burstmode(burst_mode: bool) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_conf()
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
}
fn set_in_priority(_priority: DmaPriority) {}
fn clear_in_interrupts() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_clr().write(|w| {
w.in_done().clear_bit_by_one();
w.in_err_eof().clear_bit_by_one();
w.in_suc_eof().clear_bit_by_one();
w.inlink_dscr_error().clear_bit_by_one()
});
}
fn reset_in() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_conf().modify(|_, w| w.in_rst().set_bit());
spi.dma_conf().modify(|_, w| w.in_rst().clear_bit());
}
fn set_in_descriptors(address: u32) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_in_link()
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn set_in_peripheral(_peripheral: u8) {
// no-op
}
fn start_in() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_in_link().modify(|_, w| w.inlink_start().set_bit());
}
fn stop_in() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_in_link().modify(|_, w| w.inlink_stop().set_bit());
}
fn listen_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaTxInterrupt>
for SpiDmaTxChannelImpl<C>
{
fn listen(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let spi = C::register_block();
spi.dma_int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -148,8 +117,8 @@ macro_rules! ImplSpiChannel {
})
}
fn unlisten_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
fn unlisten(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let spi = C::register_block();
spi.dma_int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -163,10 +132,10 @@ macro_rules! ImplSpiChannel {
})
}
fn is_listening_out() -> EnumSet<DmaTxInterrupt> {
fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
let spi = C::register_block();
let int_ena = spi.dma_int_ena().read();
if int_ena.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
@ -184,10 +153,25 @@ macro_rules! ImplSpiChannel {
result
}
fn pending_out_interrupts() -> EnumSet<DmaTxInterrupt> {
fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let spi = C::register_block();
spi.dma_int_clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
DmaTxInterrupt::DescriptorError => w.outlink_dscr_error().clear_bit_by_one(),
DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
};
}
w
})
}
fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
let spi = C::register_block();
let int_raw = spi.dma_int_raw().read();
if int_raw.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
@ -205,23 +189,70 @@ macro_rules! ImplSpiChannel {
result
}
fn clear_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
DmaTxInterrupt::DescriptorError => w.outlink_dscr_error().clear_bit_by_one(),
DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
};
fn waker(&self) -> &'static AtomicWaker {
C::tx_waker()
}
w
})
}
fn listen_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDmaRxChannelImpl<C> {
fn reset(&self) {
let spi = C::register_block();
spi.dma_conf().modify(|_, w| w.in_rst().set_bit());
spi.dma_conf().modify(|_, w| w.in_rst().clear_bit());
}
fn set_burst_mode(&self, burst_mode: bool) {
let spi = C::register_block();
spi.dma_conf()
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
}
fn set_priority(&self, _priority: DmaPriority) {}
fn set_peripheral(&self, _peripheral: u8) {
// no-op
}
fn set_link_addr(&self, address: u32) {
let spi = C::register_block();
spi.dma_in_link()
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn start(&self) {
let spi = C::register_block();
spi.dma_in_link().modify(|_, w| w.inlink_start().set_bit());
}
fn stop(&self) {
let spi = C::register_block();
spi.dma_in_link().modify(|_, w| w.inlink_stop().set_bit());
}
fn restart(&self) {
let spi = C::register_block();
spi.dma_in_link()
.modify(|_, w| w.inlink_restart().set_bit());
}
fn clear_interrupts(&self) {
let spi = C::register_block();
spi.dma_int_clr().write(|w| {
w.in_done().clear_bit_by_one();
w.in_err_eof().clear_bit_by_one();
w.in_suc_eof().clear_bit_by_one();
w.inlink_dscr_error().clear_bit_by_one()
});
}
}
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RxRegisterAccess for SpiDmaRxChannelImpl<C> {}
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaRxInterrupt>
for SpiDmaRxChannelImpl<C>
{
fn listen(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let spi = C::register_block();
spi.dma_int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -236,8 +267,8 @@ macro_rules! ImplSpiChannel {
})
}
fn unlisten_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
fn unlisten(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let spi = C::register_block();
spi.dma_int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -252,10 +283,10 @@ macro_rules! ImplSpiChannel {
})
}
fn is_listening_in() -> EnumSet<DmaRxInterrupt> {
fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
let spi = C::register_block();
let int_ena = spi.dma_int_ena().read();
if int_ena.inlink_dscr_error().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
@ -276,10 +307,26 @@ macro_rules! ImplSpiChannel {
result
}
fn pending_in_interrupts() -> EnumSet<DmaRxInterrupt> {
fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let spi = C::register_block();
spi.dma_int_clr().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
DmaRxInterrupt::DescriptorError => w.inlink_dscr_error().clear_bit_by_one(),
DmaRxInterrupt::DescriptorEmpty => w.inlink_dscr_empty().clear_bit_by_one(),
DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
};
}
w
})
}
fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
let spi = C::register_block();
let int_raw = spi.dma_int_raw().read();
if int_raw.inlink_dscr_error().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
@ -300,48 +347,63 @@ macro_rules! ImplSpiChannel {
result
}
fn clear_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_clr().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
DmaRxInterrupt::DescriptorError => w.inlink_dscr_error().clear_bit_by_one(),
DmaRxInterrupt::DescriptorEmpty => w.inlink_dscr_empty().clear_bit_by_one(),
DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
};
}
w
})
fn waker(&self) -> &'static AtomicWaker {
C::rx_waker()
}
}
#[non_exhaustive]
#[doc(hidden)]
pub struct [<Spi $num DmaChannelTxImpl>] {}
pub struct SpiDmaChannel<C>(PhantomData<C>);
impl $crate::private::Sealed for [<Spi $num DmaChannelTxImpl>] {}
impl<C> crate::private::Sealed for SpiDmaChannel<C> {}
impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
macro_rules! ImplSpiChannel {
($num: literal) => {
paste::paste! {
#[doc = concat!("DMA channel suitable for SPI", $num)]
#[non_exhaustive]
pub struct [<Spi $num DmaChannel>] {}
impl DmaChannel for [<Spi $num DmaChannel>] {
type Rx = SpiDmaRxChannelImpl<Self>;
type Tx = SpiDmaTxChannelImpl<Self>;
type P = [<Spi $num DmaSuitablePeripheral>];
}
impl DmaChannelExt for [<Spi $num DmaChannel>] {
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
SpiDmaRxChannelImpl::<Self>(PhantomData)
}
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
SpiDmaTxChannelImpl::<Self>(PhantomData)
}
fn set_isr(handler: InterruptHandler) {
let interrupt = $crate::peripherals::Interrupt::[< SPI $num _DMA >];
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
}
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
}
}
impl PdmaChannel for [<Spi $num DmaChannel>] {
type RegisterBlock = SpiRegisterBlock;
fn register_block() -> &'static SpiRegisterBlock {
unsafe { &*crate::peripherals::[<SPI $num>]::PTR }
}
fn tx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
fn rx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
#[non_exhaustive]
#[doc(hidden)]
pub struct [<Spi $num DmaChannelRxImpl>] {}
impl $crate::private::Sealed for [<Spi $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelRxImpl>] {
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
#[doc = concat!("Creates a channel for SPI", $num)]
#[non_exhaustive]
@ -362,11 +424,13 @@ macro_rules! ImplSpiChannel {
.modify(|_, w| unsafe { w.[< spi $num _dma_chan_sel>]().bits($num - 1) });
}
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
let tx_impl = SpiDmaTxChannelImpl(PhantomData);
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let mut rx_impl = [<Spi $num DmaChannelRxImpl>] {};
rx_impl.init(burst_mode, priority);
let rx_impl = SpiDmaRxChannelImpl(PhantomData);
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
@ -407,38 +471,26 @@ macro_rules! ImplSpiChannel {
};
}
macro_rules! ImplI2sChannel {
($num: literal, $peripheral: literal) => {
paste::paste! {
#[doc = concat!("DMA channel suitable for I2S", $num)]
pub struct [<I2s $num DmaChannel>] {}
#[doc(hidden)]
pub struct I2sDmaTxChannelImpl<C>(PhantomData<C>);
#[doc(hidden)]
pub struct I2sDmaRxChannelImpl<C>(PhantomData<C>);
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
impl<C> crate::private::Sealed for I2sDmaTxChannelImpl<C> {}
impl<C> crate::private::Sealed for I2sDmaRxChannelImpl<C> {}
impl DmaChannel for [<I2s $num DmaChannel>] {
type Channel = [<I2s $num DmaChannel>];
type Rx = [<I2s $num DmaChannelRxImpl>];
type Tx = [<I2s $num DmaChannelTxImpl>];
type P = [<I2s $num DmaSuitablePeripheral>];
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
let mut i2s = unsafe { $crate::peripherals::[< I2S $num >]::steal() };
i2s.[< bind_i2s $num _interrupt>](handler.handler());
$crate::interrupt::enable($crate::peripherals::Interrupt::[< I2S $num >], handler.priority()).unwrap();
}
}
impl RegisterAccess for [<I2s $num DmaChannel>] {
fn set_out_burstmode(burst_mode: bool) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.lc_conf()
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDmaTxChannelImpl<C> {
fn set_burst_mode(&self, burst_mode: bool) {
let reg_block = C::register_block();
reg_block
.lc_conf()
.modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
}
fn set_out_priority(_priority: DmaPriority) {}
fn set_priority(&self, _priority: DmaPriority) {}
fn clear_out_interrupts() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
fn clear_interrupts(&self) {
let reg_block = C::register_block();
reg_block.int_clr().write(|w| {
w.out_done()
.clear_bit_by_one()
@ -451,87 +503,61 @@ macro_rules! ImplI2sChannel {
});
}
fn reset_out() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
fn reset(&self) {
let reg_block = C::register_block();
reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit());
reg_block.lc_conf().modify(|_, w| w.out_rst().clear_bit());
}
fn set_out_descriptors(address: u32) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.out_link()
fn set_link_addr(&self, address: u32) {
let reg_block = C::register_block();
reg_block
.out_link()
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
}
fn set_out_peripheral(_peripheral: u8) {
fn set_peripheral(&self, _peripheral: u8) {
// no-op
}
fn start_out() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.out_link().modify(|_, w| w.outlink_start().set_bit());
fn start(&self) {
let reg_block = C::register_block();
reg_block
.out_link()
.modify(|_, w| w.outlink_start().set_bit());
}
fn stop_out() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.out_link().modify(|_, w| w.outlink_stop().set_bit());
fn stop(&self) {
let reg_block = C::register_block();
reg_block
.out_link()
.modify(|_, w| w.outlink_stop().set_bit());
}
fn last_out_dscr_address() -> usize {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.out_eof_des_addr().read().out_eof_des_addr().bits() as usize
fn restart(&self) {
let reg_block = C::register_block();
reg_block
.out_link()
.modify(|_, w| w.outlink_restart().set_bit());
}
}
fn set_in_burstmode(burst_mode: bool) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.lc_conf()
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> TxRegisterAccess for I2sDmaTxChannelImpl<C> {
fn last_dscr_address(&self) -> usize {
let reg_block = C::register_block();
reg_block
.out_eof_des_addr()
.read()
.out_eof_des_addr()
.bits() as usize
}
}
fn set_in_priority(_priority: DmaPriority) {}
fn clear_in_interrupts() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.int_clr().write(|w| {
w.in_done()
.clear_bit_by_one()
.in_err_eof()
.clear_bit_by_one()
.in_suc_eof()
.clear_bit_by_one()
.in_dscr_err()
.clear_bit_by_one()
});
}
fn reset_in() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit());
reg_block.lc_conf().modify(|_, w| w.in_rst().clear_bit());
}
fn set_in_descriptors(address: u32) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.in_link()
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn set_in_peripheral(_peripheral: u8) {
// no-op
}
fn start_in() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.in_link().modify(|_, w| w.inlink_start().set_bit());
}
fn stop_in() {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.in_link().modify(|_, w| w.inlink_stop().set_bit());
}
fn listen_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaTxInterrupt>
for I2sDmaTxChannelImpl<C>
{
fn listen(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let reg_block = C::register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -545,8 +571,8 @@ macro_rules! ImplI2sChannel {
})
}
fn unlisten_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
fn unlisten(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let reg_block = C::register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -560,10 +586,10 @@ macro_rules! ImplI2sChannel {
})
}
fn is_listening_out() -> EnumSet<DmaTxInterrupt> {
fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
let reg_block = C::register_block();
let int_ena = reg_block.int_ena().read();
if int_ena.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
@ -581,10 +607,10 @@ macro_rules! ImplI2sChannel {
result
}
fn pending_out_interrupts() -> EnumSet<DmaTxInterrupt> {
fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
let reg_block = C::register_block();
let int_raw = reg_block.int_raw().read();
if int_raw.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
@ -602,8 +628,8 @@ macro_rules! ImplI2sChannel {
result
}
fn clear_out(interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let reg_block = C::register_block();
reg_block.int_clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
@ -617,8 +643,79 @@ macro_rules! ImplI2sChannel {
})
}
fn listen_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
fn waker(&self) -> &'static AtomicWaker {
C::tx_waker()
}
}
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDmaRxChannelImpl<C> {
fn set_burst_mode(&self, burst_mode: bool) {
let reg_block = C::register_block();
reg_block
.lc_conf()
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
}
fn set_priority(&self, _priority: DmaPriority) {}
fn clear_interrupts(&self) {
let reg_block = C::register_block();
reg_block.int_clr().write(|w| {
w.in_done()
.clear_bit_by_one()
.in_err_eof()
.clear_bit_by_one()
.in_suc_eof()
.clear_bit_by_one()
.in_dscr_err()
.clear_bit_by_one()
});
}
fn reset(&self) {
let reg_block = C::register_block();
reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit());
reg_block.lc_conf().modify(|_, w| w.in_rst().clear_bit());
}
fn set_link_addr(&self, address: u32) {
let reg_block = C::register_block();
reg_block
.in_link()
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn set_peripheral(&self, _peripheral: u8) {
// no-op
}
fn start(&self) {
let reg_block = C::register_block();
reg_block
.in_link()
.modify(|_, w| w.inlink_start().set_bit());
}
fn stop(&self) {
let reg_block = C::register_block();
reg_block.in_link().modify(|_, w| w.inlink_stop().set_bit());
}
fn restart(&self) {
let reg_block = C::register_block();
reg_block
.in_link()
.modify(|_, w| w.inlink_restart().set_bit());
}
}
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RxRegisterAccess for I2sDmaRxChannelImpl<C> {}
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaRxInterrupt>
for I2sDmaRxChannelImpl<C>
{
fn listen(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let reg_block = C::register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -633,8 +730,8 @@ macro_rules! ImplI2sChannel {
})
}
fn unlisten_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
fn unlisten(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let reg_block = C::register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts.into() {
match interrupt {
@ -649,10 +746,10 @@ macro_rules! ImplI2sChannel {
})
}
fn is_listening_in() -> EnumSet<DmaRxInterrupt> {
fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
let reg_block = C::register_block();
let int_ena = reg_block.int_ena().read();
if int_ena.in_dscr_err().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
@ -673,10 +770,10 @@ macro_rules! ImplI2sChannel {
result
}
fn pending_in_interrupts() -> EnumSet<DmaRxInterrupt> {
fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
let reg_block = C::register_block();
let int_raw = reg_block.int_raw().read();
if int_raw.in_dscr_err().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
@ -697,8 +794,8 @@ macro_rules! ImplI2sChannel {
result
}
fn clear_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let reg_block = C::register_block();
reg_block.int_clr().write(|w| {
for interrupt in interrupts.into() {
match interrupt {
@ -712,27 +809,54 @@ macro_rules! ImplI2sChannel {
w
})
}
fn waker(&self) -> &'static AtomicWaker {
C::rx_waker()
}
}
#[doc(hidden)]
pub struct [<I2s $num DmaChannelTxImpl>] {}
macro_rules! ImplI2sChannel {
($num: literal) => {
paste::paste! {
#[doc = concat!("DMA channel suitable for I2S", $num)]
pub struct [<I2s $num DmaChannel>] {}
impl $crate::private::Sealed for [<I2s $num DmaChannelTxImpl>] {}
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
impl<'a> TxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelTxImpl>] {
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
impl DmaChannel for [<I2s $num DmaChannel>] {
type Rx = I2sDmaRxChannelImpl<Self>;
type Tx = I2sDmaTxChannelImpl<Self>;
type P = [<I2s $num DmaSuitablePeripheral>];
}
impl DmaChannelExt for [<I2s $num DmaChannel>] {
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
I2sDmaRxChannelImpl::<Self>(PhantomData)
}
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
I2sDmaTxChannelImpl::<Self>(PhantomData)
}
fn set_isr(handler: InterruptHandler) {
let interrupt = $crate::peripherals::Interrupt::[< I2S $num >];
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
}
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
}
}
impl PdmaChannel for [<I2s $num DmaChannel>] {
type RegisterBlock = I2sRegisterBlock;
fn register_block() -> &'static I2sRegisterBlock {
unsafe { &*crate::peripherals::[< I2S $num >]::PTR }
}
fn tx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
#[doc(hidden)]
pub struct [<I2s $num DmaChannelRxImpl>] {}
impl $crate::private::Sealed for [<I2s $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelRxImpl>] {
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
fn rx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
@ -747,11 +871,13 @@ macro_rules! ImplI2sChannel {
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>], M> {
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
let tx_impl = I2sDmaTxChannelImpl(PhantomData);
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let mut rx_impl = [<I2s $num DmaChannelRxImpl>] {};
rx_impl.init(burst_mode, priority);
let rx_impl = I2sDmaRxChannelImpl(PhantomData);
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
@ -816,7 +942,7 @@ impl PeripheralMarker for I2s0DmaSuitablePeripheral {}
impl I2sPeripheral for I2s0DmaSuitablePeripheral {}
impl I2s0Peripheral for I2s0DmaSuitablePeripheral {}
ImplI2sChannel!(0, "I2S0");
ImplI2sChannel!(0);
#[doc(hidden)]
#[non_exhaustive]
@ -826,7 +952,7 @@ impl I2sPeripheral for I2s1DmaSuitablePeripheral {}
impl I2s1Peripheral for I2s1DmaSuitablePeripheral {}
#[cfg(i2s1)]
ImplI2sChannel!(1, "I2S1");
ImplI2sChannel!(1);
/// DMA Peripheral
///