use portable_atomic::{AtomicBool, Ordering};
use crate::{asynch::AtomicWaker, dma::*, peripheral::Peripheral, peripherals::Interrupt};
pub(super) type I2sRegisterBlock = crate::peripherals::i2s0::RegisterBlock;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AnyI2sDmaRxChannel(pub(crate) AnyI2sDmaChannel);
impl crate::private::Sealed for AnyI2sDmaRxChannel {}
impl DmaRxChannel for AnyI2sDmaRxChannel {}
impl Peripheral for AnyI2sDmaRxChannel {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self(self.0.clone_unchecked())
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AnyI2sDmaTxChannel(pub(crate) AnyI2sDmaChannel);
impl crate::private::Sealed for AnyI2sDmaTxChannel {}
impl DmaTxChannel for AnyI2sDmaTxChannel {}
impl Peripheral for AnyI2sDmaTxChannel {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self(self.0.clone_unchecked())
}
}
impl RegisterAccess for AnyI2sDmaTxChannel {
fn reset(&self) {
let reg_block = self.0.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_burst_mode(&self, burst_mode: BurstConfig) {
let reg_block = self.0.register_block();
reg_block
.lc_conf()
.modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
}
fn set_descr_burst_mode(&self, burst_mode: bool) {
let reg_block = self.0.register_block();
reg_block
.lc_conf()
.modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
}
fn set_link_addr(&self, address: u32) {
let reg_block = self.0.register_block();
reg_block
.out_link()
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
}
fn set_peripheral(&self, _peripheral: u8) {
}
fn start(&self) {
let reg_block = self.0.register_block();
reg_block
.out_link()
.modify(|_, w| w.outlink_start().set_bit());
}
fn stop(&self) {
let reg_block = self.0.register_block();
reg_block
.out_link()
.modify(|_, w| w.outlink_stop().set_bit());
}
fn restart(&self) {
let reg_block = self.0.register_block();
reg_block
.out_link()
.modify(|_, w| w.outlink_restart().set_bit());
}
fn set_check_owner(&self, check_owner: Option<bool>) {
let reg_block = self.0.register_block();
reg_block
.lc_conf()
.modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
}
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
self.0.is_compatible_with(peripheral)
}
#[cfg(psram_dma)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
let spi = self.0.register_block();
spi.lc_conf()
.modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
}
#[cfg(psram_dma)]
fn can_access_psram(&self) -> bool {
matches!(self.0, AnyI2sDmaChannel(AnyI2sDmaChannelInner::I2s0(_)))
}
}
impl TxRegisterAccess for AnyI2sDmaTxChannel {
fn set_auto_write_back(&self, enable: bool) {
let reg_block = self.0.register_block();
reg_block
.lc_conf()
.modify(|_, w| w.out_auto_wrback().bit(enable));
}
fn last_dscr_address(&self) -> usize {
let reg_block = self.0.register_block();
reg_block
.out_eof_des_addr()
.read()
.out_eof_des_addr()
.bits() as usize
}
fn peripheral_interrupt(&self) -> Option<Interrupt> {
None
}
fn async_handler(&self) -> Option<InterruptHandler> {
None
}
}
impl InterruptAccess<DmaTxInterrupt> for AnyI2sDmaTxChannel {
fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
let reg_block = self.0.register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts {
match interrupt {
DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
DmaTxInterrupt::Eof => w.out_eof().bit(enable),
DmaTxInterrupt::Done => w.out_done().bit(enable),
};
}
w
});
}
fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let reg_block = self.0.register_block();
let int_ena = reg_block.int_ena().read();
if int_ena.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
}
if int_ena.out_dscr_err().bit_is_set() {
result |= DmaTxInterrupt::DescriptorError;
}
if int_ena.out_eof().bit_is_set() {
result |= DmaTxInterrupt::Eof;
}
if int_ena.out_done().bit_is_set() {
result |= DmaTxInterrupt::Done;
}
result
}
fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
let mut result = EnumSet::new();
let reg_block = self.0.register_block();
let int_raw = reg_block.int_raw().read();
if int_raw.out_total_eof().bit_is_set() {
result |= DmaTxInterrupt::TotalEof;
}
if int_raw.out_dscr_err().bit_is_set() {
result |= DmaTxInterrupt::DescriptorError;
}
if int_raw.out_eof().bit_is_set() {
result |= DmaTxInterrupt::Eof;
}
if int_raw.out_done().bit_is_set() {
result |= DmaTxInterrupt::Done;
}
result
}
fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
let reg_block = self.0.register_block();
reg_block.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 waker(&self) -> &'static AtomicWaker {
self.0.tx_waker()
}
fn is_async(&self) -> bool {
self.0.tx_async_flag().load(Ordering::Relaxed)
}
fn set_async(&self, _is_async: bool) {
self.0.tx_async_flag().store(_is_async, Ordering::Relaxed);
}
}
impl RegisterAccess for AnyI2sDmaRxChannel {
fn reset(&self) {
let reg_block = self.0.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_burst_mode(&self, _burst_mode: BurstConfig) {}
fn set_descr_burst_mode(&self, burst_mode: bool) {
let reg_block = self.0.register_block();
reg_block
.lc_conf()
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
}
fn set_link_addr(&self, address: u32) {
let reg_block = self.0.register_block();
reg_block
.in_link()
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn set_peripheral(&self, _peripheral: u8) {
}
fn start(&self) {
let reg_block = self.0.register_block();
reg_block
.in_link()
.modify(|_, w| w.inlink_start().set_bit());
}
fn stop(&self) {
let reg_block = self.0.register_block();
reg_block.in_link().modify(|_, w| w.inlink_stop().set_bit());
}
fn restart(&self) {
let reg_block = self.0.register_block();
reg_block
.in_link()
.modify(|_, w| w.inlink_restart().set_bit());
}
fn set_check_owner(&self, check_owner: Option<bool>) {
let reg_block = self.0.register_block();
reg_block
.lc_conf()
.modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true)));
}
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
self.0.is_compatible_with(peripheral)
}
#[cfg(psram_dma)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
let spi = self.0.register_block();
spi.lc_conf()
.modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
}
#[cfg(psram_dma)]
fn can_access_psram(&self) -> bool {
matches!(self.0, AnyI2sDmaChannel(AnyI2sDmaChannelInner::I2s0(_)))
}
}
impl RxRegisterAccess for AnyI2sDmaRxChannel {
fn peripheral_interrupt(&self) -> Option<Interrupt> {
Some(self.0.peripheral_interrupt())
}
fn async_handler(&self) -> Option<InterruptHandler> {
Some(self.0.async_handler())
}
}
impl InterruptAccess<DmaRxInterrupt> for AnyI2sDmaRxChannel {
fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
let reg_block = self.0.register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts {
match interrupt {
DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
DmaRxInterrupt::Done => w.in_done().bit(enable),
};
}
w
});
}
fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let reg_block = self.0.register_block();
let int_ena = reg_block.int_ena().read();
if int_ena.in_dscr_err().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
}
if int_ena.in_dscr_empty().bit_is_set() {
result |= DmaRxInterrupt::DescriptorEmpty;
}
if int_ena.in_suc_eof().bit_is_set() {
result |= DmaRxInterrupt::SuccessfulEof;
}
if int_ena.in_err_eof().bit_is_set() {
result |= DmaRxInterrupt::ErrorEof;
}
if int_ena.in_done().bit_is_set() {
result |= DmaRxInterrupt::Done;
}
result
}
fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
let mut result = EnumSet::new();
let reg_block = self.0.register_block();
let int_raw = reg_block.int_raw().read();
if int_raw.in_dscr_err().bit_is_set() {
result |= DmaRxInterrupt::DescriptorError;
}
if int_raw.in_dscr_empty().bit_is_set() {
result |= DmaRxInterrupt::DescriptorEmpty;
}
if int_raw.in_suc_eof().bit_is_set() {
result |= DmaRxInterrupt::SuccessfulEof;
}
if int_raw.in_err_eof().bit_is_set() {
result |= DmaRxInterrupt::ErrorEof;
}
if int_raw.in_done().bit_is_set() {
result |= DmaRxInterrupt::Done;
}
result
}
fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
let reg_block = self.0.register_block();
reg_block.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 waker(&self) -> &'static AtomicWaker {
self.0.rx_waker()
}
fn is_async(&self) -> bool {
self.0.rx_async_flag().load(Ordering::Relaxed)
}
fn set_async(&self, _is_async: bool) {
self.0.rx_async_flag().store(_is_async, Ordering::Relaxed);
}
}
crate::any_peripheral! {
pub peripheral AnyI2sDmaChannel {
I2s0(I2s0DmaChannel),
#[cfg(i2s1)]
I2s1(I2s1DmaChannel),
}
}
impl DmaChannel for AnyI2sDmaChannel {
type Rx = AnyI2sDmaRxChannel;
type Tx = AnyI2sDmaTxChannel;
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
(
AnyI2sDmaRxChannel(unsafe { self.clone_unchecked() }),
AnyI2sDmaTxChannel(unsafe { self.clone_unchecked() }),
)
}
}
impl PdmaChannel for AnyI2sDmaChannel {
type RegisterBlock = I2sRegisterBlock;
delegate::delegate! {
to match &self.0 {
AnyI2sDmaChannelInner::I2s0(channel) => channel,
#[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(channel) => channel,
} {
fn register_block(&self) -> &I2sRegisterBlock;
fn tx_waker(&self) -> &'static AtomicWaker;
fn rx_waker(&self) -> &'static AtomicWaker;
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
fn peripheral_interrupt(&self) -> Interrupt;
fn async_handler(&self) -> InterruptHandler;
fn rx_async_flag(&self) -> &'static AtomicBool;
fn tx_async_flag(&self) -> &'static AtomicBool;
}
}
}