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:
parent
487de0ff22
commit
f1bedbe3dc
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
fn listen_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
|
||||
Self::in_int().ena().modify(|_, w| {
|
||||
#[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),
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct SpiDmaTxChannelImpl<C>(PhantomData<C>);
|
||||
#[doc(hidden)]
|
||||
pub struct SpiDmaRxChannelImpl<C>(PhantomData<C>);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
|
||||
|
||||
impl RegisterAccess for [<Spi $num DmaChannel>] {
|
||||
fn set_out_burstmode(burst_mode: bool) {
|
||||
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
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 listen_in(interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
|
||||
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct SpiDmaChannel<C>(PhantomData<C>);
|
||||
|
||||
impl<C> crate::private::Sealed for SpiDmaChannel<C> {}
|
||||
|
||||
macro_rules! ImplSpiChannel {
|
||||
($num: literal) => {
|
||||
paste::paste! {
|
||||
#[doc = concat!("DMA channel suitable for SPI", $num)]
|
||||
#[non_exhaustive]
|
||||
#[doc(hidden)]
|
||||
pub struct [<Spi $num DmaChannelTxImpl>] {}
|
||||
pub struct [<Spi $num DmaChannel>] {}
|
||||
|
||||
impl $crate::private::Sealed for [<Spi $num DmaChannelTxImpl>] {}
|
||||
impl DmaChannel for [<Spi $num DmaChannel>] {
|
||||
type Rx = SpiDmaRxChannelImpl<Self>;
|
||||
type Tx = SpiDmaTxChannelImpl<Self>;
|
||||
type P = [<Spi $num DmaSuitablePeripheral>];
|
||||
}
|
||||
|
||||
impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {
|
||||
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
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 DmaChannel>] {}
|
||||
|
||||
impl DmaChannel for [<I2s $num DmaChannel>] {
|
||||
type Rx = I2sDmaRxChannelImpl<Self>;
|
||||
type Tx = I2sDmaTxChannelImpl<Self>;
|
||||
type P = [<I2s $num DmaSuitablePeripheral>];
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct [<I2s $num DmaChannelTxImpl>] {}
|
||||
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)
|
||||
}
|
||||
|
||||
impl $crate::private::Sealed for [<I2s $num DmaChannelTxImpl>] {}
|
||||
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<'a> TxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelTxImpl>] {
|
||||
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
|
||||
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
|
||||
///
|
||||
|
||||
Loading…
Reference in New Issue
Block a user