From 9d8c91bb60dec5bde7aa82c8d2fc18746189558a Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Thu, 14 Mar 2024 13:48:16 +0100 Subject: [PATCH] Runtime DMA interrupt binding --- esp-hal-procmacros/src/lib.rs | 41 ++- esp-hal/CHANGELOG.md | 1 + esp-hal/Cargo.toml | 16 +- esp-hal/src/aes/mod.rs | 6 +- esp-hal/src/dma/gdma.rs | 77 ++++- esp-hal/src/dma/mod.rs | 376 ++++++++---------------- esp-hal/src/dma/pdma.rs | 90 +++++- esp-hal/src/embassy/mod.rs | 47 +-- esp-hal/src/gpio.rs | 7 +- esp-hal/src/i2s.rs | 376 ++++++++++++++++++++---- esp-hal/src/parl_io.rs | 384 ++++++++++++++++++++----- esp-hal/src/soc/esp32/peripherals.rs | 8 +- esp-hal/src/soc/esp32c2/peripherals.rs | 4 +- esp-hal/src/soc/esp32c3/peripherals.rs | 6 +- esp-hal/src/soc/esp32c6/peripherals.rs | 8 +- esp-hal/src/soc/esp32h2/peripherals.rs | 8 +- esp-hal/src/soc/esp32s2/peripherals.rs | 6 +- esp-hal/src/soc/esp32s3/peripherals.rs | 10 +- esp-hal/src/spi/master.rs | 242 +++++++++++++--- esp-hal/src/spi/slave.rs | 107 ++++--- examples/src/bin/embassy_i2s_read.rs | 4 +- examples/src/bin/embassy_i2s_sound.rs | 4 +- examples/src/bin/embassy_parl_io_rx.rs | 2 +- examples/src/bin/embassy_parl_io_tx.rs | 2 +- examples/src/bin/embassy_spi.rs | 16 +- 25 files changed, 1254 insertions(+), 594 deletions(-) diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index fb5f094f5d9..0f010570bb0 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -369,15 +369,19 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_error::proc_macro_error] #[proc_macro_attribute] pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { - use darling::ast::NestedMeta; + use darling::{ast::NestedMeta, FromMeta}; use proc_macro::Span; use proc_macro2::Ident; use proc_macro_crate::{crate_name, FoundCrate}; - use proc_macro_error::abort; use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type}; use self::interrupt::{check_attr_whitelist, WhiteListCaller}; + #[derive(Debug, FromMeta)] + struct MacroArgs { + priority: Option, + } + let mut f: ItemFn = syn::parse(input).expect("`#[handler]` must be applied to a function"); let original_span = f.span(); @@ -388,6 +392,13 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { } }; + let args = match MacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { + return TokenStream::from(e.write_errors()); + } + }; + let root = Ident::new( if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") { &name @@ -397,30 +408,10 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { Span::call_site().into(), ); - let priority = if attr_args.len() > 1 { - abort!( - Span::call_site(), - "This attribute accepts one optional argument" - ) - } else if attr_args.len() == 1 { - match &attr_args[0] { - NestedMeta::Lit(syn::Lit::Str(priority)) => priority.value(), - _ => abort!( - Span::call_site(), - "The priority must be provided as a string" - ), - } + let priority = if let Some(priority) = args.priority { + quote::quote!( #priority ) } else { - String::from("min") - }; - - let priority = match priority.as_str() { - "min" => quote::quote_spanned!(original_span => #root::interrupt::Priority::min()), - "max" => quote::quote_spanned!(original_span => #root::interrupt::Priority::max()), - _ => { - let priority = Ident::new(&priority, proc_macro2::Span::call_site()); - quote::quote_spanned!(original_span => #root::interrupt::Priority::#priority) - } + quote::quote! { #root::interrupt::Priority::min() } }; // XXX should we blacklist other attributes? diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index b43b41c742a..f304f7c6658 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Uart` structs now take a `Mode` parameter which defines how the driver is initialized (#1294) - `Rmt` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument. (#1341) - All `Instance` traits are now sealed, and can no longer be implemented for arbitrary types (#1346) +- DMA channels can/have to be explicitly created for async or blocking drivers, added `set_interrupt_handler` to DMA channels, SPI, I2S, PARL_IO, don't enable interrupts on startup for DMA, I2S, PARL_IO, GPIO (#1300) ### Removed diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index ee265c80695..a7adac18c89 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -52,14 +52,14 @@ xtensa-lx = { version = "0.9.0", optional = true } # IMPORTANT: # Each supported device MUST have its PAC included below along with a # corresponding feature. -esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } -esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } -esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } -esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } -esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } -esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } -esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } -esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true } +esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } +esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } +esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } +esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } +esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } +esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } +esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } +esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true } [target.'cfg(target_arch = "riscv32")'.dependencies] esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" } diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index 72dee60c334..acae07e9702 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -277,7 +277,7 @@ pub mod dma { { pub aes: super::Aes<'d>, - pub(crate) channel: Channel<'d, C>, + pub(crate) channel: Channel<'d, C, crate::Blocking>, } pub trait WithDmaAes<'d, C> @@ -285,7 +285,7 @@ pub mod dma { C: ChannelTypes, C::P: AesPeripheral, { - fn with_dma(self, channel: Channel<'d, C>) -> AesDma<'d, C>; + fn with_dma(self, channel: Channel<'d, C, crate::Blocking>) -> AesDma<'d, C>; } impl<'d, C> WithDmaAes<'d, C> for crate::aes::Aes<'d> @@ -293,7 +293,7 @@ pub mod dma { C: ChannelTypes, C::P: AesPeripheral, { - fn with_dma(self, mut channel: Channel<'d, C>) -> AesDma<'d, C> { + fn with_dma(self, mut channel: Channel<'d, C, crate::Blocking>) -> AesDma<'d, C> { channel.tx.init_channel(); // no need to call this for both, TX and RX AesDma { aes: self, channel } diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 01398cd8895..0b30c93d1a3 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -31,8 +31,22 @@ use crate::{ }; macro_rules! impl_channel { - ($num: literal) => { + ($num: literal, $async_handler: path, $($interrupt: ident),* ) => { paste::paste! { + #[non_exhaustive] + pub struct [] {} + + impl InterruptBinder for [] { + #[cfg(feature = "vectored")] + fn set_isr(handler: $crate::interrupt::InterruptHandler) { + let mut dma = unsafe { crate::peripherals::DMA::steal() }; + $( + dma.[< bind_ $interrupt:lower _interrupt >](handler.handler()); + $crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, handler.priority()).unwrap(); + )* + } + } + #[non_exhaustive] pub struct [] {} @@ -40,6 +54,7 @@ macro_rules! impl_channel { type P = []; type Tx<'a> = ChannelTx<'a, [], []>; type Rx<'a> = ChannelRx<'a, [], []>; + type Binder = []; } impl RegisterAccess for [] { @@ -550,7 +565,7 @@ macro_rules! impl_channel { pub struct [] {} impl [] { - /// Configure the channel for use + /// Configure the channel for use with blocking APIs /// /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to /// transfer buffers of size `1..=4092`, you need 1 descriptor. @@ -560,16 +575,44 @@ macro_rules! impl_channel { tx_descriptors: &'a mut [DmaDescriptor], rx_descriptors: &'a mut [DmaDescriptor], priority: DmaPriority, - ) -> Channel<'a, []> { + ) -> Channel<'a, [], $crate::Blocking> { + let mut tx_impl = [] {}; + tx_impl.init(burst_mode, priority); + + let mut rx_impl = [] {}; + rx_impl.init(burst_mode, priority); + + Channel { + tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), + rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode), + phantom: PhantomData, + } + } + + /// Configure the channel for use with async APIs + /// + /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to + /// transfer buffers of size `1..=4092`, you need 1 descriptor. + #[cfg(feature = "async")] + pub fn configure_for_async<'a>( + self, + burst_mode: bool, + tx_descriptors: &'a mut [DmaDescriptor], + rx_descriptors: &'a mut [DmaDescriptor], + priority: DmaPriority, + ) -> Channel<'a, [], $crate::Async> { let mut tx_impl = [] {}; tx_impl.init(burst_mode, priority); let mut rx_impl = [] {}; rx_impl.init(burst_mode, priority); + <[] as ChannelTypes>::Binder::set_isr($async_handler); + Channel { tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode), + phantom: PhantomData, } } } @@ -596,15 +639,25 @@ macro_rules! impl_channel { }; } -impl_channel!(0); -#[cfg(not(esp32c2))] -impl_channel!(1); -#[cfg(not(esp32c2))] -impl_channel!(2); -#[cfg(esp32s3)] -impl_channel!(3); -#[cfg(esp32s3)] -impl_channel!(4); +cfg_if::cfg_if! { + if #[cfg(esp32c2)] { + impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0); + } else if #[cfg(esp32c3)] { + impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0); + impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_CH1); + impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_CH2); + } else if #[cfg(any(esp32c6, esp32h2))] { + impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0); + impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1); + impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2); + } else if #[cfg(esp32s3)] { + impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0); + impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1); + impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2); + impl_channel!(3, super::asynch::interrupt::interrupt_handler_ch3, DMA_IN_CH3, DMA_OUT_CH3); + impl_channel!(4, super::asynch::interrupt::interrupt_handler_ch4, DMA_IN_CH4, DMA_OUT_CH4); + } +} /// GDMA Peripheral /// diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index d29fc575d14..856e0c9a00f 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -131,16 +131,25 @@ impl DmaDescriptor { } } +use enumset::{EnumSet, EnumSetType}; + #[cfg(gdma)] pub use self::gdma::*; #[cfg(pdma)] pub use self::pdma::*; +use crate::{interrupt::InterruptHandler, Mode}; #[cfg(gdma)] mod gdma; #[cfg(pdma)] mod pdma; +#[derive(EnumSetType)] +pub enum DmaInterrupt { + TxDone, + RxDone, +} + const CHUNK_SIZE: usize = 4092; /// Convenience macro to create DMA buffers and descriptors @@ -1285,15 +1294,79 @@ pub trait ChannelTypes { type P: PeripheralMarker; type Tx<'a>: Tx; type Rx<'a>: Rx; + type Binder: InterruptBinder; +} + +pub trait InterruptBinder { + #[cfg(feature = "vectored")] + fn set_isr(handler: InterruptHandler); } /// DMA Channel -pub struct Channel<'d, C> +pub struct Channel<'d, C, MODE> where C: ChannelTypes, + MODE: Mode, { pub tx: C::Tx<'d>, pub(crate) rx: C::Rx<'d>, + phantom: PhantomData, +} + +impl<'d, C> Channel<'d, C, crate::Blocking> +where + C: ChannelTypes, +{ + /// Sets the interrupt handler for TX and RX interrupts, enables them + /// with [crate::interrupt::Priority::max()] + /// + /// Interrupts are not enabled at the peripheral level here. + #[cfg(feature = "vectored")] + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + C::Binder::set_isr(handler); + } + + /// Listen for the given interrupts + pub fn listen(&mut self, interrupts: EnumSet) { + for interrupt in interrupts { + match interrupt { + DmaInterrupt::TxDone => self.tx.listen_ch_out_done(), + DmaInterrupt::RxDone => self.rx.listen_ch_in_done(), + } + } + } + + /// Unlisten the given interrupts + pub fn unlisten(&mut self, interrupts: EnumSet) { + for interrupt in interrupts { + match interrupt { + DmaInterrupt::TxDone => self.tx.unlisten_ch_out_done(), + DmaInterrupt::RxDone => self.rx.unlisten_ch_in_done(), + } + } + } + + /// Gets asserted interrupts + pub fn interrupts(&mut self) -> EnumSet { + let mut res = EnumSet::new(); + if self.tx.is_done() { + res.insert(DmaInterrupt::TxDone); + } + if self.rx.is_done() { + res.insert(DmaInterrupt::RxDone); + } + res + } + + /// Resets asserted interrupts + pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + for interrupt in interrupts { + match interrupt { + DmaInterrupt::TxDone => self.tx.clear_ch_out_done(), + DmaInterrupt::RxDone => self.rx.clear_ch_in_done(), + } + } + } } /// Trait to be implemented for an in progress dma transfer. @@ -1319,7 +1392,6 @@ pub(crate) mod asynch { use core::task::Poll; use super::*; - use crate::macros::interrupt; pub struct DmaTxFuture<'a, TX> { pub(crate) tx: &'a mut TX, @@ -1461,44 +1533,14 @@ pub(crate) mod asynch { } } - #[cfg(esp32c2)] - mod interrupt { - use super::*; - - #[interrupt] - fn DMA_CH0() { - use crate::dma::gdma::{ - Channel0 as Channel, - Channel0RxImpl as ChannelRxImpl, - Channel0TxImpl as ChannelTxImpl, - }; - - if Channel::is_in_done() && Channel::is_listening_in_eof() { - Channel::clear_in_interrupts(); - Channel::unlisten_in_eof(); - ChannelRxImpl::waker().wake() - } - - if Channel::is_out_done() { - Channel::clear_out_interrupts(); - Channel::unlisten_out_eof(); - ChannelTxImpl::waker().wake() - } - - if Channel::is_ch_out_done_set() { - Channel::clear_ch_out_done(); - Channel::unlisten_ch_out_done(); - ChannelTxImpl::waker().wake() - } - } - } + #[cfg(not(any(esp32, esp32s2)))] + pub(crate) mod interrupt { + use procmacros::handler; - #[cfg(esp32c3)] - mod interrupt { use super::*; - #[interrupt] - fn DMA_CH0() { + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_ch0() { use crate::dma::gdma::{ Channel0 as Channel, Channel0RxImpl as ChannelRxImpl, @@ -1511,38 +1553,11 @@ pub(crate) mod asynch { ChannelRxImpl::waker().wake() } - if Channel::is_out_done() { - Channel::clear_out_interrupts(); - Channel::unlisten_out_eof(); - ChannelTxImpl::waker().wake() - } - - if Channel::is_ch_out_done_set() { - Channel::clear_ch_out_done(); - Channel::unlisten_ch_out_done(); - ChannelTxImpl::waker().wake() - } - if Channel::is_ch_in_done_set() { Channel::clear_ch_in_done(); Channel::unlisten_ch_in_done(); ChannelRxImpl::waker().wake() } - } - - #[interrupt] - fn DMA_CH1() { - use crate::dma::gdma::{ - Channel1 as Channel, - Channel1RxImpl as ChannelRxImpl, - Channel1TxImpl as ChannelTxImpl, - }; - - if Channel::is_in_done() && Channel::is_listening_in_eof() { - Channel::clear_in_interrupts(); - Channel::unlisten_in_eof(); - ChannelRxImpl::waker().wake() - } if Channel::is_out_done() { Channel::clear_out_interrupts(); @@ -1555,20 +1570,15 @@ pub(crate) mod asynch { Channel::unlisten_ch_out_done(); ChannelTxImpl::waker().wake() } - - if Channel::is_ch_in_done_set() { - Channel::clear_ch_in_done(); - Channel::unlisten_ch_in_done(); - ChannelRxImpl::waker().wake() - } } - #[interrupt] - fn DMA_CH2() { + #[cfg(not(esp32c2))] + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_ch1() { use crate::dma::gdma::{ - Channel2 as Channel, - Channel2RxImpl as ChannelRxImpl, - Channel2TxImpl as ChannelTxImpl, + Channel1 as Channel, + Channel1RxImpl as ChannelRxImpl, + Channel1TxImpl as ChannelTxImpl, }; if Channel::is_in_done() && Channel::is_listening_in_eof() { @@ -1577,157 +1587,11 @@ pub(crate) mod asynch { ChannelRxImpl::waker().wake() } - if Channel::is_out_done() { - Channel::clear_out_interrupts(); - Channel::unlisten_out_eof(); - ChannelTxImpl::waker().wake() - } - - if Channel::is_ch_out_done_set() { - Channel::clear_ch_out_done(); - Channel::unlisten_ch_out_done(); - ChannelTxImpl::waker().wake() - } - - if Channel::is_ch_in_done_set() { - Channel::clear_ch_in_done(); - Channel::unlisten_ch_in_done(); - ChannelRxImpl::waker().wake() - } - } - } - - #[cfg(any(esp32c6, esp32h2))] - mod interrupt { - use super::*; - - #[interrupt] - fn DMA_IN_CH0() { - use crate::dma::gdma::{Channel0 as Channel, Channel0RxImpl as ChannelRxImpl}; - - if Channel::is_in_done() && Channel::is_listening_in_eof() { - Channel::clear_in_interrupts(); - Channel::unlisten_in_eof(); - ChannelRxImpl::waker().wake() - } - - if Channel::is_ch_in_done_set() { - Channel::clear_ch_in_done(); - Channel::unlisten_ch_in_done(); - ChannelRxImpl::waker().wake() - } - } - - #[interrupt] - fn DMA_OUT_CH0() { - use crate::dma::gdma::{Channel0 as Channel, Channel0TxImpl as ChannelTxImpl}; - - if Channel::is_out_done() { - Channel::clear_out_interrupts(); - Channel::unlisten_out_eof(); - ChannelTxImpl::waker().wake() - } - - if Channel::is_ch_out_done_set() { - Channel::clear_ch_out_done(); - Channel::unlisten_ch_out_done(); - ChannelTxImpl::waker().wake() - } - } - - #[interrupt] - fn DMA_IN_CH1() { - use crate::dma::gdma::{Channel1 as Channel, Channel1RxImpl as ChannelRxImpl}; - - if Channel::is_in_done() && Channel::is_listening_in_eof() { - Channel::clear_in_interrupts(); - Channel::unlisten_in_eof(); - ChannelRxImpl::waker().wake() - } - - if Channel::is_ch_in_done_set() { - Channel::clear_ch_in_done(); - Channel::unlisten_ch_in_done(); - ChannelRxImpl::waker().wake() - } - } - - #[interrupt] - fn DMA_OUT_CH1() { - use crate::dma::gdma::{Channel1 as Channel, Channel1TxImpl as ChannelTxImpl}; - - if Channel::is_out_done() { - Channel::clear_out_interrupts(); - Channel::unlisten_out_eof(); - ChannelTxImpl::waker().wake() - } - - if Channel::is_ch_out_done_set() { - Channel::clear_ch_out_done(); - Channel::unlisten_ch_out_done(); - ChannelTxImpl::waker().wake() - } - } - - #[interrupt] - fn DMA_IN_CH2() { - use crate::dma::gdma::{Channel2 as Channel, Channel2RxImpl as ChannelRxImpl}; - - if Channel::is_in_done() && Channel::is_listening_in_eof() { - Channel::clear_in_interrupts(); - Channel::unlisten_in_eof(); - ChannelRxImpl::waker().wake() - } - - if Channel::is_ch_in_done_set() { - Channel::clear_ch_in_done(); - Channel::unlisten_ch_in_done(); - ChannelRxImpl::waker().wake() - } - } - - #[interrupt] - fn DMA_OUT_CH2() { - use crate::dma::gdma::{Channel2 as Channel, Channel2TxImpl as ChannelTxImpl}; - - if Channel::is_out_done() { - Channel::clear_out_interrupts(); - Channel::unlisten_out_eof(); - ChannelTxImpl::waker().wake() - } - - if Channel::is_ch_out_done_set() { - Channel::clear_ch_out_done(); - Channel::unlisten_ch_out_done(); - ChannelTxImpl::waker().wake() - } - } - } - - #[cfg(esp32s3)] - mod interrupt { - use super::*; - - #[interrupt] - fn DMA_IN_CH0() { - use crate::dma::gdma::{Channel0 as Channel, Channel0RxImpl as ChannelRxImpl}; - - if Channel::is_in_done() && Channel::is_listening_in_eof() { - Channel::clear_in_interrupts(); - Channel::unlisten_in_eof(); - ChannelRxImpl::waker().wake() - } - if Channel::is_ch_in_done_set() { Channel::clear_ch_in_done(); Channel::unlisten_ch_in_done(); ChannelRxImpl::waker().wake() } - } - - #[interrupt] - fn DMA_OUT_CH0() { - use crate::dma::gdma::{Channel0 as Channel, Channel0TxImpl as ChannelTxImpl}; if Channel::is_out_done() { Channel::clear_out_interrupts(); @@ -1742,9 +1606,14 @@ pub(crate) mod asynch { } } - #[interrupt] - fn DMA_IN_CH1() { - use crate::dma::gdma::{Channel1 as Channel, Channel1RxImpl as ChannelRxImpl}; + #[cfg(not(esp32c2))] + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_ch2() { + use crate::dma::gdma::{ + Channel2 as Channel, + Channel2RxImpl as ChannelRxImpl, + Channel2TxImpl as ChannelTxImpl, + }; if Channel::is_in_done() && Channel::is_listening_in_eof() { Channel::clear_in_interrupts(); @@ -1757,11 +1626,6 @@ pub(crate) mod asynch { Channel::unlisten_ch_in_done(); ChannelRxImpl::waker().wake() } - } - - #[interrupt] - fn DMA_OUT_CH1() { - use crate::dma::gdma::{Channel1 as Channel, Channel1TxImpl as ChannelTxImpl}; if Channel::is_out_done() { Channel::clear_out_interrupts(); @@ -1776,9 +1640,14 @@ pub(crate) mod asynch { } } - #[interrupt] - fn DMA_IN_CH3() { - use crate::dma::gdma::{Channel3 as Channel, Channel3RxImpl as ChannelRxImpl}; + #[cfg(esp32s3)] + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_ch3() { + use crate::dma::gdma::{ + Channel3 as Channel, + Channel3RxImpl as ChannelRxImpl, + Channel3TxImpl as ChannelTxImpl, + }; if Channel::is_in_done() && Channel::is_listening_in_eof() { Channel::clear_in_interrupts(); @@ -1791,11 +1660,6 @@ pub(crate) mod asynch { Channel::unlisten_ch_in_done(); ChannelRxImpl::waker().wake() } - } - - #[interrupt] - fn DMA_OUT_CH3() { - use crate::dma::gdma::{Channel3 as Channel, Channel3TxImpl as ChannelTxImpl}; if Channel::is_out_done() { Channel::clear_out_interrupts(); @@ -1810,9 +1674,14 @@ pub(crate) mod asynch { } } - #[interrupt] - fn DMA_IN_CH4() { - use crate::dma::gdma::{Channel4 as Channel, Channel4RxImpl as ChannelRxImpl}; + #[cfg(esp32s3)] + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_ch4() { + use crate::dma::gdma::{ + Channel4 as Channel, + Channel4RxImpl as ChannelRxImpl, + Channel4TxImpl as ChannelTxImpl, + }; if Channel::is_in_done() && Channel::is_listening_in_eof() { Channel::clear_in_interrupts(); @@ -1825,11 +1694,6 @@ pub(crate) mod asynch { Channel::unlisten_ch_in_done(); ChannelRxImpl::waker().wake() } - } - - #[interrupt] - fn DMA_OUT_CH4() { - use crate::dma::gdma::{Channel4 as Channel, Channel4TxImpl as ChannelTxImpl}; if Channel::is_out_done() { Channel::clear_out_interrupts(); @@ -1846,11 +1710,13 @@ pub(crate) mod asynch { } #[cfg(any(esp32, esp32s2))] - mod interrupt { + pub(crate) mod interrupt { + use procmacros::handler; + use super::*; - #[interrupt] - fn SPI2_DMA() { + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_spi2_dma() { use crate::dma::pdma::{ Spi2DmaChannel as Channel, Spi2DmaChannelRxImpl as ChannelRxImpl, @@ -1882,8 +1748,8 @@ pub(crate) mod asynch { } } - #[interrupt] - fn SPI3_DMA() { + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_spi3_dma() { use crate::dma::pdma::{ Spi3DmaChannel as Channel, Spi3DmaChannelRxImpl as ChannelRxImpl, @@ -1915,8 +1781,8 @@ pub(crate) mod asynch { } } - #[interrupt] - fn I2S0() { + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_i2s0() { use crate::dma::pdma::{ I2s0DmaChannel as Channel, I2s0DmaChannelRxImpl as ChannelRxImpl, @@ -1948,9 +1814,9 @@ pub(crate) mod asynch { } } - #[cfg(esp32)] - #[interrupt] - fn I2S1() { + #[cfg(i2s1)] + #[handler(priority = crate::interrupt::Priority::max())] + pub(crate) fn interrupt_handler_i2s1() { use crate::dma::pdma::{ I2s1DmaChannel as Channel, I2s1DmaChannelRxImpl as ChannelRxImpl, diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index d278647cd2f..bf4c9f6a76d 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -22,6 +22,18 @@ use crate::{ macro_rules! ImplSpiChannel { ($num: literal) => { paste::paste! { + #[non_exhaustive] + pub struct [] {} + + impl InterruptBinder for [] { + #[cfg(feature = "vectored")] + 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(); + } + } + #[non_exhaustive] pub struct [] {} @@ -29,6 +41,7 @@ macro_rules! ImplSpiChannel { type P = []; type Tx<'a> = ChannelTx<'a,[], []>; type Rx<'a> = ChannelRx<'a,[], []>; + type Binder = []; } impl RegisterAccess for [] { @@ -301,7 +314,7 @@ macro_rules! ImplSpiChannel { pub struct [] {} impl [] { - /// Configure the channel for use + /// Configure the channel for use with blocking APIs /// /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to /// transfer buffers of size `1..=4092`, you need 1 descriptor. @@ -311,7 +324,7 @@ macro_rules! ImplSpiChannel { tx_descriptors: &'a mut [DmaDescriptor], rx_descriptors: &'a mut [DmaDescriptor], priority: DmaPriority, - ) -> Channel<'a, []> { + ) -> Channel<'a, [], $crate::Blocking> { let mut tx_impl = [] {}; tx_impl.init(burst_mode, priority); @@ -321,6 +334,34 @@ macro_rules! ImplSpiChannel { Channel { tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode), + phantom: PhantomData, + } + } + + /// Configure the channel for use with async APIs + /// + /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to + /// transfer buffers of size `1..=4092`, you need 1 descriptor. + #[cfg(feature = "async")] + pub fn configure_for_async<'a>( + self, + burst_mode: bool, + tx_descriptors: &'a mut [DmaDescriptor], + rx_descriptors: &'a mut [DmaDescriptor], + priority: DmaPriority, + ) -> Channel<'a, [], $crate::Async> { + let mut tx_impl = [] {}; + tx_impl.init(burst_mode, priority); + + let mut rx_impl = [] {}; + rx_impl.init(burst_mode, priority); + + <[] as ChannelTypes>::Binder::set_isr(super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]); + + Channel { + tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), + rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode), + phantom: PhantomData, } } } @@ -331,12 +372,25 @@ macro_rules! ImplSpiChannel { macro_rules! ImplI2sChannel { ($num: literal, $peripheral: literal) => { paste::paste! { + #[non_exhaustive] + pub struct [] {} + + impl InterruptBinder for [] { + #[cfg(feature = "vectored")] + 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(); + } + } + pub struct [] {} impl ChannelTypes for [] { type P = []; type Tx<'a> = ChannelTx<'a,[], []>; type Rx<'a> = ChannelRx<'a,[], []>; + type Binder = []; } impl RegisterAccess for [] { @@ -587,7 +641,7 @@ macro_rules! ImplI2sChannel { pub struct [] {} impl [] { - /// Configure the channel for use + /// Configure the channel for use with blocking APIs /// /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to /// transfer buffers of size `1..=4092`, you need 1 descriptor. @@ -597,7 +651,7 @@ macro_rules! ImplI2sChannel { tx_descriptors: &'a mut [DmaDescriptor], rx_descriptors: &'a mut [DmaDescriptor], priority: DmaPriority, - ) -> Channel<'a, []> { + ) -> Channel<'a, [], $crate::Blocking> { let mut tx_impl = [] {}; tx_impl.init(burst_mode, priority); @@ -607,6 +661,34 @@ macro_rules! ImplI2sChannel { Channel { tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode), + phantom: PhantomData, + } + } + + /// Configure the channel for use with async APIs + /// + /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to + /// transfer buffers of size `1..=4092`, you need 1 descriptor. + #[cfg(feature = "async")] + pub fn configure_for_async<'a>( + self, + burst_mode: bool, + tx_descriptors: &'a mut [DmaDescriptor], + rx_descriptors: &'a mut [DmaDescriptor], + priority: DmaPriority, + ) -> Channel<'a, [], $crate::Async> { + let mut tx_impl = [] {}; + tx_impl.init(burst_mode, priority); + + let mut rx_impl = [] {}; + rx_impl.init(burst_mode, priority); + + <[] as ChannelTypes>::Binder::set_isr(super::asynch::interrupt::[< interrupt_handler_i2s $num >]); + + Channel { + tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), + rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode), + phantom: PhantomData, } } } diff --git a/esp-hal/src/embassy/mod.rs b/esp-hal/src/embassy/mod.rs index ef3b907f06b..883f4f5e112 100644 --- a/esp-hal/src/embassy/mod.rs +++ b/esp-hal/src/embassy/mod.rs @@ -111,55 +111,12 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) { // only enable interrupts if the async feature is present #[cfg(feature = "async")] { - #[cfg(any(esp32s3, esp32c6, esp32h2))] - crate::interrupt::enable(Interrupt::DMA_IN_CH0, Priority::max()).unwrap(); - #[cfg(any(esp32s3, esp32c6, esp32h2))] - crate::interrupt::enable(Interrupt::DMA_OUT_CH0, Priority::max()).unwrap(); - #[cfg(any(esp32s3, esp32c6, esp32h2))] - crate::interrupt::enable(Interrupt::DMA_IN_CH1, Priority::max()).unwrap(); - #[cfg(any(esp32s3, esp32c6, esp32h2))] - crate::interrupt::enable(Interrupt::DMA_OUT_CH1, Priority::max()).unwrap(); - #[cfg(any(esp32s3, esp32c6, esp32h2))] - crate::interrupt::enable(Interrupt::DMA_IN_CH2, Priority::max()).unwrap(); - #[cfg(any(esp32s3, esp32c6, esp32h2))] - crate::interrupt::enable(Interrupt::DMA_OUT_CH2, Priority::max()).unwrap(); - - #[cfg(esp32s3)] - crate::interrupt::enable(Interrupt::DMA_IN_CH3, Priority::max()).unwrap(); - #[cfg(esp32s3)] - crate::interrupt::enable(Interrupt::DMA_OUT_CH3, Priority::max()).unwrap(); - - #[cfg(any(esp32c3, esp32c2))] - crate::interrupt::enable(Interrupt::DMA_CH0, Priority::max()).unwrap(); - #[cfg(esp32c3)] - crate::interrupt::enable(Interrupt::DMA_CH1, Priority::max()).unwrap(); - #[cfg(esp32c3)] - crate::interrupt::enable(Interrupt::DMA_CH2, Priority::max()).unwrap(); - - #[cfg(esp32)] - crate::interrupt::enable(Interrupt::SPI1_DMA, Priority::max()).unwrap(); - #[cfg(any(esp32, esp32s2))] - crate::interrupt::enable(Interrupt::SPI2_DMA, Priority::max()).unwrap(); - #[cfg(any(esp32, esp32s2))] - crate::interrupt::enable(Interrupt::SPI3_DMA, Priority::max()).unwrap(); - #[cfg(esp32s2)] - crate::interrupt::enable(Interrupt::SPI4_DMA, Priority::max()).unwrap(); - - #[cfg(i2s0)] - crate::interrupt::enable(Interrupt::I2S0, Priority::min()).unwrap(); - #[cfg(i2s1)] - crate::interrupt::enable(Interrupt::I2S1, Priority::min()).unwrap(); + #[cfg(rmt)] + crate::interrupt::enable(Interrupt::RMT, Priority::min()).unwrap(); #[cfg(usb_device)] crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap(); - #[cfg(all(parl_io, not(esp32h2)))] - crate::interrupt::enable(Interrupt::PARL_IO, Priority::min()).unwrap(); - #[cfg(all(parl_io, esp32h2))] - crate::interrupt::enable(Interrupt::PARL_IO_RX, Priority::min()).unwrap(); - #[cfg(all(parl_io, esp32h2))] - crate::interrupt::enable(Interrupt::PARL_IO_TX, Priority::min()).unwrap(); - crate::interrupt::enable(Interrupt::I2C_EXT0, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap(); diff --git a/esp-hal/src/gpio.rs b/esp-hal/src/gpio.rs index 55f68b717ab..95d240c06c1 100644 --- a/esp-hal/src/gpio.rs +++ b/esp-hal/src/gpio.rs @@ -25,7 +25,6 @@ use core::{cell::Cell, convert::Infallible, marker::PhantomData}; use critical_section::Mutex; -use procmacros::handler; #[cfg(any(adc, dac))] pub(crate) use crate::analog; @@ -1876,7 +1875,8 @@ pub struct IO { impl IO { /// Initialize the I/O driver. pub fn new(mut gpio: GPIO, io_mux: IO_MUX) -> Self { - gpio.bind_gpio_interrupt(gpio_interrupt_handler.handler()); + gpio.bind_gpio_interrupt(gpio_interrupt_handler); + let pins = gpio.split(); IO { @@ -1910,8 +1910,7 @@ impl IO { } } -#[handler] -fn gpio_interrupt_handler() { +extern "C" fn gpio_interrupt_handler() { if let Some(user_handler) = critical_section::with(|cs| USER_INTERRUPT_HANDLER.borrow(cs).get()) { user_handler.call(); diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index 5fb02c46f22..2d3c8b9e56e 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -68,6 +68,7 @@ use core::marker::PhantomData; use embedded_dma::{ReadBuffer, WriteBuffer}; +use enumset::{EnumSet, EnumSetType}; use private::*; #[cfg(any(esp32, esp32s3))] @@ -85,11 +86,23 @@ use crate::{ TxPrivate, }, gpio::OutputPin, + interrupt::InterruptHandler, into_ref, peripheral::Peripheral, system::PeripheralClockControl, + Mode, }; +#[derive(EnumSetType)] +pub enum I2sInterrupt { + TxHung, + RxHung, + #[cfg(not(any(esp32, esp32s2)))] + TxDone, + #[cfg(not(any(esp32, esp32s2)))] + RxDone, +} + #[cfg(any(esp32, esp32s2, esp32s3))] const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6; @@ -199,18 +212,20 @@ impl DataFormat { /// An in-progress DMA write transfer. #[must_use] -pub struct I2sWriteDmaTransfer<'t, 'd, T, CH> +pub struct I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { - i2s_tx: &'t mut I2sTx<'d, T, CH>, + i2s_tx: &'t mut I2sTx<'d, T, CH, DmaMode>, } -impl<'t, 'd, T, CH> I2sWriteDmaTransfer<'t, 'd, T, CH> +impl<'t, 'd, T, CH, DmaMode> I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { /// Amount of bytes which can be pushed. /// Only useful for circular DMA transfers @@ -246,10 +261,11 @@ where } } -impl<'t, 'd, T, CH> DmaTransfer for I2sWriteDmaTransfer<'t, 'd, T, CH> +impl<'t, 'd, T, CH, DmaMode> DmaTransfer for I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { /// Wait for the DMA transfer to complete fn wait(self) -> Result<(), DmaError> { @@ -270,10 +286,11 @@ where } } -impl<'t, 'd, T, CH> Drop for I2sWriteDmaTransfer<'t, 'd, T, CH> +impl<'t, 'd, T, CH, DmaMode> Drop for I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn drop(&mut self) { self.i2s_tx.wait_tx_dma_done().ok(); @@ -286,10 +303,11 @@ pub trait I2sWrite { } /// Initiate a DMA tx transfer -pub trait I2sWriteDma<'d, T, CH, TXBUF> +pub trait I2sWriteDma<'d, T, CH, TXBUF, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { /// Write I2S. /// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA @@ -297,7 +315,7 @@ where fn write_dma<'t>( &'t mut self, words: &'t TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer; @@ -306,25 +324,27 @@ where fn write_dma_circular<'t>( &'t mut self, words: &'t TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer; } /// An in-progress DMA read transfer. #[must_use] -pub struct I2sReadDmaTransfer<'t, 'd, T, CH> +pub struct I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { - i2s_rx: &'t mut I2sRx<'d, T, CH>, + i2s_rx: &'t mut I2sRx<'d, T, CH, DmaMode>, } -impl<'t, 'd, T, CH> I2sReadDmaTransfer<'t, 'd, T, CH> +impl<'t, 'd, T, CH, DmaMode> I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { /// Amount of bytes which can be popped pub fn available(&mut self) -> usize { @@ -352,10 +372,11 @@ where } } -impl<'t, 'd, T, CH> DmaTransfer for I2sReadDmaTransfer<'t, 'd, T, CH> +impl<'t, 'd, T, CH, DmaMode> DmaTransfer for I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { /// Wait for the DMA transfer to complete fn wait(self) -> Result<(), DmaError> { @@ -376,10 +397,11 @@ where } } -impl<'t, T, CH> Drop for I2sReadDmaTransfer<'t, '_, T, CH> +impl<'t, T, CH, DmaMode> Drop for I2sReadDmaTransfer<'t, '_, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn drop(&mut self) { self.i2s_rx.wait_rx_dma_done().ok(); @@ -392,10 +414,11 @@ pub trait I2sRead { } /// Initiate a DMA rx transfer -pub trait I2sReadDma<'d, T, CH, RXBUF> +pub trait I2sReadDma<'d, T, CH, RXBUF, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { /// Read I2S. /// Returns [I2sReadDmaTransfer] which represents the in-progress DMA @@ -403,7 +426,7 @@ where fn read_dma<'t>( &'t mut self, words: &'t mut RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer; @@ -413,32 +436,35 @@ where fn read_dma_circular<'t>( &'t mut self, words: &'t mut RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer; } /// Instance of the I2S peripheral driver -pub struct I2s<'d, I, CH> +pub struct I2s<'d, I, CH, DmaMode> where I: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { - pub i2s_tx: TxCreator<'d, I, CH>, - pub i2s_rx: RxCreator<'d, I, CH>, + pub i2s_tx: TxCreator<'d, I, CH, DmaMode>, + pub i2s_rx: RxCreator<'d, I, CH, DmaMode>, + phantom: PhantomData, } -impl<'d, I, CH> I2s<'d, I, CH> +impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode> where I: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn new_internal( _i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - mut channel: Channel<'d, CH>, + mut channel: Channel<'d, CH, DmaMode>, clocks: &Clocks, ) -> Self { // on ESP32-C3 / ESP32-S3 and later RX and TX are independent and @@ -461,19 +487,58 @@ where i2s_tx: TxCreator { register_access: PhantomData, tx_channel: channel.tx, + phantom: PhantomData, }, i2s_rx: RxCreator { register_access: PhantomData, rx_channel: channel.rx, + phantom: PhantomData, }, + phantom: PhantomData, } } } -impl<'d, I, CH> I2s<'d, I, CH> +impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode> where I: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, +{ + /// Sets the interrupt handler, enables it with + /// [crate::interrupt::Priority::min()] + /// + /// Interrupts are not enabled at the peripheral level here. + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + I::set_interrupt_handler(handler); + } + + /// Listen for the given interrupts + pub fn listen(&mut self, interrupts: EnumSet) { + I::listen(interrupts); + } + + /// Unlisten the given interrupts + pub fn unlisten(&mut self, interrupts: EnumSet) { + I::unlisten(interrupts); + } + + /// Gets asserted interrupts + pub fn interrupts(&mut self) -> EnumSet { + I::interrupts() + } + + /// Resets asserted interrupts + pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + I::clear_interrupts(interrupts); + } +} + +impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode> +where + I: RegisterAccess, + CH: ChannelTypes, + DmaMode: Mode, { /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral @@ -482,12 +547,13 @@ where standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH>, + channel: Channel<'d, CH, DmaMode>, clocks: &Clocks, ) -> Self where I: I2s0Instance, CH::P: I2sPeripheral + I2s0Peripheral, + DmaMode: Mode, { Self::new_internal(i2s, standard, data_format, sample_rate, channel, clocks) } @@ -500,7 +566,7 @@ where standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH>, + channel: Channel<'d, CH, DmaMode>, clocks: &Clocks, ) -> Self where @@ -519,34 +585,38 @@ where } /// I2S TX channel -pub struct I2sTx<'d, T, CH> +pub struct I2sTx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, { register_access: PhantomData, tx_channel: CH::Tx<'d>, + phantom: PhantomData, } -impl<'d, T, CH> core::fmt::Debug for I2sTx<'d, T, CH> +impl<'d, T, CH, DmaMode> core::fmt::Debug for I2sTx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("I2sTx").finish() } } -impl<'d, T, CH> I2sTx<'d, T, CH> +impl<'d, T, CH, DmaMode> I2sTx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn new(tx_channel: CH::Tx<'d>) -> Self { Self { register_access: PhantomData, tx_channel, + phantom: PhantomData, } } @@ -578,9 +648,10 @@ where &'t mut self, words: &'t TXBUF, circular: bool, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer, + DmaMode: Mode, { let (ptr, len) = unsafe { words.read_buffer() }; @@ -635,11 +706,12 @@ where } } -impl<'d, T, W, CH> I2sWrite for I2sTx<'d, T, CH> +impl<'d, T, W, CH, DmaMode> I2sWrite for I2sTx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, W: AcceptedWord, + DmaMode: Mode, { fn write(&mut self, words: &[W]) -> Result<(), Error> { self.write_bytes(unsafe { @@ -651,15 +723,16 @@ where } } -impl<'d, T, CH, TXBUF> I2sWriteDma<'d, T, CH, TXBUF> for I2sTx<'d, T, CH> +impl<'d, T, CH, TXBUF, DmaMode> I2sWriteDma<'d, T, CH, TXBUF, DmaMode> for I2sTx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn write_dma<'t>( &'t mut self, words: &'t TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer, { @@ -669,7 +742,7 @@ where fn write_dma_circular<'t>( &'t mut self, words: &'t TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer, { @@ -678,34 +751,39 @@ where } /// I2S RX channel -pub struct I2sRx<'d, T, CH> +pub struct I2sRx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { register_access: PhantomData, rx_channel: CH::Rx<'d>, + phantom: PhantomData, } -impl<'d, T, CH> core::fmt::Debug for I2sRx<'d, T, CH> +impl<'d, T, CH, DmaMode> core::fmt::Debug for I2sRx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("I2sRx").finish() } } -impl<'d, T, CH> I2sRx<'d, T, CH> +impl<'d, T, CH, DmaMode> I2sRx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn new(rx_channel: CH::Rx<'d>) -> Self { Self { register_access: PhantomData, rx_channel, + phantom: PhantomData, } } @@ -737,7 +815,7 @@ where &'t mut self, words: &'t mut RXBUF, circular: bool, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer, { @@ -809,11 +887,12 @@ where } } -impl<'d, W, T, CH> I2sRead for I2sRx<'d, T, CH> +impl<'d, W, T, CH, DmaMode> I2sRead for I2sRx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, W: AcceptedWord, + DmaMode: Mode, { fn read(&mut self, words: &mut [W]) -> Result<(), Error> { if core::mem::size_of_val(words) > 4096 || words.is_empty() { @@ -829,15 +908,16 @@ where } } -impl<'d, T, CH, RXBUF> I2sReadDma<'d, T, CH, RXBUF> for I2sRx<'d, T, CH> +impl<'d, T, CH, RXBUF, DmaMode> I2sReadDma<'d, T, CH, RXBUF, DmaMode> for I2sRx<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { fn read_dma<'t>( &'t mut self, words: &'t mut RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer, { @@ -847,7 +927,7 @@ where fn read_dma_circular<'t>( &'t mut self, words: &'t mut RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer, { @@ -860,9 +940,18 @@ pub trait RegisterAccess: RegisterAccessPrivate {} mod private { use core::marker::PhantomData; + use enumset::EnumSet; use fugit::HertzU32; - use super::{DataFormat, I2sRx, I2sTx, RegisterAccess, Standard, I2S_LL_MCLK_DIVIDER_MAX}; + use super::{ + DataFormat, + I2sInterrupt, + I2sRx, + I2sTx, + RegisterAccess, + Standard, + I2S_LL_MCLK_DIVIDER_MAX, + }; #[cfg(not(any(esp32, esp32s3)))] use crate::peripherals::i2s0::RegisterBlock; // on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features @@ -873,26 +962,31 @@ mod private { clock::Clocks, dma::{ChannelTypes, DmaPeripheral}, gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, + interrupt::InterruptHandler, into_ref, peripherals::I2S0, system::Peripheral, + Mode, }; - pub struct TxCreator<'d, T, CH> + pub struct TxCreator<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { pub register_access: PhantomData, pub tx_channel: CH::Tx<'d>, + pub(crate) phantom: PhantomData, } - impl<'d, T, CH> TxCreator<'d, T, CH> + impl<'d, T, CH, DmaMode> TxCreator<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { - pub fn build(self) -> I2sTx<'d, T, CH> { + pub fn build(self) -> I2sTx<'d, T, CH, DmaMode> { I2sTx::new(self.tx_channel) } @@ -927,21 +1021,24 @@ mod private { } } - pub struct RxCreator<'d, T, CH> + pub struct RxCreator<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { pub register_access: PhantomData, pub rx_channel: CH::Rx<'d>, + pub(crate) phantom: PhantomData, } - impl<'d, T, CH> RxCreator<'d, T, CH> + impl<'d, T, CH, DmaMode> RxCreator<'d, T, CH, DmaMode> where T: RegisterAccess, CH: ChannelTypes, + DmaMode: Mode, { - pub fn build(self) -> I2sRx<'d, T, CH> { + pub fn build(self) -> I2sRx<'d, T, CH, DmaMode> { I2sRx::new(self.rx_channel) } @@ -1002,6 +1099,68 @@ mod private { #[cfg(any(esp32, esp32s2))] pub trait RegisterAccessPrivate: Signals + RegBlock { + fn set_interrupt_handler(handler: InterruptHandler); + + fn listen(interrupts: EnumSet) { + let reg_block = Self::register_block(); + + for interrupt in interrupts { + match interrupt { + I2sInterrupt::TxHung => reg_block + .int_ena() + .modify(|_, w| w.tx_hung_int_ena().set_bit()), + I2sInterrupt::RxHung => reg_block + .int_ena() + .modify(|_, w| w.rx_hung_int_ena().set_bit()), + } + } + } + + fn unlisten(interrupts: EnumSet) { + let reg_block = Self::register_block(); + + for interrupt in interrupts { + match interrupt { + I2sInterrupt::TxHung => reg_block + .int_ena() + .modify(|_, w| w.tx_hung_int_ena().clear_bit()), + I2sInterrupt::RxHung => reg_block + .int_ena() + .modify(|_, w| w.rx_hung_int_ena().clear_bit()), + } + } + } + + fn interrupts() -> EnumSet { + let mut res = EnumSet::new(); + let reg_block = Self::register_block(); + let ints = reg_block.int_st().read(); + + if ints.tx_hung_int_st().bit() { + res.insert(I2sInterrupt::TxHung); + } + if ints.rx_hung_int_st().bit() { + res.insert(I2sInterrupt::RxHung); + } + + res + } + + fn clear_interrupts(interrupts: EnumSet) { + let reg_block = Self::register_block(); + + for interrupt in interrupts { + match interrupt { + I2sInterrupt::TxHung => { + reg_block.int_clr().write(|w| w.tx_hung_int_clr().set_bit()) + } + I2sInterrupt::RxHung => { + reg_block.int_clr().write(|w| w.rx_hung_int_clr().set_bit()) + } + } + } + } + fn set_clock(clock_settings: I2sClockDividers) { let i2s = Self::register_block(); @@ -1193,6 +1352,92 @@ mod private { #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] pub trait RegisterAccessPrivate: Signals + RegBlock { + fn set_interrupt_handler(handler: InterruptHandler); + + fn listen(interrupts: EnumSet) { + let reg_block = Self::register_block(); + + for interrupt in interrupts { + match interrupt { + I2sInterrupt::TxHung => reg_block + .int_ena() + .modify(|_, w| w.tx_hung_int_ena().set_bit()), + I2sInterrupt::RxHung => reg_block + .int_ena() + .modify(|_, w| w.rx_hung_int_ena().set_bit()), + I2sInterrupt::TxDone => reg_block + .int_ena() + .modify(|_, w| w.tx_done_int_ena().set_bit()), + I2sInterrupt::RxDone => reg_block + .int_ena() + .modify(|_, w| w.rx_done_int_ena().set_bit()), + } + } + } + + fn unlisten(interrupts: EnumSet) { + let reg_block = Self::register_block(); + + for interrupt in interrupts { + match interrupt { + I2sInterrupt::TxHung => reg_block + .int_ena() + .modify(|_, w| w.tx_hung_int_ena().clear_bit()), + I2sInterrupt::RxHung => reg_block + .int_ena() + .modify(|_, w| w.rx_hung_int_ena().clear_bit()), + I2sInterrupt::TxDone => reg_block + .int_ena() + .modify(|_, w| w.tx_done_int_ena().clear_bit()), + I2sInterrupt::RxDone => reg_block + .int_ena() + .modify(|_, w| w.rx_done_int_ena().clear_bit()), + } + } + } + + fn interrupts() -> EnumSet { + let mut res = EnumSet::new(); + let reg_block = Self::register_block(); + let ints = reg_block.int_st().read(); + + if ints.tx_hung_int_st().bit() { + res.insert(I2sInterrupt::TxHung); + } + if ints.rx_hung_int_st().bit() { + res.insert(I2sInterrupt::RxHung); + } + if ints.tx_done_int_st().bit() { + res.insert(I2sInterrupt::TxDone); + } + if ints.rx_done_int_st().bit() { + res.insert(I2sInterrupt::RxDone); + } + + res + } + + fn clear_interrupts(interrupts: EnumSet) { + let reg_block = Self::register_block(); + + for interrupt in interrupts { + match interrupt { + I2sInterrupt::TxHung => { + reg_block.int_clr().write(|w| w.tx_hung_int_clr().set_bit()) + } + I2sInterrupt::RxHung => { + reg_block.int_clr().write(|w| w.rx_hung_int_clr().set_bit()) + } + I2sInterrupt::TxDone => { + reg_block.int_clr().write(|w| w.tx_done_int_clr().set_bit()) + } + I2sInterrupt::RxDone => { + reg_block.int_clr().write(|w| w.rx_done_int_clr().set_bit()) + } + } + } + } + #[cfg(any(esp32c3, esp32s3))] fn set_clock(clock_settings: I2sClockDividers) { let i2s = Self::register_block(); @@ -1870,11 +2115,23 @@ mod private { } } - impl RegisterAccessPrivate for I2S0 {} + impl RegisterAccessPrivate for I2S0 { + fn set_interrupt_handler(handler: InterruptHandler) { + unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::I2S0, handler.priority()) + .unwrap(); + } + } impl super::RegisterAccess for I2S0 {} #[cfg(any(esp32s3, esp32))] - impl RegisterAccessPrivate for I2S1 {} + impl RegisterAccessPrivate for I2S1 { + fn set_interrupt_handler(handler: InterruptHandler) { + unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::I2S1, handler.priority()) + .unwrap(); + } + } #[cfg(any(esp32s3, esp32))] impl super::RegisterAccess for I2S1 {} @@ -1970,11 +2227,14 @@ pub mod asynch { use embedded_dma::{ReadBuffer, WriteBuffer}; use super::{Error, I2sRx, I2sTx, RegisterAccess}; - use crate::dma::{ - asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture}, - ChannelTypes, - RxPrivate, - TxPrivate, + use crate::{ + dma::{ + asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture}, + ChannelTypes, + RxPrivate, + TxPrivate, + }, + Async, }; /// Initiate an async DMA tx transfer @@ -1995,7 +2255,7 @@ pub mod asynch { TXBUF: ReadBuffer; } - impl<'d, T, CH> I2sWriteDmaAsync<'d, T, CH> for super::I2sTx<'d, T, CH> + impl<'d, T, CH> I2sWriteDmaAsync<'d, T, CH> for super::I2sTx<'d, T, CH, Async> where T: RegisterAccess, CH: ChannelTypes, @@ -2039,7 +2299,7 @@ pub mod asynch { T: RegisterAccess, CH: ChannelTypes, { - i2s_tx: I2sTx<'d, T, CH>, + i2s_tx: I2sTx<'d, T, CH, Async>, _buffer: BUFFER, } @@ -2102,7 +2362,7 @@ pub mod asynch { RXBUF: WriteBuffer; } - impl<'d, T, CH> I2sReadDmaAsync<'d, T, CH> for super::I2sRx<'d, T, CH> + impl<'d, T, CH> I2sReadDmaAsync<'d, T, CH> for super::I2sRx<'d, T, CH, Async> where T: RegisterAccess, CH: ChannelTypes, @@ -2146,7 +2406,7 @@ pub mod asynch { T: RegisterAccess, CH: ChannelTypes, { - i2s_rx: I2sRx<'d, T, CH>, + i2s_rx: I2sRx<'d, T, CH, Async>, _buffer: BUFFER, } diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 032b98ca0c8..1fba3429aae 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -77,7 +77,10 @@ //! transfer.wait().unwrap(); //! ``` +use core::marker::PhantomData; + use embedded_dma::{ReadBuffer, WriteBuffer}; +use enumset::{EnumSet, EnumSetType}; use fugit::HertzU32; use peripheral::PeripheralRef; use private::*; @@ -86,14 +89,24 @@ use crate::{ clock::Clocks, dma::{Channel, ChannelTypes, DmaError, DmaPeripheral, ParlIoPeripheral, RxPrivate, TxPrivate}, gpio::{InputPin, OutputPin}, + interrupt::InterruptHandler, peripheral::{self, Peripheral}, peripherals, system::PeripheralClockControl, + Blocking, + Mode, }; #[allow(unused)] const MAX_DMA_SIZE: usize = 32736; +#[derive(EnumSetType)] +pub enum ParlIoInterrupt { + TxFifoReEmpty, + RxFifoWOvf, + TxEof, +} + /// Parallel IO errors #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -837,9 +850,10 @@ impl<'d, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15> { } -impl<'d, CH> TxCreatorFullDuplex<'d, CH> +impl<'d, CH, DM> TxCreatorFullDuplex<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub fn with_config( self, @@ -848,7 +862,7 @@ where idle_value: u16, sample_edge: SampleEdge, bit_order: BitPackOrder, - ) -> Result, Error> + ) -> Result, Error> where P: FullDuplex + TxPins + ConfigurePins, CP: TxClkPin, @@ -864,13 +878,15 @@ where tx_channel: self.tx_channel, _pins: tx_pins, _clk_pin: clk_pin, + phantom: PhantomData, }) } } -impl<'d, CH> TxCreator<'d, CH> +impl<'d, CH, DM> TxCreator<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub fn with_config( self, @@ -879,7 +895,7 @@ where idle_value: u16, sample_edge: SampleEdge, bit_order: BitPackOrder, - ) -> Result, Error> + ) -> Result, Error> where P: TxPins + ConfigurePins, CP: TxClkPin, @@ -895,36 +911,41 @@ where tx_channel: self.tx_channel, _pins: tx_pins, _clk_pin: clk_pin, + phantom: PhantomData, }) } } /// Parallel IO TX channel -pub struct ParlIoTx<'d, CH, P, CP> +pub struct ParlIoTx<'d, CH, P, CP, DM> where CH: ChannelTypes, P: TxPins + ConfigurePins, CP: TxClkPin, + DM: Mode, { tx_channel: CH::Tx<'d>, _pins: P, _clk_pin: CP, + phantom: PhantomData, } -impl<'d, CH, P, CP> core::fmt::Debug for ParlIoTx<'d, CH, P, CP> +impl<'d, CH, P, CP, DM> core::fmt::Debug for ParlIoTx<'d, CH, P, CP, DM> where CH: ChannelTypes, P: TxPins + ConfigurePins, CP: TxClkPin, + DM: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("ParlIoTx").finish() } } -impl<'d, CH> RxCreatorFullDuplex<'d, CH> +impl<'d, CH, DM> RxCreatorFullDuplex<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub fn with_config( self, @@ -932,7 +953,7 @@ where mut clk_pin: CP, bit_order: BitPackOrder, timeout_ticks: Option, - ) -> Result, Error> + ) -> Result, Error> where P: FullDuplex + RxPins + ConfigurePins, CP: RxClkPin, @@ -947,13 +968,15 @@ where rx_channel: self.rx_channel, _pins: rx_pins, _clk_pin: clk_pin, + phantom: PhantomData, }) } } -impl<'d, CH> RxCreator<'d, CH> +impl<'d, CH, DM> RxCreator<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub fn with_config( self, @@ -961,7 +984,7 @@ where mut clk_pin: CP, bit_order: BitPackOrder, timeout_ticks: Option, - ) -> Result, Error> + ) -> Result, Error> where P: RxPins + ConfigurePins, CP: RxClkPin, @@ -976,142 +999,343 @@ where rx_channel: self.rx_channel, _pins: rx_pins, _clk_pin: clk_pin, + phantom: PhantomData, }) } } /// Parallel IO RX channel -pub struct ParlIoRx<'d, CH, P, CP> +pub struct ParlIoRx<'d, CH, P, CP, DM> where CH: ChannelTypes, P: RxPins + ConfigurePins, CP: RxClkPin, + DM: Mode, { rx_channel: CH::Rx<'d>, _pins: P, _clk_pin: CP, + phantom: PhantomData, } -impl<'d, CH, P, CP> core::fmt::Debug for ParlIoRx<'d, CH, P, CP> +impl<'d, CH, P, CP, DM> core::fmt::Debug for ParlIoRx<'d, CH, P, CP, DM> where CH: ChannelTypes, P: RxPins + ConfigurePins, CP: RxClkPin, + DM: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("ParlIoTx").finish() } } +fn internal_set_interrupt_handler(handler: InterruptHandler) { + #[cfg(esp32c6)] + { + unsafe { crate::peripherals::PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler()); + + crate::interrupt::enable(crate::peripherals::Interrupt::PARL_IO, handler.priority()) + .unwrap(); + } + #[cfg(esp32h2)] + { + unsafe { crate::peripherals::PARL_IO::steal() } + .bind_parl_io_tx_interrupt(handler.handler()); + unsafe { crate::peripherals::PARL_IO::steal() } + .bind_parl_io_rx_interrupt(handler.handler()); + + crate::interrupt::enable( + crate::peripherals::Interrupt::PARL_IO_TX, + handler.priority(), + ) + .unwrap(); + crate::interrupt::enable( + crate::peripherals::Interrupt::PARL_IO_RX, + handler.priority(), + ) + .unwrap(); + } +} + +fn internal_listen(interrupts: EnumSet) { + let parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + for interrupt in interrupts { + match interrupt { + ParlIoInterrupt::TxFifoReEmpty => parl_io + .int_ena() + .modify(|_, w| w.tx_fifo_rempty_int_ena().set_bit()), + ParlIoInterrupt::RxFifoWOvf => parl_io + .int_ena() + .modify(|_, w| w.rx_fifo_wovf_int_ena().set_bit()), + ParlIoInterrupt::TxEof => parl_io.int_ena().write(|w| w.tx_eof_int_ena().set_bit()), + } + } +} + +fn internal_unlisten(interrupts: EnumSet) { + let parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + for interrupt in interrupts { + match interrupt { + ParlIoInterrupt::TxFifoReEmpty => parl_io + .int_ena() + .modify(|_, w| w.tx_fifo_rempty_int_ena().clear_bit()), + ParlIoInterrupt::RxFifoWOvf => parl_io + .int_ena() + .modify(|_, w| w.rx_fifo_wovf_int_ena().clear_bit()), + ParlIoInterrupt::TxEof => parl_io.int_ena().write(|w| w.tx_eof_int_ena().clear_bit()), + } + } +} + +fn internal_interrupts() -> EnumSet { + let mut res = EnumSet::new(); + let parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + let ints = parl_io.int_st().read(); + if ints.tx_fifo_rempty_int_st().bit() { + res.insert(ParlIoInterrupt::TxFifoReEmpty); + } + if ints.rx_fifo_wovf_int_st().bit() { + res.insert(ParlIoInterrupt::RxFifoWOvf); + } + if ints.tx_eof_int_st().bit() { + res.insert(ParlIoInterrupt::TxEof); + } + + res +} + +fn internal_clear_interrupts(interrupts: EnumSet) { + let parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + for interrupt in interrupts { + match interrupt { + ParlIoInterrupt::TxFifoReEmpty => parl_io + .int_clr() + .write(|w| w.tx_fifo_rempty_int_clr().set_bit()), + ParlIoInterrupt::RxFifoWOvf => parl_io + .int_clr() + .write(|w| w.rx_fifo_wovf_int_clr().set_bit()), + ParlIoInterrupt::TxEof => parl_io.int_clr().write(|w| w.tx_eof_int_clr().set_bit()), + } + } +} + /// Parallel IO in full duplex mode /// /// Full duplex mode might limit the maximum possible bit width. -pub struct ParlIoFullDuplex<'d, CH> +pub struct ParlIoFullDuplex<'d, CH, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, + DM: Mode, { - _parl_io: PeripheralRef<'d, peripherals::PARL_IO>, - pub tx: TxCreatorFullDuplex<'d, CH>, - pub rx: RxCreatorFullDuplex<'d, CH>, + pub tx: TxCreatorFullDuplex<'d, CH, DM>, + pub rx: RxCreatorFullDuplex<'d, CH, DM>, } -impl<'d, CH> ParlIoFullDuplex<'d, CH> +impl<'d, CH, DM> ParlIoFullDuplex<'d, CH, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, + DM: Mode, { pub fn new( - parl_io: impl Peripheral

+ 'd, - mut dma_channel: Channel<'d, CH>, + _parl_io: impl Peripheral

+ 'd, + mut dma_channel: Channel<'d, CH, DM>, frequency: HertzU32, _clocks: &Clocks, ) -> Result { - crate::into_ref!(parl_io); internal_init(&mut dma_channel, frequency)?; Ok(Self { - _parl_io: parl_io, tx: TxCreatorFullDuplex { tx_channel: dma_channel.tx, + phantom: PhantomData, }, rx: RxCreatorFullDuplex { rx_channel: dma_channel.rx, + phantom: PhantomData, }, }) } } +impl<'d, CH> ParlIoFullDuplex<'d, CH, Blocking> +where + CH: ChannelTypes, + CH::P: ParlIoPeripheral, +{ + /// Sets the interrupt handler, enables it with + /// [crate::interrupt::Priority::min()] + /// + /// Interrupts are not enabled at the peripheral level here. + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + internal_set_interrupt_handler(handler); + } + + /// Listen for the given interrupts + pub fn listen(&mut self, interrupts: EnumSet) { + internal_listen(interrupts); + } + + /// Unlisten the given interrupts + pub fn unlisten(&mut self, interrupts: EnumSet) { + internal_unlisten(interrupts); + } + + /// Gets asserted interrupts + pub fn interrupts(&mut self) -> EnumSet { + internal_interrupts() + } + + /// Resets asserted interrupts + pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + internal_clear_interrupts(interrupts); + } +} + /// Parallel IO in half duplex / TX only mode -pub struct ParlIoTxOnly<'d, CH> +pub struct ParlIoTxOnly<'d, CH, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, + DM: Mode, { - _parl_io: PeripheralRef<'d, peripherals::PARL_IO>, - pub tx: TxCreator<'d, CH>, + pub tx: TxCreator<'d, CH, DM>, } -impl<'d, CH> ParlIoTxOnly<'d, CH> +impl<'d, CH, DM> ParlIoTxOnly<'d, CH, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, + DM: Mode, { pub fn new( - parl_io: impl Peripheral

+ 'd, - mut dma_channel: Channel<'d, CH>, + _parl_io: impl Peripheral

+ 'd, + mut dma_channel: Channel<'d, CH, DM>, frequency: HertzU32, _clocks: &Clocks, ) -> Result { - crate::into_ref!(parl_io); internal_init(&mut dma_channel, frequency)?; Ok(Self { - _parl_io: parl_io, tx: TxCreator { tx_channel: dma_channel.tx, + phantom: PhantomData, }, }) } } +impl<'d, CH> ParlIoTxOnly<'d, CH, Blocking> +where + CH: ChannelTypes, + CH::P: ParlIoPeripheral, +{ + /// Sets the interrupt handler, enables it with + /// [crate::interrupt::Priority::min()] + /// + /// Interrupts are not enabled at the peripheral level here. + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + internal_set_interrupt_handler(handler); + } + + /// Listen for the given interrupts + pub fn listen(&mut self, interrupts: EnumSet) { + internal_listen(interrupts); + } + + /// Unlisten the given interrupts + pub fn unlisten(&mut self, interrupts: EnumSet) { + internal_unlisten(interrupts); + } + + /// Gets asserted interrupts + pub fn interrupts(&mut self) -> EnumSet { + internal_interrupts() + } + + /// Resets asserted interrupts + pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + internal_clear_interrupts(interrupts); + } +} + /// Parallel IO in half duplex / RX only mode -pub struct ParlIoRxOnly<'d, CH> +pub struct ParlIoRxOnly<'d, CH, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, + DM: Mode, { - _parl_io: PeripheralRef<'d, peripherals::PARL_IO>, - pub rx: RxCreator<'d, CH>, + pub rx: RxCreator<'d, CH, DM>, } -impl<'d, CH> ParlIoRxOnly<'d, CH> +impl<'d, CH, DM> ParlIoRxOnly<'d, CH, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, + DM: Mode, { pub fn new( - parl_io: impl Peripheral

+ 'd, - mut dma_channel: Channel<'d, CH>, + _parl_io: impl Peripheral

+ 'd, + mut dma_channel: Channel<'d, CH, DM>, frequency: HertzU32, _clocks: &Clocks, ) -> Result { - crate::into_ref!(parl_io); internal_init(&mut dma_channel, frequency)?; Ok(Self { - _parl_io: parl_io, rx: RxCreator { rx_channel: dma_channel.rx, + phantom: PhantomData, }, }) } } -fn internal_init(dma_channel: &mut Channel<'_, CH>, frequency: HertzU32) -> Result<(), Error> +impl<'d, CH> ParlIoRxOnly<'d, CH, Blocking> +where + CH: ChannelTypes, + CH::P: ParlIoPeripheral, +{ + /// Sets the interrupt handler, enables it with + /// [crate::interrupt::Priority::min()] + /// + /// Interrupts are not enabled at the peripheral level here. + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + internal_set_interrupt_handler(handler); + } + + /// Listen for the given interrupts + pub fn listen(&mut self, interrupts: EnumSet) { + internal_listen(interrupts); + } + + /// Unlisten the given interrupts + pub fn unlisten(&mut self, interrupts: EnumSet) { + internal_unlisten(interrupts); + } + + /// Gets asserted interrupts + pub fn interrupts(&mut self) -> EnumSet { + internal_interrupts() + } + + /// Resets asserted interrupts + pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + internal_clear_interrupts(interrupts); + } +} + +fn internal_init( + dma_channel: &mut Channel<'_, CH, DM>, + frequency: HertzU32, +) -> Result<(), Error> where CH: ChannelTypes, CH::P: ParlIoPeripheral, + DM: Mode, { if frequency.raw() > 40_000_000 { return Err(Error::UnreachableClockRate); @@ -1152,12 +1376,13 @@ where Ok(()) } -impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP> +impl<'d, CH, P, CP, DM> ParlIoTx<'d, CH, P, CP, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, P: TxPins + ConfigurePins, CP: TxClkPin, + DM: Mode, { /// Perform a DMA write. /// @@ -1168,7 +1393,7 @@ where pub fn write_dma<'t, TXBUF>( &'t mut self, words: &'t TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer, { @@ -1212,22 +1437,24 @@ where /// An in-progress DMA transfer. #[must_use] -pub struct DmaTransfer<'t, 'd, C, P, CP> +pub struct DmaTransfer<'t, 'd, C, P, CP, DM> where C: ChannelTypes, C::P: ParlIoPeripheral, P: TxPins + ConfigurePins, CP: TxClkPin, + DM: Mode, { - instance: &'t mut ParlIoTx<'d, C, P, CP>, + instance: &'t mut ParlIoTx<'d, C, P, CP, DM>, } -impl<'t, 'd, C, P, CP> DmaTransfer<'t, 'd, C, P, CP> +impl<'t, 'd, C, P, CP, DM> DmaTransfer<'t, 'd, C, P, CP, DM> where C: ChannelTypes, C::P: ParlIoPeripheral, P: TxPins + ConfigurePins, CP: TxClkPin, + DM: Mode, { /// Wait for the DMA transfer to complete #[allow(clippy::type_complexity)] @@ -1252,12 +1479,13 @@ where } } -impl<'d, CH, P, CP> ParlIoRx<'d, CH, P, CP> +impl<'d, CH, P, CP, DM> ParlIoRx<'d, CH, P, CP, DM> where CH: ChannelTypes, CH::P: ParlIoPeripheral, P: RxPins + ConfigurePins, CP: RxClkPin, + DM: Mode, { /// Perform a DMA read. /// @@ -1271,7 +1499,7 @@ where pub fn read_dma<'t, RXBUF>( &'t mut self, words: &'t mut RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer, { @@ -1308,22 +1536,24 @@ where } /// An in-progress DMA transfer. -pub struct RxDmaTransfer<'t, 'd, C, P, CP> +pub struct RxDmaTransfer<'t, 'd, C, P, CP, DM> where C: ChannelTypes, C::P: ParlIoPeripheral, P: RxPins + ConfigurePins, CP: RxClkPin, + DM: Mode, { - instance: &'t mut ParlIoRx<'d, C, P, CP>, + instance: &'t mut ParlIoRx<'d, C, P, CP, DM>, } -impl<'t, 'd, C, P, CP> RxDmaTransfer<'t, 'd, C, P, CP> +impl<'t, 'd, C, P, CP, DM> RxDmaTransfer<'t, 'd, C, P, CP, DM> where C: ChannelTypes, C::P: ParlIoPeripheral, P: RxPins + ConfigurePins, CP: RxClkPin, + DM: Mode, { /// Wait for the DMA transfer to complete #[allow(clippy::type_complexity)] @@ -1362,6 +1592,7 @@ pub mod asynch { use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; + use procmacros::handler; use super::{ private::{ConfigurePins, Instance, RxClkPin, RxPins, TxClkPin, TxPins}, @@ -1372,7 +1603,7 @@ pub mod asynch { }; use crate::{ dma::{asynch::DmaRxDoneChFuture, ChannelTypes, ParlIoPeripheral}, - macros::interrupt, + peripherals::Interrupt, }; static TX_WAKER: AtomicWaker = AtomicWaker::new(); @@ -1393,6 +1624,20 @@ pub mod asynch { self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> Poll { + let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() }; + + #[cfg(esp32c6)] + { + parl_io.bind_parl_io_interrupt(interrupt_handler.handler()); + crate::interrupt::enable(Interrupt::PARL_IO, interrupt_handler.priority()).unwrap(); + } + #[cfg(esp32h2)] + { + parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler()); + crate::interrupt::enable(Interrupt::PARL_IO_TX, interrupt_handler.priority()) + .unwrap(); + } + TX_WAKER.register(cx.waker()); if Instance::is_listening_tx_done() { Poll::Pending @@ -1402,19 +1647,8 @@ pub mod asynch { } } - #[cfg(esp32c6)] - #[interrupt] - fn PARL_IO() { - if Instance::is_tx_done_set() { - Instance::clear_is_tx_done(); - Instance::unlisten_tx_done(); - TX_WAKER.wake() - } - } - - #[cfg(esp32h2)] - #[interrupt] - fn PARL_IO_TX() { + #[handler] + fn interrupt_handler() { if Instance::is_tx_done_set() { Instance::clear_is_tx_done(); Instance::unlisten_tx_done(); @@ -1422,7 +1656,7 @@ pub mod asynch { } } - impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP> + impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP, crate::Async> where CH: ChannelTypes, CH::P: ParlIoPeripheral, @@ -1447,7 +1681,7 @@ pub mod asynch { } } - impl<'d, CH, P, CP> ParlIoRx<'d, CH, P, CP> + impl<'d, CH, P, CP> ParlIoRx<'d, CH, P, CP, crate::Async> where CH: ChannelTypes, CH::P: ParlIoPeripheral, @@ -1476,8 +1710,10 @@ pub mod asynch { } mod private { + use core::marker::PhantomData; + use super::{BitPackOrder, EofMode, Error, SampleEdge}; - use crate::dma::ChannelTypes; + use crate::{dma::ChannelTypes, Mode}; pub trait FullDuplex {} @@ -1501,32 +1737,40 @@ mod private { fn configure(&mut self) -> Result<(), Error>; } - pub struct TxCreator<'d, CH> + pub struct TxCreator<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub tx_channel: CH::Tx<'d>, + pub(crate) phantom: PhantomData, } - pub struct RxCreator<'d, CH> + pub struct RxCreator<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub rx_channel: CH::Rx<'d>, + pub(crate) phantom: PhantomData, } - pub struct TxCreatorFullDuplex<'d, CH> + pub struct TxCreatorFullDuplex<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub tx_channel: CH::Tx<'d>, + pub(crate) phantom: PhantomData, } - pub struct RxCreatorFullDuplex<'d, CH> + pub struct RxCreatorFullDuplex<'d, CH, DM> where CH: ChannelTypes, + DM: Mode, { pub rx_channel: CH::Rx<'d>, + pub(crate) phantom: PhantomData, } #[cfg(esp32c6)] @@ -1670,7 +1914,7 @@ mod private { reg_block .int_clr() - .write(|w| w.rx_fifo_wfull_int_clr().set_bit()); + .write(|w| w.rx_fifo_wovf_int_clr().set_bit()); } pub fn set_rx_bytes(len: u16) { diff --git a/esp-hal/src/soc/esp32/peripherals.rs b/esp-hal/src/soc/esp32/peripherals.rs index b56d41cd4b1..aeea7b39c0b 100644 --- a/esp-hal/src/soc/esp32/peripherals.rs +++ b/esp-hal/src/soc/esp32/peripherals.rs @@ -37,8 +37,8 @@ crate::peripherals! { HINF <= HINF, I2C0 <= I2C0, I2C1 <= I2C1, - I2S0 <= I2S0, - I2S1 <= I2S1, + I2S0 <= I2S0 (I2S0), + I2S1 <= I2S1 (I2S1), IO_MUX <= IO_MUX, LEDC <= LEDC, MCPWM0 <= MCPWM0, @@ -58,8 +58,8 @@ crate::peripherals! { SLCHOST <= SLCHOST, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2, - SPI3 <= SPI3, + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), SYSTEM <= DPORT, TIMG0 <= TIMG0, TIMG1 <= TIMG1, diff --git a/esp-hal/src/soc/esp32c2/peripherals.rs b/esp-hal/src/soc/esp32c2/peripherals.rs index 072a7e80a4a..1c9743d7007 100644 --- a/esp-hal/src/soc/esp32c2/peripherals.rs +++ b/esp-hal/src/soc/esp32c2/peripherals.rs @@ -24,7 +24,7 @@ crate::peripherals! { APB_CTRL <= APB_CTRL, ASSIST_DEBUG <= ASSIST_DEBUG, BT <= virtual, - DMA <= DMA, + DMA <= DMA (DMA_CH0), ECC <= ECC, EFUSE <= EFUSE, EXTMEM <= EXTMEM, @@ -39,7 +39,7 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2, + SPI2 <= SPI2 (SPI2), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, TIMG0 <= TIMG0, diff --git a/esp-hal/src/soc/esp32c3/peripherals.rs b/esp-hal/src/soc/esp32c3/peripherals.rs index 5d1c9e229aa..0edd8e7e6ab 100644 --- a/esp-hal/src/soc/esp32c3/peripherals.rs +++ b/esp-hal/src/soc/esp32c3/peripherals.rs @@ -26,7 +26,7 @@ crate::peripherals! { APB_CTRL <= APB_CTRL, ASSIST_DEBUG <= ASSIST_DEBUG, BT <= virtual, - DMA <= DMA, + DMA <= DMA (DMA_CH0,DMA_CH1,DMA_CH2), DS <= DS, EFUSE <= EFUSE, EXTMEM <= EXTMEM, @@ -34,7 +34,7 @@ crate::peripherals! { GPIO_SD <= GPIO_SD, HMAC <= HMAC, I2C0 <= I2C0, - I2S0 <= I2S0, + I2S0 <= I2S0 (I2S0), INTERRUPT_CORE0 <= INTERRUPT_CORE0, IO_MUX <= IO_MUX, LEDC <= LEDC, @@ -46,7 +46,7 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2, + SPI2 <= SPI2 (SPI2), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, TIMG0 <= TIMG0, diff --git a/esp-hal/src/soc/esp32c6/peripherals.rs b/esp-hal/src/soc/esp32c6/peripherals.rs index 11360622b80..26340fdb752 100644 --- a/esp-hal/src/soc/esp32c6/peripherals.rs +++ b/esp-hal/src/soc/esp32c6/peripherals.rs @@ -25,7 +25,7 @@ crate::peripherals! { ASSIST_DEBUG <= ASSIST_DEBUG, ATOMIC <= ATOMIC, BT <= virtual, - DMA <= DMA, + DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2), DS <= DS, ECC <= ECC, EFUSE <= EFUSE, @@ -37,7 +37,7 @@ crate::peripherals! { HP_APM <= HP_APM, HP_SYS <= HP_SYS, I2C0 <= I2C0, - I2S0 <= I2S0, + I2S0 <= I2S0 (I2S0), IEEE802154 <= virtual, INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTPRI <= INTPRI, @@ -60,7 +60,7 @@ crate::peripherals! { MCPWM0 <= MCPWM0, MEM_MONITOR <= MEM_MONITOR, OTP_DEBUG <= OTP_DEBUG, - PARL_IO <= PARL_IO, + PARL_IO <= PARL_IO (PARL_IO), PAU <= PAU, PCNT <= PCNT, PMU <= PMU, @@ -72,7 +72,7 @@ crate::peripherals! { SOC_ETM <= SOC_ETM, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2, + SPI2 <= SPI2 (SPI2), SYSTEM <= PCR, SYSTIMER <= SYSTIMER, TEE <= TEE, diff --git a/esp-hal/src/soc/esp32h2/peripherals.rs b/esp-hal/src/soc/esp32h2/peripherals.rs index 251fc492934..e09d10590bf 100644 --- a/esp-hal/src/soc/esp32h2/peripherals.rs +++ b/esp-hal/src/soc/esp32h2/peripherals.rs @@ -24,7 +24,7 @@ crate::peripherals! { AES <= AES, ASSIST_DEBUG <= ASSIST_DEBUG, BT <= virtual, - DMA <= DMA, + DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2), DS <= DS, ECC <= ECC, EFUSE <= EFUSE, @@ -35,7 +35,7 @@ crate::peripherals! { HP_SYS <= HP_SYS, I2C0 <= I2C0, I2C1 <= I2C1, - I2S0 <= I2S0, + I2S0 <= I2S0 (I2S0), IEEE802154 <= virtual, INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTPRI <= INTPRI, @@ -53,7 +53,7 @@ crate::peripherals! { MODEM_LPCON <= MODEM_LPCON, MODEM_SYSCON <= MODEM_SYSCON, OTP_DEBUG <= OTP_DEBUG, - PARL_IO <= PARL_IO, + PARL_IO <= PARL_IO (PARL_IO_TX, PARL_IO_RX), PAU <= PAU, PCNT <= PCNT, PMU <= PMU, @@ -64,7 +64,7 @@ crate::peripherals! { SOC_ETM <= SOC_ETM, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2, + SPI2 <= SPI2 (SPI2), SYSTEM <= PCR, SYSTIMER <= SYSTIMER, TEE <= TEE, diff --git a/esp-hal/src/soc/esp32s2/peripherals.rs b/esp-hal/src/soc/esp32s2/peripherals.rs index f8c04dc5478..b053e64ee45 100644 --- a/esp-hal/src/soc/esp32s2/peripherals.rs +++ b/esp-hal/src/soc/esp32s2/peripherals.rs @@ -35,7 +35,7 @@ crate::peripherals! { HMAC <= HMAC, I2C0 <= I2C0, I2C1 <= I2C1, - I2S0 <= I2S0, + I2S0 <= I2S0 (I2S0), INTERRUPT_CORE0 <= INTERRUPT_CORE0, IO_MUX <= IO_MUX, LEDC <= LEDC, @@ -51,8 +51,8 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2, - SPI3 <= SPI3, + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), SPI4 <= SPI4, SYSCON <= SYSCON, SYSTEM <= SYSTEM, diff --git a/esp-hal/src/soc/esp32s3/peripherals.rs b/esp-hal/src/soc/esp32s3/peripherals.rs index aa93b173659..ab1e92a04e4 100644 --- a/esp-hal/src/soc/esp32s3/peripherals.rs +++ b/esp-hal/src/soc/esp32s3/peripherals.rs @@ -26,7 +26,7 @@ crate::peripherals! { APB_CTRL <= APB_CTRL, ASSIST_DEBUG <= ASSIST_DEBUG, BT <= virtual, - DMA <= DMA, + DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_IN_CH3,DMA_IN_CH4,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2,DMA_OUT_CH3,DMA_OUT_CH4), DS <= DS, EFUSE <= EFUSE, EXTMEM <= EXTMEM, @@ -35,8 +35,8 @@ crate::peripherals! { HMAC <= HMAC, I2C0 <= I2C0, I2C1 <= I2C1, - I2S0 <= I2S0, - I2S1 <= I2S1, + I2S0 <= I2S0 (I2S0), + I2S1 <= I2S1 (I2S1), INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE1 <= INTERRUPT_CORE1, IO_MUX <= IO_MUX, @@ -57,8 +57,8 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2, - SPI3 <= SPI3, + SPI2 <= SPI2 (SPI2), + SPI3 <= SPI3 (SPI3), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, TIMG0 <= TIMG0, diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 8b56e98fe77..625422e5750 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -49,6 +49,10 @@ use core::marker::PhantomData; +#[cfg(not(any(esp32, esp32s2)))] +use enumset::EnumSet; +#[cfg(not(any(esp32, esp32s2)))] +use enumset::EnumSetType; use fugit::HertzU32; #[cfg(feature = "place-spi-driver-in-ram")] use procmacros::ram; @@ -67,6 +71,7 @@ use crate::{ clock::Clocks, dma::{DmaPeripheral, Rx, Tx}, gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, + interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, peripherals::spi2::RegisterBlock, system::PeripheralClockControl, @@ -83,6 +88,12 @@ pub mod prelude { }; } +#[cfg(not(any(esp32, esp32s2)))] +#[derive(EnumSetType)] +pub enum SpiInterrupt { + TransDone, +} + /// The size of the FIFO buffer for SPI #[cfg(not(esp32s2))] const FIFO_SIZE: usize = 64; @@ -780,37 +791,47 @@ pub mod dma { TxPrivate, }, FlashSafeDma, + Mode, }; - pub trait WithDmaSpi2<'d, C, M> + pub trait WithDmaSpi2<'d, C, M, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { - fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI2, C, M>; + fn with_dma( + self, + channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI2, C, M, DmaMode>; } #[cfg(spi3)] - pub trait WithDmaSpi3<'d, C, M> + pub trait WithDmaSpi3<'d, C, M, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { - fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI3, C, M>; + fn with_dma( + self, + channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI3, C, M, DmaMode>; } - impl<'d, C, M> WithDmaSpi2<'d, C, M> for Spi<'d, crate::peripherals::SPI2, M> + impl<'d, C, M, DmaMode> WithDmaSpi2<'d, C, M, DmaMode> for Spi<'d, crate::peripherals::SPI2, M> where C: ChannelTypes, C::P: SpiPeripheral + Spi2Peripheral, M: DuplexMode, + DmaMode: Mode, { fn with_dma( self, - mut channel: Channel<'d, C>, - ) -> SpiDma<'d, crate::peripherals::SPI2, C, M> { + mut channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI2, C, M, DmaMode> { channel.tx.init_channel(); // no need to call this for both, TX and RX SpiDma { @@ -822,16 +843,17 @@ pub mod dma { } #[cfg(spi3)] - impl<'d, C, M> WithDmaSpi3<'d, C, M> for Spi<'d, crate::peripherals::SPI3, M> + impl<'d, C, M, DmaMode> WithDmaSpi3<'d, C, M, DmaMode> for Spi<'d, crate::peripherals::SPI3, M> where C: ChannelTypes, C::P: SpiPeripheral + Spi3Peripheral, M: DuplexMode, + DmaMode: Mode, { fn with_dma( self, - mut channel: Channel<'d, C>, - ) -> SpiDma<'d, crate::peripherals::SPI3, C, M> { + mut channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI3, C, M, DmaMode> { channel.tx.init_channel(); // no need to call this for both, TX and RX SpiDma { @@ -843,22 +865,24 @@ pub mod dma { } /// An in-progress DMA transfer #[must_use] - pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M> + pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { - spi_dma: &'t mut SpiDma<'d, T, C, M>, + spi_dma: &'t mut SpiDma<'d, T, C, M, DmaMode>, } - impl<'t, 'd, T, C, M> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, M> + impl<'t, 'd, T, C, M, DmaMode> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { /// Wait for the DMA transfer to complete fn wait(self) -> Result<(), DmaError> { @@ -880,12 +904,13 @@ pub mod dma { } } - impl<'t, 'd, T, C, M> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, M> + impl<'t, 'd, T, C, M, DmaMode> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { fn drop(&mut self) { self.spi_dma.spi.flush().ok(); @@ -894,22 +919,24 @@ pub mod dma { /// An in-progress DMA transfer. #[must_use] - pub struct SpiDmaTransfer<'t, 'd, T, C, M> + pub struct SpiDmaTransfer<'t, 'd, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { - spi_dma: &'t mut SpiDma<'d, T, C, M>, + spi_dma: &'t mut SpiDma<'d, T, C, M, DmaMode>, } - impl<'t, 'd, T, C, M> DmaTransfer for SpiDmaTransfer<'t, 'd, T, C, M> + impl<'t, 'd, T, C, M, DmaMode> DmaTransfer for SpiDmaTransfer<'t, 'd, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { /// Wait for the DMA transfer to complete fn wait(self) -> Result<(), DmaError> { @@ -931,12 +958,13 @@ pub mod dma { } } - impl<'t, 'd, T, C, M> Drop for SpiDmaTransfer<'t, 'd, T, C, M> + impl<'t, 'd, T, C, M, DmaMode> Drop for SpiDmaTransfer<'t, 'd, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { fn drop(&mut self) { self.spi_dma.spi.flush().ok(); @@ -944,46 +972,91 @@ pub mod dma { } /// A DMA capable SPI instance. - pub struct SpiDma<'d, T, C, M> + pub struct SpiDma<'d, T, C, M, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, C>, + pub(crate) channel: Channel<'d, C, DmaMode>, _mode: PhantomData, } - impl<'d, T, C, M> core::fmt::Debug for SpiDma<'d, T, C, M> + impl<'d, T, C, M, DmaMode> core::fmt::Debug for SpiDma<'d, T, C, M, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("SpiDma").finish() } } - impl<'d, T, C, M> SpiDma<'d, T, C, M> + impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode> + where + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode, + DmaMode: Mode, + { + /// Sets the interrupt handler, enables it with + /// [crate::interrupt::Priority::min()] + /// + /// Interrupts are not enabled at the peripheral level here. + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.spi.set_interrupt_handler(handler); + } + + /// Listen for the given interrupts + #[cfg(not(any(esp32, esp32s2)))] + pub fn listen(&mut self, interrupts: EnumSet) { + self.spi.listen(interrupts); + } + + /// Unlisten the given interrupts + #[cfg(not(any(esp32, esp32s2)))] + pub fn unlisten(&mut self, interrupts: EnumSet) { + self.spi.unlisten(interrupts); + } + + /// Gets asserted interrupts + #[cfg(not(any(esp32, esp32s2)))] + pub fn interrupts(&mut self) -> EnumSet { + self.spi.interrupts() + } + + /// Resets asserted interrupts + #[cfg(not(any(esp32, esp32s2)))] + pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + self.spi.clear_interrupts(interrupts); + } + } + + impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: DuplexMode, + DmaMode: Mode, { pub fn change_bus_frequency(&mut self, frequency: HertzU32, clocks: &Clocks) { self.spi.ch_bus_freq(frequency, clocks); } } - impl<'d, T, C, M> SpiDma<'d, T, C, M> + impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: IsFullDuplex, + DmaMode: Mode, { /// Perform a DMA write. /// @@ -994,7 +1067,7 @@ pub mod dma { pub fn dma_write<'t, TXBUF>( &'t mut self, words: &'t TXBUF, - ) -> Result, super::Error> + ) -> Result, super::Error> where TXBUF: ReadBuffer, { @@ -1018,7 +1091,7 @@ pub mod dma { pub fn dma_read<'t, RXBUF>( &'t mut self, words: &'t mut RXBUF, - ) -> Result, super::Error> + ) -> Result, super::Error> where RXBUF: WriteBuffer, { @@ -1042,7 +1115,7 @@ pub mod dma { &'t mut self, words: &'t TXBUF, read_buffer: &'t mut RXBUF, - ) -> Result, super::Error> + ) -> Result, super::Error> where TXBUF: ReadBuffer, RXBUF: WriteBuffer, @@ -1067,12 +1140,13 @@ pub mod dma { } } - impl<'d, T, C, M> SpiDma<'d, T, C, M> + impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: IsHalfDuplex, + DmaMode: Mode, { #[cfg_attr(feature = "place-spi-driver-in-ram", ram)] pub fn read<'t, RXBUF>( @@ -1082,7 +1156,7 @@ pub mod dma { address: Address, dummy: u8, buffer: &'t mut RXBUF, - ) -> Result, super::Error> + ) -> Result, super::Error> where RXBUF: WriteBuffer, { @@ -1153,7 +1227,7 @@ pub mod dma { address: Address, dummy: u8, buffer: &'t TXBUF, - ) -> Result, super::Error> + ) -> Result, super::Error> where TXBUF: ReadBuffer, { @@ -1218,12 +1292,14 @@ pub mod dma { } #[cfg(feature = "embedded-hal-02")] - impl<'d, T, C, M> embedded_hal_02::blocking::spi::Transfer for SpiDma<'d, T, C, M> + impl<'d, T, C, M, DmaMode> embedded_hal_02::blocking::spi::Transfer + for SpiDma<'d, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: IsFullDuplex, + DmaMode: Mode, { type Error = super::Error; @@ -1234,12 +1310,14 @@ pub mod dma { } #[cfg(feature = "embedded-hal-02")] - impl<'d, T, C, M> embedded_hal_02::blocking::spi::Write for SpiDma<'d, T, C, M> + impl<'d, T, C, M, DmaMode> embedded_hal_02::blocking::spi::Write + for SpiDma<'d, T, C, M, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, M: IsFullDuplex, + DmaMode: Mode, { type Error = super::Error; @@ -1308,7 +1386,7 @@ pub mod dma { mod asynch { use super::*; - impl<'d, T, C, M> embedded_hal_async::spi::SpiBus for SpiDma<'d, T, C, M> + impl<'d, T, C, M> embedded_hal_async::spi::SpiBus for SpiDma<'d, T, C, M, crate::Async> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, @@ -1468,7 +1546,7 @@ pub mod dma { use super::*; - impl<'d, T, C, M> ErrorType for SpiDma<'d, T, C, M> + impl<'d, T, C, M> ErrorType for SpiDma<'d, T, C, M, crate::Async> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, @@ -1478,7 +1556,7 @@ pub mod dma { type Error = Error; } - impl<'d, T, C, M> SpiBus for SpiDma<'d, T, C, M> + impl<'d, T, C, M> SpiBus for SpiDma<'d, T, C, M, crate::Async> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, @@ -2361,6 +2439,72 @@ pub trait Instance: crate::private::Sealed { .write(|w| unsafe { w.bits(reg_val) }); } + /// Set the interrupt handler + fn set_interrupt_handler(&mut self, handler: InterruptHandler); + + /// Listen for the given interrupts + #[cfg(not(any(esp32, esp32s2)))] + fn listen(&mut self, interrupts: EnumSet) { + let reg_block = self.register_block(); + + for interrupt in interrupts { + match interrupt { + SpiInterrupt::TransDone => { + reg_block + .dma_int_ena() + .modify(|_, w| w.trans_done_int_ena().set_bit()); + } + } + } + } + + /// Unlisten the given interrupts + #[cfg(not(any(esp32, esp32s2)))] + fn unlisten(&mut self, interrupts: EnumSet) { + let reg_block = self.register_block(); + + for interrupt in interrupts { + match interrupt { + SpiInterrupt::TransDone => { + reg_block + .dma_int_ena() + .modify(|_, w| w.trans_done_int_ena().clear_bit()); + } + } + } + } + + /// Gets asserted interrupts + #[cfg(not(any(esp32, esp32s2)))] + fn interrupts(&mut self) -> EnumSet { + let mut res = EnumSet::new(); + let reg_block = self.register_block(); + + let ints = reg_block.dma_int_st().read(); + + if ints.trans_done_int_st().bit() { + res.insert(SpiInterrupt::TransDone); + } + + res + } + + /// Resets asserted interrupts + #[cfg(not(any(esp32, esp32s2)))] + fn clear_interrupts(&mut self, interrupts: EnumSet) { + let reg_block = self.register_block(); + + for interrupt in interrupts { + match interrupt { + SpiInterrupt::TransDone => { + reg_block + .dma_int_clr() + .write(|w| w.trans_done_int_clr().set_bit()); + } + } + } + } + #[cfg(not(esp32))] fn set_data_mode(&mut self, data_mode: SpiMode) -> &mut Self { let reg_block = self.register_block(); @@ -2837,6 +2981,12 @@ impl Instance for crate::peripherals::SPI2 { self } + #[inline(always)] + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.bind_spi2_interrupt(handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap(); + } + #[inline(always)] fn sclk_signal(&self) -> OutputSignal { OutputSignal::FSPICLK_MUX @@ -2908,6 +3058,12 @@ impl Instance for crate::peripherals::SPI2 { self } + #[inline(always)] + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.bind_spi2_interrupt(handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap(); + } + #[inline(always)] fn sclk_signal(&self) -> OutputSignal { OutputSignal::HSPICLK @@ -2973,6 +3129,12 @@ impl Instance for crate::peripherals::SPI3 { self } + #[inline(always)] + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.bind_spi3_interrupt(handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap(); + } + #[inline(always)] fn sclk_signal(&self) -> OutputSignal { OutputSignal::VSPICLK @@ -3011,6 +3173,12 @@ impl Instance for crate::peripherals::SPI2 { self } + #[inline(always)] + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.bind_spi2_interrupt(handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap(); + } + #[inline(always)] fn sclk_signal(&self) -> OutputSignal { OutputSignal::FSPICLK @@ -3082,6 +3250,12 @@ impl Instance for crate::peripherals::SPI3 { self } + #[inline(always)] + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.bind_spi3_interrupt(handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap(); + } + #[inline(always)] fn sclk_signal(&self) -> OutputSignal { OutputSignal::SPI3_CLK diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 076f531baf4..c5cd5b9635f 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -142,41 +142,57 @@ pub mod dma { use super::*; #[cfg(spi3)] use crate::dma::Spi3Peripheral; - use crate::dma::{ - Channel, - ChannelTypes, - DmaError, - DmaTransfer, - DmaTransferRxTx, - RxPrivate, - Spi2Peripheral, - SpiPeripheral, - TxPrivate, + use crate::{ + dma::{ + Channel, + ChannelTypes, + DmaError, + DmaTransfer, + DmaTransferRxTx, + RxPrivate, + Spi2Peripheral, + SpiPeripheral, + TxPrivate, + }, + Mode, }; - pub trait WithDmaSpi2<'d, C> + pub trait WithDmaSpi2<'d, C, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { - fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI2, C>; + fn with_dma( + self, + channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI2, C, DmaMode>; } #[cfg(spi3)] - pub trait WithDmaSpi3<'d, C> + pub trait WithDmaSpi3<'d, C, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { - fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI3, C>; + fn with_dma( + self, + channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI3, C, DmaMode>; } - impl<'d, C> WithDmaSpi2<'d, C> for Spi<'d, crate::peripherals::SPI2, FullDuplexMode> + impl<'d, C, DmaMode> WithDmaSpi2<'d, C, DmaMode> + for Spi<'d, crate::peripherals::SPI2, FullDuplexMode> where C: ChannelTypes, C::P: SpiPeripheral + Spi2Peripheral, + DmaMode: Mode, { - fn with_dma(self, mut channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI2, C> { + fn with_dma( + self, + mut channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI2, C, DmaMode> { channel.tx.init_channel(); // no need to call this for both, TX and RX #[cfg(esp32)] @@ -195,12 +211,17 @@ pub mod dma { } #[cfg(spi3)] - impl<'d, C> WithDmaSpi3<'d, C> for Spi<'d, crate::peripherals::SPI3, FullDuplexMode> + impl<'d, C, DmaMode> WithDmaSpi3<'d, C, DmaMode> + for Spi<'d, crate::peripherals::SPI3, FullDuplexMode> where C: ChannelTypes, C::P: SpiPeripheral + Spi3Peripheral, + DmaMode: Mode, { - fn with_dma(self, mut channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI3, C> { + fn with_dma( + self, + mut channel: Channel<'d, C, DmaMode>, + ) -> SpiDma<'d, crate::peripherals::SPI3, C, DmaMode> { channel.tx.init_channel(); // no need to call this for both, TX and RX #[cfg(esp32)] @@ -219,20 +240,22 @@ pub mod dma { } /// An in-progress DMA transfer #[must_use] - pub struct SpiDmaTransferRxTx<'t, 'd, T, C> + pub struct SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { - spi_dma: &'t mut SpiDma<'d, T, C>, + spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>, } - impl<'t, 'd, T, C> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C> + impl<'t, 'd, T, C, DmaMode> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { /// Wait for the DMA transfer to complete fn wait(self) -> Result<(), DmaError> { @@ -255,11 +278,12 @@ pub mod dma { } } - impl<'t, 'd, T, C> Drop for SpiDmaTransferRxTx<'t, 'd, T, C> + impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { fn drop(&mut self) { while !self.is_done() {} @@ -269,20 +293,22 @@ pub mod dma { /// An in-progress DMA transfer. #[must_use] - pub struct SpiDmaTransferRx<'t, 'd, T, C> + pub struct SpiDmaTransferRx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { - spi_dma: &'t mut SpiDma<'d, T, C>, + spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>, } - impl<'t, 'd, T, C> DmaTransfer for SpiDmaTransferRx<'t, 'd, T, C> + impl<'t, 'd, T, C, DmaMode> DmaTransfer for SpiDmaTransferRx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { /// Wait for the DMA transfer to complete fn wait(self) -> Result<(), DmaError> { @@ -303,11 +329,12 @@ pub mod dma { } } - impl<'t, 'd, T, C> Drop for SpiDmaTransferRx<'t, 'd, T, C> + impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferRx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { fn drop(&mut self) { while !self.is_done() {} @@ -318,20 +345,22 @@ pub mod dma { /// An in-progress DMA transfer. #[must_use] - pub struct SpiDmaTransferTx<'t, 'd, T, C> + pub struct SpiDmaTransferTx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { - spi_dma: &'t mut SpiDma<'d, T, C>, + spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>, } - impl<'t, 'd, T, C> DmaTransfer for SpiDmaTransferTx<'t, 'd, T, C> + impl<'t, 'd, T, C, DmaMode> DmaTransfer for SpiDmaTransferTx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { /// Wait for the DMA transfer to complete fn wait(self) -> Result<(), DmaError> { @@ -354,11 +383,12 @@ pub mod dma { } } - impl<'t, 'd, T, C> Drop for SpiDmaTransferTx<'t, 'd, T, C> + impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferTx<'t, 'd, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { fn drop(&mut self) { while !self.is_done() {} @@ -368,30 +398,33 @@ pub mod dma { } /// A DMA capable SPI instance. - pub struct SpiDma<'d, T, C> + pub struct SpiDma<'d, T, C, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, C>, + pub(crate) channel: Channel<'d, C, DmaMode>, } - impl<'d, T, C> core::fmt::Debug for SpiDma<'d, T, C> + impl<'d, T, C, DmaMode> core::fmt::Debug for SpiDma<'d, T, C, DmaMode> where C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("SpiDma").finish() } } - impl<'d, T, C> SpiDma<'d, T, C> + impl<'d, T, C, DmaMode> SpiDma<'d, T, C, DmaMode> where T: InstanceDma, C::Rx<'d>>, C: ChannelTypes, C::P: SpiPeripheral, + DmaMode: Mode, { /// Register a buffer for a DMA write. /// @@ -403,7 +436,7 @@ pub mod dma { pub fn dma_write<'t, TXBUF>( &'t mut self, words: &'t TXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer, { @@ -428,7 +461,7 @@ pub mod dma { pub fn dma_read<'t, RXBUF>( &'t mut self, words: &'t mut RXBUF, - ) -> Result, Error> + ) -> Result, Error> where RXBUF: WriteBuffer, { @@ -455,7 +488,7 @@ pub mod dma { &'t mut self, words: &'t TXBUF, read_buffer: &'t mut RXBUF, - ) -> Result, Error> + ) -> Result, Error> where TXBUF: ReadBuffer, RXBUF: WriteBuffer, diff --git a/examples/src/bin/embassy_i2s_read.rs b/examples/src/bin/embassy_i2s_read.rs index 6f1fc0fe915..c3559d287f2 100644 --- a/examples/src/bin/embassy_i2s_read.rs +++ b/examples/src/bin/embassy_i2s_read.rs @@ -57,8 +57,8 @@ async fn main(_spawner: Spawner) { peripherals.I2S0, Standard::Philips, DataFormat::Data16Channel16, - 44100.Hz(), - dma_channel.configure( + 44100u32.Hz(), + dma_channel.configure_for_async( false, &mut tx_descriptors, &mut rx_descriptors, diff --git a/examples/src/bin/embassy_i2s_sound.rs b/examples/src/bin/embassy_i2s_sound.rs index 2e429a0b01a..6bc875ab428 100644 --- a/examples/src/bin/embassy_i2s_sound.rs +++ b/examples/src/bin/embassy_i2s_sound.rs @@ -80,8 +80,8 @@ async fn main(_spawner: Spawner) { peripherals.I2S0, Standard::Philips, DataFormat::Data16Channel16, - 44100.Hz(), - dma_channel.configure( + 44100u32.Hz(), + dma_channel.configure_for_async( false, &mut tx_descriptors, &mut rx_descriptors, diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index c104a8032a0..6115d4130a9 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, - dma_channel.configure( + dma_channel.configure_for_async( false, &mut tx_descriptors, &mut rx_descriptors, diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index 25b3bd16b55..c0cff0cc001 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoTxOnly::new( peripherals.PARL_IO, - dma_channel.configure( + dma_channel.configure_for_async( false, &mut tx_descriptors, &mut rx_descriptors, diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 0b551ed81a3..d64fca512ad 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -2,9 +2,9 @@ //! //! Folowing pins are used: //! SCLK GPIO0 -//! MISO GPIO1 -//! MOSI GPIO2 -//! CS GPIO3 +//! MISO GPIO2 +//! MOSI GPIO4 +//! CS GPIO5 //! //! Depending on your target and the board you are using you have to change the //! pins. @@ -51,9 +51,9 @@ async fn main(_spawner: Spawner) { let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let sclk = io.pins.gpio0; - let miso = io.pins.gpio1; - let mosi = io.pins.gpio2; - let cs = io.pins.gpio3; + let miso = io.pins.gpio2; + let mosi = io.pins.gpio4; + let cs = io.pins.gpio5; let dma = Dma::new(peripherals.DMA); @@ -66,7 +66,7 @@ async fn main(_spawner: Spawner) { let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0, &clocks) .with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs)) - .with_dma(dma_channel.configure( + .with_dma(dma_channel.configure_for_async( false, &mut descriptors, &mut rx_descriptors, @@ -80,7 +80,7 @@ async fn main(_spawner: Spawner) { embedded_hal_async::spi::SpiBus::transfer(&mut spi, &mut buffer, &send_buffer) .await .unwrap(); - esp_println::println!("Bytes recieved: {:?}", buffer); + esp_println::println!("Bytes received: {:?}", buffer); Timer::after(Duration::from_millis(5_000)).await; } }