Runtime DMA interrupt binding (#1300)

This commit is contained in:
Björn Quentin 2024-03-26 14:56:48 +01:00 committed by GitHub
parent 65dca0025b
commit 4077734c3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 1265 additions and 605 deletions

View File

@ -369,15 +369,19 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_error::proc_macro_error] #[proc_macro_error::proc_macro_error]
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
use darling::ast::NestedMeta; use darling::{ast::NestedMeta, FromMeta};
use proc_macro::Span; use proc_macro::Span;
use proc_macro2::Ident; use proc_macro2::Ident;
use proc_macro_crate::{crate_name, FoundCrate}; use proc_macro_crate::{crate_name, FoundCrate};
use proc_macro_error::abort;
use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type}; use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type};
use self::interrupt::{check_attr_whitelist, WhiteListCaller}; use self::interrupt::{check_attr_whitelist, WhiteListCaller};
#[derive(Debug, FromMeta)]
struct MacroArgs {
priority: Option<syn::Expr>,
}
let mut f: ItemFn = syn::parse(input).expect("`#[handler]` must be applied to a function"); let mut f: ItemFn = syn::parse(input).expect("`#[handler]` must be applied to a function");
let original_span = f.span(); 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( let root = Ident::new(
if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") { if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
&name &name
@ -397,30 +408,10 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
Span::call_site().into(), Span::call_site().into(),
); );
let priority = if attr_args.len() > 1 { let priority = if let Some(priority) = args.priority {
abort!( quote::quote!( #priority )
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"
),
}
} else { } else {
String::from("min") quote::quote! { #root::interrupt::Priority::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)
}
}; };
// XXX should we blacklist other attributes? // XXX should we blacklist other attributes?

View File

@ -36,6 +36,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) - `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) - `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) - 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 ### Removed

View File

@ -52,14 +52,14 @@ xtensa-lx = { version = "0.9.0", optional = true }
# IMPORTANT: # IMPORTANT:
# Each supported device MUST have its PAC included below along with a # Each supported device MUST have its PAC included below along with a
# corresponding feature. # corresponding feature.
esp32 = { 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 = "963c280", 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 = "963c280", 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 = "963c280", 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 = "963c280", 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 = "963c280", 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 = "963c280", 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 = "963c280", 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] [target.'cfg(target_arch = "riscv32")'.dependencies]
esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" } esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" }

View File

@ -277,7 +277,7 @@ pub mod dma {
{ {
pub aes: super::Aes<'d>, pub aes: super::Aes<'d>,
pub(crate) channel: Channel<'d, C>, pub(crate) channel: Channel<'d, C, crate::Blocking>,
} }
pub trait WithDmaAes<'d, C> pub trait WithDmaAes<'d, C>
@ -285,7 +285,7 @@ pub mod dma {
C: ChannelTypes, C: ChannelTypes,
C::P: AesPeripheral, 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> impl<'d, C> WithDmaAes<'d, C> for crate::aes::Aes<'d>
@ -293,7 +293,7 @@ pub mod dma {
C: ChannelTypes, C: ChannelTypes,
C::P: AesPeripheral, 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 channel.tx.init_channel(); // no need to call this for both, TX and RX
AesDma { aes: self, channel } AesDma { aes: self, channel }

View File

@ -31,8 +31,22 @@ use crate::{
}; };
macro_rules! impl_channel { macro_rules! impl_channel {
($num: literal) => { ($num: literal, $async_handler: path, $($interrupt: ident),* ) => {
paste::paste! { paste::paste! {
#[non_exhaustive]
pub struct [<Channel $num InterruptBinder>] {}
impl InterruptBinder for [<Channel $num InterruptBinder>] {
#[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] #[non_exhaustive]
pub struct [<Channel $num>] {} pub struct [<Channel $num>] {}
@ -40,6 +54,7 @@ macro_rules! impl_channel {
type P = [<SuitablePeripheral $num>]; type P = [<SuitablePeripheral $num>];
type Tx<'a> = ChannelTx<'a, [<Channel $num TxImpl>], [<Channel $num>]>; type Tx<'a> = ChannelTx<'a, [<Channel $num TxImpl>], [<Channel $num>]>;
type Rx<'a> = ChannelRx<'a, [<Channel $num RxImpl>], [<Channel $num>]>; type Rx<'a> = ChannelRx<'a, [<Channel $num RxImpl>], [<Channel $num>]>;
type Binder = [<Channel $num InterruptBinder>];
} }
impl RegisterAccess for [<Channel $num>] { impl RegisterAccess for [<Channel $num>] {
@ -550,7 +565,7 @@ macro_rules! impl_channel {
pub struct [<ChannelCreator $num>] {} pub struct [<ChannelCreator $num>] {}
impl [<ChannelCreator $num>] { impl [<ChannelCreator $num>] {
/// 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 /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor. /// transfer buffers of size `1..=4092`, you need 1 descriptor.
@ -560,7 +575,7 @@ macro_rules! impl_channel {
tx_descriptors: &'a mut [DmaDescriptor], tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor], rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<Channel $num>]> { ) -> Channel<'a, [<Channel $num>], $crate::Blocking> {
let mut tx_impl = [<Channel $num TxImpl>] {}; let mut tx_impl = [<Channel $num TxImpl>] {};
tx_impl.init(burst_mode, priority); tx_impl.init(burst_mode, priority);
@ -570,6 +585,34 @@ macro_rules! impl_channel {
Channel { Channel {
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
rx: ChannelRx::new(rx_descriptors, rx_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, [<Channel $num>], $crate::Async> {
let mut tx_impl = [<Channel $num TxImpl>] {};
tx_impl.init(burst_mode, priority);
let mut rx_impl = [<Channel $num RxImpl>] {};
rx_impl.init(burst_mode, priority);
<[<Channel $num>] 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_if::cfg_if! {
#[cfg(not(esp32c2))] if #[cfg(esp32c2)] {
impl_channel!(1); impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0);
#[cfg(not(esp32c2))] } else if #[cfg(esp32c3)] {
impl_channel!(2); impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0);
#[cfg(esp32s3)] impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_CH1);
impl_channel!(3); impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_CH2);
#[cfg(esp32s3)] } else if #[cfg(any(esp32c6, esp32h2))] {
impl_channel!(4); 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 /// GDMA Peripheral
/// ///

View File

@ -131,16 +131,25 @@ impl DmaDescriptor {
} }
} }
use enumset::{EnumSet, EnumSetType};
#[cfg(gdma)] #[cfg(gdma)]
pub use self::gdma::*; pub use self::gdma::*;
#[cfg(pdma)] #[cfg(pdma)]
pub use self::pdma::*; pub use self::pdma::*;
use crate::{interrupt::InterruptHandler, Mode};
#[cfg(gdma)] #[cfg(gdma)]
mod gdma; mod gdma;
#[cfg(pdma)] #[cfg(pdma)]
mod pdma; mod pdma;
#[derive(EnumSetType)]
pub enum DmaInterrupt {
TxDone,
RxDone,
}
const CHUNK_SIZE: usize = 4092; const CHUNK_SIZE: usize = 4092;
/// Convenience macro to create DMA buffers and descriptors /// Convenience macro to create DMA buffers and descriptors
@ -1285,15 +1294,79 @@ pub trait ChannelTypes {
type P: PeripheralMarker; type P: PeripheralMarker;
type Tx<'a>: Tx; type Tx<'a>: Tx;
type Rx<'a>: Rx; type Rx<'a>: Rx;
type Binder: InterruptBinder;
}
pub trait InterruptBinder {
#[cfg(feature = "vectored")]
fn set_isr(handler: InterruptHandler);
} }
/// DMA Channel /// DMA Channel
pub struct Channel<'d, C> pub struct Channel<'d, C, MODE>
where where
C: ChannelTypes, C: ChannelTypes,
MODE: Mode,
{ {
pub tx: C::Tx<'d>, pub tx: C::Tx<'d>,
pub(crate) rx: C::Rx<'d>, pub(crate) rx: C::Rx<'d>,
phantom: PhantomData<MODE>,
}
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<DmaInterrupt>) {
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<DmaInterrupt>) {
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<DmaInterrupt> {
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<DmaInterrupt>) {
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. /// Trait to be implemented for an in progress dma transfer.
@ -1319,7 +1392,6 @@ pub(crate) mod asynch {
use core::task::Poll; use core::task::Poll;
use super::*; use super::*;
use crate::macros::interrupt;
pub struct DmaTxFuture<'a, TX> { pub struct DmaTxFuture<'a, TX> {
pub(crate) tx: &'a mut TX, pub(crate) tx: &'a mut TX,
@ -1461,12 +1533,14 @@ pub(crate) mod asynch {
} }
} }
#[cfg(esp32c2)] #[cfg(not(any(esp32, esp32s2)))]
mod interrupt { pub(crate) mod interrupt {
use procmacros::handler;
use super::*; use super::*;
#[interrupt] #[handler(priority = crate::interrupt::Priority::max())]
fn DMA_CH0() { pub(crate) fn interrupt_handler_ch0() {
use crate::dma::gdma::{ use crate::dma::gdma::{
Channel0 as Channel, Channel0 as Channel,
Channel0RxImpl as ChannelRxImpl, Channel0RxImpl as ChannelRxImpl,
@ -1479,59 +1553,28 @@ pub(crate) mod asynch {
ChannelRxImpl::waker().wake() 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(esp32c3)]
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()
}
if Channel::is_ch_in_done_set() { if Channel::is_ch_in_done_set() {
Channel::clear_ch_in_done(); Channel::clear_ch_in_done();
Channel::unlisten_ch_in_done(); Channel::unlisten_ch_in_done();
ChannelRxImpl::waker().wake() 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()
}
} }
#[interrupt] #[cfg(not(esp32c2))]
fn DMA_CH1() { #[handler(priority = crate::interrupt::Priority::max())]
pub(crate) fn interrupt_handler_ch1() {
use crate::dma::gdma::{ use crate::dma::gdma::{
Channel1 as Channel, Channel1 as Channel,
Channel1RxImpl as ChannelRxImpl, Channel1RxImpl as ChannelRxImpl,
@ -1544,6 +1587,12 @@ pub(crate) mod asynch {
ChannelRxImpl::waker().wake() ChannelRxImpl::waker().wake()
} }
if Channel::is_ch_in_done_set() {
Channel::clear_ch_in_done();
Channel::unlisten_ch_in_done();
ChannelRxImpl::waker().wake()
}
if Channel::is_out_done() { if Channel::is_out_done() {
Channel::clear_out_interrupts(); Channel::clear_out_interrupts();
Channel::unlisten_out_eof(); Channel::unlisten_out_eof();
@ -1555,16 +1604,11 @@ pub(crate) mod asynch {
Channel::unlisten_ch_out_done(); Channel::unlisten_ch_out_done();
ChannelTxImpl::waker().wake() ChannelTxImpl::waker().wake()
} }
if Channel::is_ch_in_done_set() {
Channel::clear_ch_in_done();
Channel::unlisten_ch_in_done();
ChannelRxImpl::waker().wake()
}
} }
#[interrupt] #[cfg(not(esp32c2))]
fn DMA_CH2() { #[handler(priority = crate::interrupt::Priority::max())]
pub(crate) fn interrupt_handler_ch2() {
use crate::dma::gdma::{ use crate::dma::gdma::{
Channel2 as Channel, Channel2 as Channel,
Channel2RxImpl as ChannelRxImpl, Channel2RxImpl as ChannelRxImpl,
@ -1577,50 +1621,11 @@ pub(crate) mod asynch {
ChannelRxImpl::waker().wake() 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() { if Channel::is_ch_in_done_set() {
Channel::clear_ch_in_done(); Channel::clear_ch_in_done();
Channel::unlisten_ch_in_done(); Channel::unlisten_ch_in_done();
ChannelRxImpl::waker().wake() 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() { if Channel::is_out_done() {
Channel::clear_out_interrupts(); Channel::clear_out_interrupts();
@ -1635,9 +1640,14 @@ pub(crate) mod asynch {
} }
} }
#[interrupt] #[cfg(esp32s3)]
fn DMA_IN_CH1() { #[handler(priority = crate::interrupt::Priority::max())]
use crate::dma::gdma::{Channel1 as Channel, Channel1RxImpl as ChannelRxImpl}; 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() { if Channel::is_in_done() && Channel::is_listening_in_eof() {
Channel::clear_in_interrupts(); Channel::clear_in_interrupts();
@ -1650,11 +1660,6 @@ pub(crate) mod asynch {
Channel::unlisten_ch_in_done(); Channel::unlisten_ch_in_done();
ChannelRxImpl::waker().wake() ChannelRxImpl::waker().wake()
} }
}
#[interrupt]
fn DMA_OUT_CH1() {
use crate::dma::gdma::{Channel1 as Channel, Channel1TxImpl as ChannelTxImpl};
if Channel::is_out_done() { if Channel::is_out_done() {
Channel::clear_out_interrupts(); Channel::clear_out_interrupts();
@ -1669,9 +1674,14 @@ pub(crate) mod asynch {
} }
} }
#[interrupt] #[cfg(esp32s3)]
fn DMA_IN_CH2() { #[handler(priority = crate::interrupt::Priority::max())]
use crate::dma::gdma::{Channel2 as Channel, Channel2RxImpl as ChannelRxImpl}; 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() { if Channel::is_in_done() && Channel::is_listening_in_eof() {
Channel::clear_in_interrupts(); Channel::clear_in_interrupts();
@ -1684,152 +1694,6 @@ pub(crate) mod asynch {
Channel::unlisten_ch_in_done(); Channel::unlisten_ch_in_done();
ChannelRxImpl::waker().wake() 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();
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_CH3() {
use crate::dma::gdma::{Channel3 as Channel, Channel3RxImpl 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_CH3() {
use crate::dma::gdma::{Channel3 as Channel, Channel3TxImpl 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_CH4() {
use crate::dma::gdma::{Channel4 as Channel, Channel4RxImpl 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_CH4() {
use crate::dma::gdma::{Channel4 as Channel, Channel4TxImpl as ChannelTxImpl};
if Channel::is_out_done() { if Channel::is_out_done() {
Channel::clear_out_interrupts(); Channel::clear_out_interrupts();
@ -1846,11 +1710,13 @@ pub(crate) mod asynch {
} }
#[cfg(any(esp32, esp32s2))] #[cfg(any(esp32, esp32s2))]
mod interrupt { pub(crate) mod interrupt {
use procmacros::handler;
use super::*; use super::*;
#[interrupt] #[handler(priority = crate::interrupt::Priority::max())]
fn SPI2_DMA() { pub(crate) fn interrupt_handler_spi2_dma() {
use crate::dma::pdma::{ use crate::dma::pdma::{
Spi2DmaChannel as Channel, Spi2DmaChannel as Channel,
Spi2DmaChannelRxImpl as ChannelRxImpl, Spi2DmaChannelRxImpl as ChannelRxImpl,
@ -1882,8 +1748,8 @@ pub(crate) mod asynch {
} }
} }
#[interrupt] #[handler(priority = crate::interrupt::Priority::max())]
fn SPI3_DMA() { pub(crate) fn interrupt_handler_spi3_dma() {
use crate::dma::pdma::{ use crate::dma::pdma::{
Spi3DmaChannel as Channel, Spi3DmaChannel as Channel,
Spi3DmaChannelRxImpl as ChannelRxImpl, Spi3DmaChannelRxImpl as ChannelRxImpl,
@ -1915,8 +1781,8 @@ pub(crate) mod asynch {
} }
} }
#[interrupt] #[handler(priority = crate::interrupt::Priority::max())]
fn I2S0() { pub(crate) fn interrupt_handler_i2s0() {
use crate::dma::pdma::{ use crate::dma::pdma::{
I2s0DmaChannel as Channel, I2s0DmaChannel as Channel,
I2s0DmaChannelRxImpl as ChannelRxImpl, I2s0DmaChannelRxImpl as ChannelRxImpl,
@ -1948,9 +1814,9 @@ pub(crate) mod asynch {
} }
} }
#[cfg(esp32)] #[cfg(i2s1)]
#[interrupt] #[handler(priority = crate::interrupt::Priority::max())]
fn I2S1() { pub(crate) fn interrupt_handler_i2s1() {
use crate::dma::pdma::{ use crate::dma::pdma::{
I2s1DmaChannel as Channel, I2s1DmaChannel as Channel,
I2s1DmaChannelRxImpl as ChannelRxImpl, I2s1DmaChannelRxImpl as ChannelRxImpl,

View File

@ -22,6 +22,18 @@ use crate::{
macro_rules! ImplSpiChannel { macro_rules! ImplSpiChannel {
($num: literal) => { ($num: literal) => {
paste::paste! { paste::paste! {
#[non_exhaustive]
pub struct [<Channel $num InterruptBinder>] {}
impl InterruptBinder for [<Channel $num InterruptBinder>] {
#[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] #[non_exhaustive]
pub struct [<Spi $num DmaChannel>] {} pub struct [<Spi $num DmaChannel>] {}
@ -29,6 +41,7 @@ macro_rules! ImplSpiChannel {
type P = [<Spi $num DmaSuitablePeripheral>]; type P = [<Spi $num DmaSuitablePeripheral>];
type Tx<'a> = ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>; type Tx<'a> = ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>;
type Rx<'a> = ChannelRx<'a,[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>; type Rx<'a> = ChannelRx<'a,[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>;
type Binder = [<Channel $num InterruptBinder>];
} }
impl RegisterAccess for [<Spi $num DmaChannel>] { impl RegisterAccess for [<Spi $num DmaChannel>] {
@ -301,7 +314,7 @@ macro_rules! ImplSpiChannel {
pub struct [<Spi $num DmaChannelCreator>] {} pub struct [<Spi $num DmaChannelCreator>] {}
impl [<Spi $num DmaChannelCreator>] { impl [<Spi $num DmaChannelCreator>] {
/// 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 /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor. /// transfer buffers of size `1..=4092`, you need 1 descriptor.
@ -311,7 +324,7 @@ macro_rules! ImplSpiChannel {
tx_descriptors: &'a mut [DmaDescriptor], tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor], rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>]> { ) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Blocking> {
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {}; let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority); tx_impl.init(burst_mode, priority);
@ -321,6 +334,34 @@ macro_rules! ImplSpiChannel {
Channel { Channel {
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
rx: ChannelRx::new(rx_descriptors, rx_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, [<Spi $num DmaChannel>], $crate::Async> {
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
let mut rx_impl = [<Spi $num DmaChannelRxImpl>] {};
rx_impl.init(burst_mode, priority);
<[<Spi $num DmaChannel>] 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 { macro_rules! ImplI2sChannel {
($num: literal, $peripheral: literal) => { ($num: literal, $peripheral: literal) => {
paste::paste! { paste::paste! {
#[non_exhaustive]
pub struct [<Channel $num InterruptBinder>] {}
impl InterruptBinder for [<Channel $num InterruptBinder>] {
#[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 [<I2s $num DmaChannel>] {} pub struct [<I2s $num DmaChannel>] {}
impl ChannelTypes for [<I2s $num DmaChannel>] { impl ChannelTypes for [<I2s $num DmaChannel>] {
type P = [<I2s $num DmaSuitablePeripheral>]; type P = [<I2s $num DmaSuitablePeripheral>];
type Tx<'a> = ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>; type Tx<'a> = ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>;
type Rx<'a> = ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>; type Rx<'a> = ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>;
type Binder = [<Channel $num InterruptBinder>];
} }
impl RegisterAccess for [<I2s $num DmaChannel>] { impl RegisterAccess for [<I2s $num DmaChannel>] {
@ -587,7 +641,7 @@ macro_rules! ImplI2sChannel {
pub struct [<I2s $num DmaChannelCreator>] {} pub struct [<I2s $num DmaChannelCreator>] {}
impl [<I2s $num DmaChannelCreator>] { impl [<I2s $num DmaChannelCreator>] {
/// 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 /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor. /// transfer buffers of size `1..=4092`, you need 1 descriptor.
@ -597,7 +651,7 @@ macro_rules! ImplI2sChannel {
tx_descriptors: &'a mut [DmaDescriptor], tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor], rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>]> { ) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Blocking> {
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {}; let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority); tx_impl.init(burst_mode, priority);
@ -607,6 +661,34 @@ macro_rules! ImplI2sChannel {
Channel { Channel {
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode), tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
rx: ChannelRx::new(rx_descriptors, rx_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, [<I2s $num DmaChannel>], $crate::Async> {
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
let mut rx_impl = [<I2s $num DmaChannelRxImpl>] {};
rx_impl.init(burst_mode, priority);
<[<I2s $num DmaChannel>] 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,
} }
} }
} }

View File

@ -111,55 +111,12 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) {
// only enable interrupts if the async feature is present // only enable interrupts if the async feature is present
#[cfg(feature = "async")] #[cfg(feature = "async")]
{ {
#[cfg(any(esp32s3, esp32c6, esp32h2))] #[cfg(rmt)]
crate::interrupt::enable(Interrupt::DMA_IN_CH0, Priority::max()).unwrap(); crate::interrupt::enable(Interrupt::RMT, Priority::min()).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(usb_device)] #[cfg(usb_device)]
crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap(); 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::I2C_EXT0, Priority::min()).unwrap();
crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap();

View File

@ -25,7 +25,6 @@
use core::{cell::Cell, convert::Infallible, marker::PhantomData}; use core::{cell::Cell, convert::Infallible, marker::PhantomData};
use critical_section::Mutex; use critical_section::Mutex;
use procmacros::handler;
#[cfg(any(adc, dac))] #[cfg(any(adc, dac))]
pub(crate) use crate::analog; pub(crate) use crate::analog;
@ -1876,7 +1875,8 @@ pub struct IO {
impl IO { impl IO {
/// Initialize the I/O driver. /// Initialize the I/O driver.
pub fn new(mut gpio: GPIO, io_mux: IO_MUX) -> Self { 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(); let pins = gpio.split();
IO { IO {
@ -1910,8 +1910,7 @@ impl IO {
} }
} }
#[handler] extern "C" fn gpio_interrupt_handler() {
fn gpio_interrupt_handler() {
if let Some(user_handler) = critical_section::with(|cs| USER_INTERRUPT_HANDLER.borrow(cs).get()) if let Some(user_handler) = critical_section::with(|cs| USER_INTERRUPT_HANDLER.borrow(cs).get())
{ {
user_handler.call(); user_handler.call();

View File

@ -68,6 +68,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use embedded_dma::{ReadBuffer, WriteBuffer}; use embedded_dma::{ReadBuffer, WriteBuffer};
use enumset::{EnumSet, EnumSetType};
use private::*; use private::*;
#[cfg(any(esp32, esp32s3))] #[cfg(any(esp32, esp32s3))]
@ -85,11 +86,23 @@ use crate::{
TxPrivate, TxPrivate,
}, },
gpio::OutputPin, gpio::OutputPin,
interrupt::InterruptHandler,
into_ref, into_ref,
peripheral::Peripheral, peripheral::Peripheral,
system::PeripheralClockControl, 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))] #[cfg(any(esp32, esp32s2, esp32s3))]
const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6; const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6;
@ -199,18 +212,20 @@ impl DataFormat {
/// An in-progress DMA write transfer. /// An in-progress DMA write transfer.
#[must_use] #[must_use]
pub struct I2sWriteDmaTransfer<'t, 'd, T, CH> pub struct I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
/// Amount of bytes which can be pushed. /// Amount of bytes which can be pushed.
/// Only useful for circular DMA transfers /// 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> { 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.i2s_tx.wait_tx_dma_done().ok(); self.i2s_tx.wait_tx_dma_done().ok();
@ -286,10 +303,11 @@ pub trait I2sWrite<W> {
} }
/// Initiate a DMA tx transfer /// Initiate a DMA tx transfer
pub trait I2sWriteDma<'d, T, CH, TXBUF> pub trait I2sWriteDma<'d, T, CH, TXBUF, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
/// Write I2S. /// Write I2S.
/// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA /// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA
@ -297,7 +315,7 @@ where
fn write_dma<'t>( fn write_dma<'t>(
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
TXBUF: ReadBuffer<Word = u8>; TXBUF: ReadBuffer<Word = u8>;
@ -306,25 +324,27 @@ where
fn write_dma_circular<'t>( fn write_dma_circular<'t>(
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
TXBUF: ReadBuffer<Word = u8>; TXBUF: ReadBuffer<Word = u8>;
} }
/// An in-progress DMA read transfer. /// An in-progress DMA read transfer.
#[must_use] #[must_use]
pub struct I2sReadDmaTransfer<'t, 'd, T, CH> pub struct I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
/// Amount of bytes which can be popped /// Amount of bytes which can be popped
pub fn available(&mut self) -> usize { 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> { 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.i2s_rx.wait_rx_dma_done().ok(); self.i2s_rx.wait_rx_dma_done().ok();
@ -392,10 +414,11 @@ pub trait I2sRead<W> {
} }
/// Initiate a DMA rx transfer /// Initiate a DMA rx transfer
pub trait I2sReadDma<'d, T, CH, RXBUF> pub trait I2sReadDma<'d, T, CH, RXBUF, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
/// Read I2S. /// Read I2S.
/// Returns [I2sReadDmaTransfer] which represents the in-progress DMA /// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
@ -403,7 +426,7 @@ where
fn read_dma<'t>( fn read_dma<'t>(
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
RXBUF: WriteBuffer<Word = u8>; RXBUF: WriteBuffer<Word = u8>;
@ -413,32 +436,35 @@ where
fn read_dma_circular<'t>( fn read_dma_circular<'t>(
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
RXBUF: WriteBuffer<Word = u8>; RXBUF: WriteBuffer<Word = u8>;
} }
/// Instance of the I2S peripheral driver /// Instance of the I2S peripheral driver
pub struct I2s<'d, I, CH> pub struct I2s<'d, I, CH, DmaMode>
where where
I: RegisterAccess, I: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
pub i2s_tx: TxCreator<'d, I, CH>, pub i2s_tx: TxCreator<'d, I, CH, DmaMode>,
pub i2s_rx: RxCreator<'d, I, CH>, pub i2s_rx: RxCreator<'d, I, CH, DmaMode>,
phantom: PhantomData<DmaMode>,
} }
impl<'d, I, CH> I2s<'d, I, CH> impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode>
where where
I: RegisterAccess, I: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn new_internal( fn new_internal(
_i2s: impl Peripheral<P = I> + 'd, _i2s: impl Peripheral<P = I> + 'd,
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
mut channel: Channel<'d, CH>, mut channel: Channel<'d, CH, DmaMode>,
clocks: &Clocks, clocks: &Clocks,
) -> Self { ) -> Self {
// on ESP32-C3 / ESP32-S3 and later RX and TX are independent and // on ESP32-C3 / ESP32-S3 and later RX and TX are independent and
@ -461,19 +487,58 @@ where
i2s_tx: TxCreator { i2s_tx: TxCreator {
register_access: PhantomData, register_access: PhantomData,
tx_channel: channel.tx, tx_channel: channel.tx,
phantom: PhantomData,
}, },
i2s_rx: RxCreator { i2s_rx: RxCreator {
register_access: PhantomData, register_access: PhantomData,
rx_channel: channel.rx, 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 where
I: RegisterAccess, I: RegisterAccess,
CH: ChannelTypes, 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<I2sInterrupt>) {
I::listen(interrupts);
}
/// Unlisten the given interrupts
pub fn unlisten(&mut self, interrupts: EnumSet<I2sInterrupt>) {
I::unlisten(interrupts);
}
/// Gets asserted interrupts
pub fn interrupts(&mut self) -> EnumSet<I2sInterrupt> {
I::interrupts()
}
/// Resets asserted interrupts
pub fn clear_interrupts(&mut self, interrupts: EnumSet<I2sInterrupt>) {
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 /// Construct a new I2S peripheral driver instance for the first I2S
/// peripheral /// peripheral
@ -482,12 +547,13 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH>, channel: Channel<'d, CH, DmaMode>,
clocks: &Clocks, clocks: &Clocks,
) -> Self ) -> Self
where where
I: I2s0Instance, I: I2s0Instance,
CH::P: I2sPeripheral + I2s0Peripheral, CH::P: I2sPeripheral + I2s0Peripheral,
DmaMode: Mode,
{ {
Self::new_internal(i2s, standard, data_format, sample_rate, channel, clocks) Self::new_internal(i2s, standard, data_format, sample_rate, channel, clocks)
} }
@ -500,7 +566,7 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH>, channel: Channel<'d, CH, DmaMode>,
clocks: &Clocks, clocks: &Clocks,
) -> Self ) -> Self
where where
@ -519,34 +585,38 @@ where
} }
/// I2S TX channel /// I2S TX channel
pub struct I2sTx<'d, T, CH> pub struct I2sTx<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
register_access: PhantomData<T>, register_access: PhantomData<T>,
tx_channel: CH::Tx<'d>, tx_channel: CH::Tx<'d>,
phantom: PhantomData<DmaMode>,
} }
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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("I2sTx").finish() f.debug_struct("I2sTx").finish()
} }
} }
impl<'d, T, CH> I2sTx<'d, T, CH> impl<'d, T, CH, DmaMode> I2sTx<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn new(tx_channel: CH::Tx<'d>) -> Self { fn new(tx_channel: CH::Tx<'d>) -> Self {
Self { Self {
register_access: PhantomData, register_access: PhantomData,
tx_channel, tx_channel,
phantom: PhantomData,
} }
} }
@ -578,9 +648,10 @@ where
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
circular: bool, circular: bool,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
DmaMode: Mode,
{ {
let (ptr, len) = unsafe { words.read_buffer() }; let (ptr, len) = unsafe { words.read_buffer() };
@ -635,11 +706,12 @@ where
} }
} }
impl<'d, T, W, CH> I2sWrite<W> for I2sTx<'d, T, CH> impl<'d, T, W, CH, DmaMode> I2sWrite<W> for I2sTx<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
W: AcceptedWord, W: AcceptedWord,
DmaMode: Mode,
{ {
fn write(&mut self, words: &[W]) -> Result<(), Error> { fn write(&mut self, words: &[W]) -> Result<(), Error> {
self.write_bytes(unsafe { 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn write_dma<'t>( fn write_dma<'t>(
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -669,7 +742,7 @@ where
fn write_dma_circular<'t>( fn write_dma_circular<'t>(
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -678,34 +751,39 @@ where
} }
/// I2S RX channel /// I2S RX channel
pub struct I2sRx<'d, T, CH> pub struct I2sRx<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
register_access: PhantomData<T>, register_access: PhantomData<T>,
rx_channel: CH::Rx<'d>, rx_channel: CH::Rx<'d>,
phantom: PhantomData<DmaMode>,
} }
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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("I2sRx").finish() f.debug_struct("I2sRx").finish()
} }
} }
impl<'d, T, CH> I2sRx<'d, T, CH> impl<'d, T, CH, DmaMode> I2sRx<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn new(rx_channel: CH::Rx<'d>) -> Self { fn new(rx_channel: CH::Rx<'d>) -> Self {
Self { Self {
register_access: PhantomData, register_access: PhantomData,
rx_channel, rx_channel,
phantom: PhantomData,
} }
} }
@ -737,7 +815,7 @@ where
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
circular: bool, circular: bool,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -809,11 +887,12 @@ where
} }
} }
impl<'d, W, T, CH> I2sRead<W> for I2sRx<'d, T, CH> impl<'d, W, T, CH, DmaMode> I2sRead<W> for I2sRx<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
W: AcceptedWord, W: AcceptedWord,
DmaMode: Mode,
{ {
fn read(&mut self, words: &mut [W]) -> Result<(), Error> { fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
if core::mem::size_of_val(words) > 4096 || words.is_empty() { 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
fn read_dma<'t>( fn read_dma<'t>(
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -847,7 +927,7 @@ where
fn read_dma_circular<'t>( fn read_dma_circular<'t>(
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error> ) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -860,9 +940,18 @@ pub trait RegisterAccess: RegisterAccessPrivate {}
mod private { mod private {
use core::marker::PhantomData; use core::marker::PhantomData;
use enumset::EnumSet;
use fugit::HertzU32; 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)))] #[cfg(not(any(esp32, esp32s3)))]
use crate::peripherals::i2s0::RegisterBlock; use crate::peripherals::i2s0::RegisterBlock;
// on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features // on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features
@ -873,26 +962,31 @@ mod private {
clock::Clocks, clock::Clocks,
dma::{ChannelTypes, DmaPeripheral}, dma::{ChannelTypes, DmaPeripheral},
gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
interrupt::InterruptHandler,
into_ref, into_ref,
peripherals::I2S0, peripherals::I2S0,
system::Peripheral, system::Peripheral,
Mode,
}; };
pub struct TxCreator<'d, T, CH> pub struct TxCreator<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
pub register_access: PhantomData<T>, pub register_access: PhantomData<T>,
pub tx_channel: CH::Tx<'d>, pub tx_channel: CH::Tx<'d>,
pub(crate) phantom: PhantomData<DmaMode>,
} }
impl<'d, T, CH> TxCreator<'d, T, CH> impl<'d, T, CH, DmaMode> TxCreator<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, 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) 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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
DmaMode: Mode,
{ {
pub register_access: PhantomData<T>, pub register_access: PhantomData<T>,
pub rx_channel: CH::Rx<'d>, pub rx_channel: CH::Rx<'d>,
pub(crate) phantom: PhantomData<DmaMode>,
} }
impl<'d, T, CH> RxCreator<'d, T, CH> impl<'d, T, CH, DmaMode> RxCreator<'d, T, CH, DmaMode>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, 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) I2sRx::new(self.rx_channel)
} }
@ -1002,6 +1099,68 @@ mod private {
#[cfg(any(esp32, esp32s2))] #[cfg(any(esp32, esp32s2))]
pub trait RegisterAccessPrivate: Signals + RegBlock { pub trait RegisterAccessPrivate: Signals + RegBlock {
fn set_interrupt_handler(handler: InterruptHandler);
fn listen(interrupts: EnumSet<I2sInterrupt>) {
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<I2sInterrupt>) {
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<I2sInterrupt> {
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<I2sInterrupt>) {
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) { fn set_clock(clock_settings: I2sClockDividers) {
let i2s = Self::register_block(); let i2s = Self::register_block();
@ -1193,6 +1352,92 @@ mod private {
#[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))]
pub trait RegisterAccessPrivate: Signals + RegBlock { pub trait RegisterAccessPrivate: Signals + RegBlock {
fn set_interrupt_handler(handler: InterruptHandler);
fn listen(interrupts: EnumSet<I2sInterrupt>) {
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<I2sInterrupt>) {
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<I2sInterrupt> {
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<I2sInterrupt>) {
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))] #[cfg(any(esp32c3, esp32s3))]
fn set_clock(clock_settings: I2sClockDividers) { fn set_clock(clock_settings: I2sClockDividers) {
let i2s = Self::register_block(); 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 {} impl super::RegisterAccess for I2S0 {}
#[cfg(any(esp32s3, esp32))] #[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))] #[cfg(any(esp32s3, esp32))]
impl super::RegisterAccess for I2S1 {} impl super::RegisterAccess for I2S1 {}
@ -1970,11 +2227,14 @@ pub mod asynch {
use embedded_dma::{ReadBuffer, WriteBuffer}; use embedded_dma::{ReadBuffer, WriteBuffer};
use super::{Error, I2sRx, I2sTx, RegisterAccess}; use super::{Error, I2sRx, I2sTx, RegisterAccess};
use crate::dma::{ use crate::{
asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture}, dma::{
ChannelTypes, asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture},
RxPrivate, ChannelTypes,
TxPrivate, RxPrivate,
TxPrivate,
},
Async,
}; };
/// Initiate an async DMA tx transfer /// Initiate an async DMA tx transfer
@ -1995,7 +2255,7 @@ pub mod asynch {
TXBUF: ReadBuffer<Word = u8>; TXBUF: ReadBuffer<Word = u8>;
} }
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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
@ -2039,7 +2299,7 @@ pub mod asynch {
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
i2s_tx: I2sTx<'d, T, CH>, i2s_tx: I2sTx<'d, T, CH, Async>,
_buffer: BUFFER, _buffer: BUFFER,
} }
@ -2102,7 +2362,7 @@ pub mod asynch {
RXBUF: WriteBuffer<Word = u8>; RXBUF: WriteBuffer<Word = u8>;
} }
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 where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
@ -2146,7 +2406,7 @@ pub mod asynch {
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
i2s_rx: I2sRx<'d, T, CH>, i2s_rx: I2sRx<'d, T, CH, Async>,
_buffer: BUFFER, _buffer: BUFFER,
} }

View File

@ -77,7 +77,10 @@
//! transfer.wait().unwrap(); //! transfer.wait().unwrap();
//! ``` //! ```
use core::marker::PhantomData;
use embedded_dma::{ReadBuffer, WriteBuffer}; use embedded_dma::{ReadBuffer, WriteBuffer};
use enumset::{EnumSet, EnumSetType};
use fugit::HertzU32; use fugit::HertzU32;
use peripheral::PeripheralRef; use peripheral::PeripheralRef;
use private::*; use private::*;
@ -86,14 +89,24 @@ use crate::{
clock::Clocks, clock::Clocks,
dma::{Channel, ChannelTypes, DmaError, DmaPeripheral, ParlIoPeripheral, RxPrivate, TxPrivate}, dma::{Channel, ChannelTypes, DmaError, DmaPeripheral, ParlIoPeripheral, RxPrivate, TxPrivate},
gpio::{InputPin, OutputPin}, gpio::{InputPin, OutputPin},
interrupt::InterruptHandler,
peripheral::{self, Peripheral}, peripheral::{self, Peripheral},
peripherals, peripherals,
system::PeripheralClockControl, system::PeripheralClockControl,
Blocking,
Mode,
}; };
#[allow(unused)] #[allow(unused)]
const MAX_DMA_SIZE: usize = 32736; const MAX_DMA_SIZE: usize = 32736;
#[derive(EnumSetType)]
pub enum ParlIoInterrupt {
TxFifoReEmpty,
RxFifoWOvf,
TxEof,
}
/// Parallel IO errors /// Parallel IO errors
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[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 where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub fn with_config<P, CP>( pub fn with_config<P, CP>(
self, self,
@ -848,7 +862,7 @@ where
idle_value: u16, idle_value: u16,
sample_edge: SampleEdge, sample_edge: SampleEdge,
bit_order: BitPackOrder, bit_order: BitPackOrder,
) -> Result<ParlIoTx<'d, CH, P, CP>, Error> ) -> Result<ParlIoTx<'d, CH, P, CP, DM>, Error>
where where
P: FullDuplex + TxPins + ConfigurePins, P: FullDuplex + TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
@ -864,13 +878,15 @@ where
tx_channel: self.tx_channel, tx_channel: self.tx_channel,
_pins: tx_pins, _pins: tx_pins,
_clk_pin: clk_pin, _clk_pin: clk_pin,
phantom: PhantomData,
}) })
} }
} }
impl<'d, CH> TxCreator<'d, CH> impl<'d, CH, DM> TxCreator<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub fn with_config<P, CP>( pub fn with_config<P, CP>(
self, self,
@ -879,7 +895,7 @@ where
idle_value: u16, idle_value: u16,
sample_edge: SampleEdge, sample_edge: SampleEdge,
bit_order: BitPackOrder, bit_order: BitPackOrder,
) -> Result<ParlIoTx<'d, CH, P, CP>, Error> ) -> Result<ParlIoTx<'d, CH, P, CP, DM>, Error>
where where
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
@ -895,36 +911,41 @@ where
tx_channel: self.tx_channel, tx_channel: self.tx_channel,
_pins: tx_pins, _pins: tx_pins,
_clk_pin: clk_pin, _clk_pin: clk_pin,
phantom: PhantomData,
}) })
} }
} }
/// Parallel IO TX channel /// Parallel IO TX channel
pub struct ParlIoTx<'d, CH, P, CP> pub struct ParlIoTx<'d, CH, P, CP, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
DM: Mode,
{ {
tx_channel: CH::Tx<'d>, tx_channel: CH::Tx<'d>,
_pins: P, _pins: P,
_clk_pin: CP, _clk_pin: CP,
phantom: PhantomData<DM>,
} }
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 where
CH: ChannelTypes, CH: ChannelTypes,
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
DM: Mode,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ParlIoTx").finish() f.debug_struct("ParlIoTx").finish()
} }
} }
impl<'d, CH> RxCreatorFullDuplex<'d, CH> impl<'d, CH, DM> RxCreatorFullDuplex<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub fn with_config<P, CP>( pub fn with_config<P, CP>(
self, self,
@ -932,7 +953,7 @@ where
mut clk_pin: CP, mut clk_pin: CP,
bit_order: BitPackOrder, bit_order: BitPackOrder,
timeout_ticks: Option<u16>, timeout_ticks: Option<u16>,
) -> Result<ParlIoRx<'d, CH, P, CP>, Error> ) -> Result<ParlIoRx<'d, CH, P, CP, DM>, Error>
where where
P: FullDuplex + RxPins + ConfigurePins, P: FullDuplex + RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
@ -947,13 +968,15 @@ where
rx_channel: self.rx_channel, rx_channel: self.rx_channel,
_pins: rx_pins, _pins: rx_pins,
_clk_pin: clk_pin, _clk_pin: clk_pin,
phantom: PhantomData,
}) })
} }
} }
impl<'d, CH> RxCreator<'d, CH> impl<'d, CH, DM> RxCreator<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub fn with_config<P, CP>( pub fn with_config<P, CP>(
self, self,
@ -961,7 +984,7 @@ where
mut clk_pin: CP, mut clk_pin: CP,
bit_order: BitPackOrder, bit_order: BitPackOrder,
timeout_ticks: Option<u16>, timeout_ticks: Option<u16>,
) -> Result<ParlIoRx<'d, CH, P, CP>, Error> ) -> Result<ParlIoRx<'d, CH, P, CP, DM>, Error>
where where
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
@ -976,142 +999,343 @@ where
rx_channel: self.rx_channel, rx_channel: self.rx_channel,
_pins: rx_pins, _pins: rx_pins,
_clk_pin: clk_pin, _clk_pin: clk_pin,
phantom: PhantomData,
}) })
} }
} }
/// Parallel IO RX channel /// Parallel IO RX channel
pub struct ParlIoRx<'d, CH, P, CP> pub struct ParlIoRx<'d, CH, P, CP, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
DM: Mode,
{ {
rx_channel: CH::Rx<'d>, rx_channel: CH::Rx<'d>,
_pins: P, _pins: P,
_clk_pin: CP, _clk_pin: CP,
phantom: PhantomData<DM>,
} }
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 where
CH: ChannelTypes, CH: ChannelTypes,
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
DM: Mode,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ParlIoTx").finish() 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<ParlIoInterrupt>) {
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<ParlIoInterrupt>) {
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<ParlIoInterrupt> {
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<ParlIoInterrupt>) {
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 /// Parallel IO in full duplex mode
/// ///
/// Full duplex mode might limit the maximum possible bit width. /// Full duplex mode might limit the maximum possible bit width.
pub struct ParlIoFullDuplex<'d, CH> pub struct ParlIoFullDuplex<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
DM: Mode,
{ {
_parl_io: PeripheralRef<'d, peripherals::PARL_IO>, pub tx: TxCreatorFullDuplex<'d, CH, DM>,
pub tx: TxCreatorFullDuplex<'d, CH>, pub rx: RxCreatorFullDuplex<'d, CH, DM>,
pub rx: RxCreatorFullDuplex<'d, CH>,
} }
impl<'d, CH> ParlIoFullDuplex<'d, CH> impl<'d, CH, DM> ParlIoFullDuplex<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
DM: Mode,
{ {
pub fn new( pub fn new(
parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
mut dma_channel: Channel<'d, CH>, mut dma_channel: Channel<'d, CH, DM>,
frequency: HertzU32, frequency: HertzU32,
_clocks: &Clocks, _clocks: &Clocks,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
crate::into_ref!(parl_io);
internal_init(&mut dma_channel, frequency)?; internal_init(&mut dma_channel, frequency)?;
Ok(Self { Ok(Self {
_parl_io: parl_io,
tx: TxCreatorFullDuplex { tx: TxCreatorFullDuplex {
tx_channel: dma_channel.tx, tx_channel: dma_channel.tx,
phantom: PhantomData,
}, },
rx: RxCreatorFullDuplex { rx: RxCreatorFullDuplex {
rx_channel: dma_channel.rx, 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<ParlIoInterrupt>) {
internal_listen(interrupts);
}
/// Unlisten the given interrupts
pub fn unlisten(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
internal_unlisten(interrupts);
}
/// Gets asserted interrupts
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
internal_interrupts()
}
/// Resets asserted interrupts
pub fn clear_interrupts(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
internal_clear_interrupts(interrupts);
}
}
/// Parallel IO in half duplex / TX only mode /// Parallel IO in half duplex / TX only mode
pub struct ParlIoTxOnly<'d, CH> pub struct ParlIoTxOnly<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
DM: Mode,
{ {
_parl_io: PeripheralRef<'d, peripherals::PARL_IO>, pub tx: TxCreator<'d, CH, DM>,
pub tx: TxCreator<'d, CH>,
} }
impl<'d, CH> ParlIoTxOnly<'d, CH> impl<'d, CH, DM> ParlIoTxOnly<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
DM: Mode,
{ {
pub fn new( pub fn new(
parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
mut dma_channel: Channel<'d, CH>, mut dma_channel: Channel<'d, CH, DM>,
frequency: HertzU32, frequency: HertzU32,
_clocks: &Clocks, _clocks: &Clocks,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
crate::into_ref!(parl_io);
internal_init(&mut dma_channel, frequency)?; internal_init(&mut dma_channel, frequency)?;
Ok(Self { Ok(Self {
_parl_io: parl_io,
tx: TxCreator { tx: TxCreator {
tx_channel: dma_channel.tx, 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<ParlIoInterrupt>) {
internal_listen(interrupts);
}
/// Unlisten the given interrupts
pub fn unlisten(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
internal_unlisten(interrupts);
}
/// Gets asserted interrupts
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
internal_interrupts()
}
/// Resets asserted interrupts
pub fn clear_interrupts(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
internal_clear_interrupts(interrupts);
}
}
/// Parallel IO in half duplex / RX only mode /// Parallel IO in half duplex / RX only mode
pub struct ParlIoRxOnly<'d, CH> pub struct ParlIoRxOnly<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
DM: Mode,
{ {
_parl_io: PeripheralRef<'d, peripherals::PARL_IO>, pub rx: RxCreator<'d, CH, DM>,
pub rx: RxCreator<'d, CH>,
} }
impl<'d, CH> ParlIoRxOnly<'d, CH> impl<'d, CH, DM> ParlIoRxOnly<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
DM: Mode,
{ {
pub fn new( pub fn new(
parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
mut dma_channel: Channel<'d, CH>, mut dma_channel: Channel<'d, CH, DM>,
frequency: HertzU32, frequency: HertzU32,
_clocks: &Clocks, _clocks: &Clocks,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
crate::into_ref!(parl_io);
internal_init(&mut dma_channel, frequency)?; internal_init(&mut dma_channel, frequency)?;
Ok(Self { Ok(Self {
_parl_io: parl_io,
rx: RxCreator { rx: RxCreator {
rx_channel: dma_channel.rx, rx_channel: dma_channel.rx,
phantom: PhantomData,
}, },
}) })
} }
} }
fn internal_init<CH>(dma_channel: &mut Channel<'_, CH>, frequency: HertzU32) -> Result<(), Error> impl<'d, CH> ParlIoRxOnly<'d, CH, Blocking>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, 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<ParlIoInterrupt>) {
internal_listen(interrupts);
}
/// Unlisten the given interrupts
pub fn unlisten(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
internal_unlisten(interrupts);
}
/// Gets asserted interrupts
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
internal_interrupts()
}
/// Resets asserted interrupts
pub fn clear_interrupts(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
internal_clear_interrupts(interrupts);
}
}
fn internal_init<CH, DM>(
dma_channel: &mut Channel<'_, CH, DM>,
frequency: HertzU32,
) -> Result<(), Error>
where
CH: ChannelTypes,
CH::P: ParlIoPeripheral,
DM: Mode,
{ {
if frequency.raw() > 40_000_000 { if frequency.raw() > 40_000_000 {
return Err(Error::UnreachableClockRate); return Err(Error::UnreachableClockRate);
@ -1152,12 +1376,13 @@ where
Ok(()) Ok(())
} }
impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP> impl<'d, CH, P, CP, DM> ParlIoTx<'d, CH, P, CP, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
DM: Mode,
{ {
/// Perform a DMA write. /// Perform a DMA write.
/// ///
@ -1168,7 +1393,7 @@ where
pub fn write_dma<'t, TXBUF>( pub fn write_dma<'t, TXBUF>(
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
) -> Result<DmaTransfer<'t, 'd, CH, P, CP>, Error> ) -> Result<DmaTransfer<'t, 'd, CH, P, CP, DM>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1212,22 +1437,24 @@ where
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
#[must_use] #[must_use]
pub struct DmaTransfer<'t, 'd, C, P, CP> pub struct DmaTransfer<'t, 'd, C, P, CP, DM>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, 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 where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
DM: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
#[allow(clippy::type_complexity)] #[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 where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
DM: Mode,
{ {
/// Perform a DMA read. /// Perform a DMA read.
/// ///
@ -1271,7 +1499,7 @@ where
pub fn read_dma<'t, RXBUF>( pub fn read_dma<'t, RXBUF>(
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
) -> Result<RxDmaTransfer<'t, 'd, CH, P, CP>, Error> ) -> Result<RxDmaTransfer<'t, 'd, CH, P, CP, DM>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1308,22 +1536,24 @@ where
} }
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
pub struct RxDmaTransfer<'t, 'd, C, P, CP> pub struct RxDmaTransfer<'t, 'd, C, P, CP, DM>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, 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 where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
DM: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
@ -1362,6 +1592,7 @@ pub mod asynch {
use core::task::Poll; use core::task::Poll;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use procmacros::handler;
use super::{ use super::{
private::{ConfigurePins, Instance, RxClkPin, RxPins, TxClkPin, TxPins}, private::{ConfigurePins, Instance, RxClkPin, RxPins, TxClkPin, TxPins},
@ -1372,7 +1603,7 @@ pub mod asynch {
}; };
use crate::{ use crate::{
dma::{asynch::DmaRxDoneChFuture, ChannelTypes, ParlIoPeripheral}, dma::{asynch::DmaRxDoneChFuture, ChannelTypes, ParlIoPeripheral},
macros::interrupt, peripherals::Interrupt,
}; };
static TX_WAKER: AtomicWaker = AtomicWaker::new(); static TX_WAKER: AtomicWaker = AtomicWaker::new();
@ -1393,6 +1624,20 @@ pub mod asynch {
self: core::pin::Pin<&mut Self>, self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>, cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> { ) -> Poll<Self::Output> {
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()); TX_WAKER.register(cx.waker());
if Instance::is_listening_tx_done() { if Instance::is_listening_tx_done() {
Poll::Pending Poll::Pending
@ -1402,9 +1647,8 @@ pub mod asynch {
} }
} }
#[cfg(esp32c6)] #[handler]
#[interrupt] fn interrupt_handler() {
fn PARL_IO() {
if Instance::is_tx_done_set() { if Instance::is_tx_done_set() {
Instance::clear_is_tx_done(); Instance::clear_is_tx_done();
Instance::unlisten_tx_done(); Instance::unlisten_tx_done();
@ -1412,17 +1656,7 @@ pub mod asynch {
} }
} }
#[cfg(esp32h2)] impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP, crate::Async>
#[interrupt]
fn PARL_IO_TX() {
if Instance::is_tx_done_set() {
Instance::clear_is_tx_done();
Instance::unlisten_tx_done();
TX_WAKER.wake()
}
}
impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP>
where where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, 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 where
CH: ChannelTypes, CH: ChannelTypes,
CH::P: ParlIoPeripheral, CH::P: ParlIoPeripheral,
@ -1476,8 +1710,10 @@ pub mod asynch {
} }
mod private { mod private {
use core::marker::PhantomData;
use super::{BitPackOrder, EofMode, Error, SampleEdge}; use super::{BitPackOrder, EofMode, Error, SampleEdge};
use crate::dma::ChannelTypes; use crate::{dma::ChannelTypes, Mode};
pub trait FullDuplex {} pub trait FullDuplex {}
@ -1501,32 +1737,40 @@ mod private {
fn configure(&mut self) -> Result<(), Error>; fn configure(&mut self) -> Result<(), Error>;
} }
pub struct TxCreator<'d, CH> pub struct TxCreator<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub tx_channel: CH::Tx<'d>, pub tx_channel: CH::Tx<'d>,
pub(crate) phantom: PhantomData<DM>,
} }
pub struct RxCreator<'d, CH> pub struct RxCreator<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub rx_channel: CH::Rx<'d>, pub rx_channel: CH::Rx<'d>,
pub(crate) phantom: PhantomData<DM>,
} }
pub struct TxCreatorFullDuplex<'d, CH> pub struct TxCreatorFullDuplex<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub tx_channel: CH::Tx<'d>, pub tx_channel: CH::Tx<'d>,
pub(crate) phantom: PhantomData<DM>,
} }
pub struct RxCreatorFullDuplex<'d, CH> pub struct RxCreatorFullDuplex<'d, CH, DM>
where where
CH: ChannelTypes, CH: ChannelTypes,
DM: Mode,
{ {
pub rx_channel: CH::Rx<'d>, pub rx_channel: CH::Rx<'d>,
pub(crate) phantom: PhantomData<DM>,
} }
#[cfg(esp32c6)] #[cfg(esp32c6)]
@ -1670,7 +1914,7 @@ mod private {
reg_block reg_block
.int_clr() .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) { pub fn set_rx_bytes(len: u16) {

View File

@ -37,8 +37,8 @@ crate::peripherals! {
HINF <= HINF, HINF <= HINF,
I2C0 <= I2C0, I2C0 <= I2C0,
I2C1 <= I2C1, I2C1 <= I2C1,
I2S0 <= I2S0, I2S0 <= I2S0 (I2S0),
I2S1 <= I2S1, I2S1 <= I2S1 (I2S1),
IO_MUX <= IO_MUX, IO_MUX <= IO_MUX,
LEDC <= LEDC, LEDC <= LEDC,
MCPWM0 <= MCPWM0, MCPWM0 <= MCPWM0,
@ -58,8 +58,8 @@ crate::peripherals! {
SLCHOST <= SLCHOST, SLCHOST <= SLCHOST,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2, SPI2 <= SPI2 (SPI2_DMA, SPI2),
SPI3 <= SPI3, SPI3 <= SPI3 (SPI3_DMA, SPI3),
SYSTEM <= DPORT, SYSTEM <= DPORT,
TIMG0 <= TIMG0, TIMG0 <= TIMG0,
TIMG1 <= TIMG1, TIMG1 <= TIMG1,

View File

@ -24,7 +24,7 @@ crate::peripherals! {
APB_CTRL <= APB_CTRL, APB_CTRL <= APB_CTRL,
ASSIST_DEBUG <= ASSIST_DEBUG, ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual, BT <= virtual,
DMA <= DMA, DMA <= DMA (DMA_CH0),
ECC <= ECC, ECC <= ECC,
EFUSE <= EFUSE, EFUSE <= EFUSE,
EXTMEM <= EXTMEM, EXTMEM <= EXTMEM,
@ -39,7 +39,7 @@ crate::peripherals! {
SHA <= SHA, SHA <= SHA,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2, SPI2 <= SPI2 (SPI2),
SYSTEM <= SYSTEM, SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER, SYSTIMER <= SYSTIMER,
TIMG0 <= TIMG0, TIMG0 <= TIMG0,

View File

@ -26,7 +26,7 @@ crate::peripherals! {
APB_CTRL <= APB_CTRL, APB_CTRL <= APB_CTRL,
ASSIST_DEBUG <= ASSIST_DEBUG, ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual, BT <= virtual,
DMA <= DMA, DMA <= DMA (DMA_CH0,DMA_CH1,DMA_CH2),
DS <= DS, DS <= DS,
EFUSE <= EFUSE, EFUSE <= EFUSE,
EXTMEM <= EXTMEM, EXTMEM <= EXTMEM,
@ -34,7 +34,7 @@ crate::peripherals! {
GPIO_SD <= GPIO_SD, GPIO_SD <= GPIO_SD,
HMAC <= HMAC, HMAC <= HMAC,
I2C0 <= I2C0, I2C0 <= I2C0,
I2S0 <= I2S0, I2S0 <= I2S0 (I2S0),
INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE0 <= INTERRUPT_CORE0,
IO_MUX <= IO_MUX, IO_MUX <= IO_MUX,
LEDC <= LEDC, LEDC <= LEDC,
@ -46,7 +46,7 @@ crate::peripherals! {
SHA <= SHA, SHA <= SHA,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2, SPI2 <= SPI2 (SPI2),
SYSTEM <= SYSTEM, SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER, SYSTIMER <= SYSTIMER,
TIMG0 <= TIMG0, TIMG0 <= TIMG0,

View File

@ -25,7 +25,7 @@ crate::peripherals! {
ASSIST_DEBUG <= ASSIST_DEBUG, ASSIST_DEBUG <= ASSIST_DEBUG,
ATOMIC <= ATOMIC, ATOMIC <= ATOMIC,
BT <= virtual, 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, DS <= DS,
ECC <= ECC, ECC <= ECC,
EFUSE <= EFUSE, EFUSE <= EFUSE,
@ -37,7 +37,7 @@ crate::peripherals! {
HP_APM <= HP_APM, HP_APM <= HP_APM,
HP_SYS <= HP_SYS, HP_SYS <= HP_SYS,
I2C0 <= I2C0, I2C0 <= I2C0,
I2S0 <= I2S0, I2S0 <= I2S0 (I2S0),
IEEE802154 <= virtual, IEEE802154 <= virtual,
INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTPRI <= INTPRI, INTPRI <= INTPRI,
@ -60,7 +60,7 @@ crate::peripherals! {
MCPWM0 <= MCPWM0, MCPWM0 <= MCPWM0,
MEM_MONITOR <= MEM_MONITOR, MEM_MONITOR <= MEM_MONITOR,
OTP_DEBUG <= OTP_DEBUG, OTP_DEBUG <= OTP_DEBUG,
PARL_IO <= PARL_IO, PARL_IO <= PARL_IO (PARL_IO),
PAU <= PAU, PAU <= PAU,
PCNT <= PCNT, PCNT <= PCNT,
PMU <= PMU, PMU <= PMU,
@ -72,7 +72,7 @@ crate::peripherals! {
SOC_ETM <= SOC_ETM, SOC_ETM <= SOC_ETM,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2, SPI2 <= SPI2 (SPI2),
SYSTEM <= PCR, SYSTEM <= PCR,
SYSTIMER <= SYSTIMER, SYSTIMER <= SYSTIMER,
TEE <= TEE, TEE <= TEE,

View File

@ -24,7 +24,7 @@ crate::peripherals! {
AES <= AES, AES <= AES,
ASSIST_DEBUG <= ASSIST_DEBUG, ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual, 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, DS <= DS,
ECC <= ECC, ECC <= ECC,
EFUSE <= EFUSE, EFUSE <= EFUSE,
@ -35,7 +35,7 @@ crate::peripherals! {
HP_SYS <= HP_SYS, HP_SYS <= HP_SYS,
I2C0 <= I2C0, I2C0 <= I2C0,
I2C1 <= I2C1, I2C1 <= I2C1,
I2S0 <= I2S0, I2S0 <= I2S0 (I2S0),
IEEE802154 <= virtual, IEEE802154 <= virtual,
INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTPRI <= INTPRI, INTPRI <= INTPRI,
@ -53,7 +53,7 @@ crate::peripherals! {
MODEM_LPCON <= MODEM_LPCON, MODEM_LPCON <= MODEM_LPCON,
MODEM_SYSCON <= MODEM_SYSCON, MODEM_SYSCON <= MODEM_SYSCON,
OTP_DEBUG <= OTP_DEBUG, OTP_DEBUG <= OTP_DEBUG,
PARL_IO <= PARL_IO, PARL_IO <= PARL_IO (PARL_IO_TX, PARL_IO_RX),
PAU <= PAU, PAU <= PAU,
PCNT <= PCNT, PCNT <= PCNT,
PMU <= PMU, PMU <= PMU,
@ -64,7 +64,7 @@ crate::peripherals! {
SOC_ETM <= SOC_ETM, SOC_ETM <= SOC_ETM,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2, SPI2 <= SPI2 (SPI2),
SYSTEM <= PCR, SYSTEM <= PCR,
SYSTIMER <= SYSTIMER, SYSTIMER <= SYSTIMER,
TEE <= TEE, TEE <= TEE,

View File

@ -35,7 +35,7 @@ crate::peripherals! {
HMAC <= HMAC, HMAC <= HMAC,
I2C0 <= I2C0, I2C0 <= I2C0,
I2C1 <= I2C1, I2C1 <= I2C1,
I2S0 <= I2S0, I2S0 <= I2S0 (I2S0),
INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE0 <= INTERRUPT_CORE0,
IO_MUX <= IO_MUX, IO_MUX <= IO_MUX,
LEDC <= LEDC, LEDC <= LEDC,
@ -51,8 +51,8 @@ crate::peripherals! {
SHA <= SHA, SHA <= SHA,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2, SPI2 <= SPI2 (SPI2_DMA, SPI2),
SPI3 <= SPI3, SPI3 <= SPI3 (SPI3_DMA, SPI3),
SPI4 <= SPI4, SPI4 <= SPI4,
SYSCON <= SYSCON, SYSCON <= SYSCON,
SYSTEM <= SYSTEM, SYSTEM <= SYSTEM,

View File

@ -26,7 +26,7 @@ crate::peripherals! {
APB_CTRL <= APB_CTRL, APB_CTRL <= APB_CTRL,
ASSIST_DEBUG <= ASSIST_DEBUG, ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual, 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, DS <= DS,
EFUSE <= EFUSE, EFUSE <= EFUSE,
EXTMEM <= EXTMEM, EXTMEM <= EXTMEM,
@ -35,8 +35,8 @@ crate::peripherals! {
HMAC <= HMAC, HMAC <= HMAC,
I2C0 <= I2C0, I2C0 <= I2C0,
I2C1 <= I2C1, I2C1 <= I2C1,
I2S0 <= I2S0, I2S0 <= I2S0 (I2S0),
I2S1 <= I2S1, I2S1 <= I2S1 (I2S1),
INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTERRUPT_CORE1 <= INTERRUPT_CORE1, INTERRUPT_CORE1 <= INTERRUPT_CORE1,
IO_MUX <= IO_MUX, IO_MUX <= IO_MUX,
@ -57,8 +57,8 @@ crate::peripherals! {
SHA <= SHA, SHA <= SHA,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2, SPI2 <= SPI2 (SPI2),
SPI3 <= SPI3, SPI3 <= SPI3 (SPI3),
SYSTEM <= SYSTEM, SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER, SYSTIMER <= SYSTIMER,
TIMG0 <= TIMG0, TIMG0 <= TIMG0,

View File

@ -49,6 +49,10 @@
use core::marker::PhantomData; use core::marker::PhantomData;
#[cfg(not(any(esp32, esp32s2)))]
use enumset::EnumSet;
#[cfg(not(any(esp32, esp32s2)))]
use enumset::EnumSetType;
use fugit::HertzU32; use fugit::HertzU32;
#[cfg(feature = "place-spi-driver-in-ram")] #[cfg(feature = "place-spi-driver-in-ram")]
use procmacros::ram; use procmacros::ram;
@ -67,6 +71,7 @@ use crate::{
clock::Clocks, clock::Clocks,
dma::{DmaPeripheral, Rx, Tx}, dma::{DmaPeripheral, Rx, Tx},
gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::spi2::RegisterBlock, peripherals::spi2::RegisterBlock,
system::PeripheralClockControl, 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 /// The size of the FIFO buffer for SPI
#[cfg(not(esp32s2))] #[cfg(not(esp32s2))]
const FIFO_SIZE: usize = 64; const FIFO_SIZE: usize = 64;
@ -780,37 +791,47 @@ pub mod dma {
TxPrivate, TxPrivate,
}, },
FlashSafeDma, FlashSafeDma,
Mode,
}; };
pub trait WithDmaSpi2<'d, C, M> pub trait WithDmaSpi2<'d, C, M, DmaMode>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, 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)] #[cfg(spi3)]
pub trait WithDmaSpi3<'d, C, M> pub trait WithDmaSpi3<'d, C, M, DmaMode>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, 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 where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral + Spi2Peripheral, C::P: SpiPeripheral + Spi2Peripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
fn with_dma( fn with_dma(
self, self,
mut channel: Channel<'d, C>, mut channel: Channel<'d, C, DmaMode>,
) -> SpiDma<'d, crate::peripherals::SPI2, C, M> { ) -> SpiDma<'d, crate::peripherals::SPI2, C, M, DmaMode> {
channel.tx.init_channel(); // no need to call this for both, TX and RX channel.tx.init_channel(); // no need to call this for both, TX and RX
SpiDma { SpiDma {
@ -822,16 +843,17 @@ pub mod dma {
} }
#[cfg(spi3)] #[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 where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral + Spi3Peripheral, C::P: SpiPeripheral + Spi3Peripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
fn with_dma( fn with_dma(
self, self,
mut channel: Channel<'d, C>, mut channel: Channel<'d, C, DmaMode>,
) -> SpiDma<'d, crate::peripherals::SPI3, C, M> { ) -> SpiDma<'d, crate::peripherals::SPI3, C, M, DmaMode> {
channel.tx.init_channel(); // no need to call this for both, TX and RX channel.tx.init_channel(); // no need to call this for both, TX and RX
SpiDma { SpiDma {
@ -843,22 +865,24 @@ pub mod dma {
} }
/// An in-progress DMA transfer /// An in-progress DMA transfer
#[must_use] #[must_use]
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M> pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> { 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.spi_dma.spi.flush().ok(); self.spi_dma.spi.flush().ok();
@ -894,22 +919,24 @@ pub mod dma {
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
#[must_use] #[must_use]
pub struct SpiDmaTransfer<'t, 'd, T, C, M> pub struct SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> { 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.spi_dma.spi.flush().ok(); self.spi_dma.spi.flush().ok();
@ -944,46 +972,91 @@ pub mod dma {
} }
/// A DMA capable SPI instance. /// A DMA capable SPI instance.
pub struct SpiDma<'d, T, C, M> pub struct SpiDma<'d, T, C, M, DmaMode>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<'d, C>, pub(crate) channel: Channel<'d, C, DmaMode>,
_mode: PhantomData<M>, _mode: PhantomData<M>,
} }
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 where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
DmaMode: Mode,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SpiDma").finish() 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, 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<SpiInterrupt>) {
self.spi.listen(interrupts);
}
/// Unlisten the given interrupts
#[cfg(not(any(esp32, esp32s2)))]
pub fn unlisten(&mut self, interrupts: EnumSet<SpiInterrupt>) {
self.spi.unlisten(interrupts);
}
/// Gets asserted interrupts
#[cfg(not(any(esp32, esp32s2)))]
pub fn interrupts(&mut self) -> EnumSet<SpiInterrupt> {
self.spi.interrupts()
}
/// Resets asserted interrupts
#[cfg(not(any(esp32, esp32s2)))]
pub fn clear_interrupts(&mut self, interrupts: EnumSet<SpiInterrupt>) {
self.spi.clear_interrupts(interrupts);
}
}
impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{ {
pub fn change_bus_frequency(&mut self, frequency: HertzU32, clocks: &Clocks) { pub fn change_bus_frequency(&mut self, frequency: HertzU32, clocks: &Clocks) {
self.spi.ch_bus_freq(frequency, 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
DmaMode: Mode,
{ {
/// Perform a DMA write. /// Perform a DMA write.
/// ///
@ -994,7 +1067,7 @@ pub mod dma {
pub fn dma_write<'t, TXBUF>( pub fn dma_write<'t, TXBUF>(
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1018,7 +1091,7 @@ pub mod dma {
pub fn dma_read<'t, RXBUF>( pub fn dma_read<'t, RXBUF>(
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1042,7 +1115,7 @@ pub mod dma {
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
read_buffer: &'t mut RXBUF, read_buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, M>, super::Error> ) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
@ -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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: IsHalfDuplex, M: IsHalfDuplex,
DmaMode: Mode,
{ {
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)] #[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
pub fn read<'t, RXBUF>( pub fn read<'t, RXBUF>(
@ -1082,7 +1156,7 @@ pub mod dma {
address: Address, address: Address,
dummy: u8, dummy: u8,
buffer: &'t mut RXBUF, buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1153,7 +1227,7 @@ pub mod dma {
address: Address, address: Address,
dummy: u8, dummy: u8,
buffer: &'t TXBUF, buffer: &'t TXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1218,12 +1292,14 @@ pub mod dma {
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<'d, T, C, M> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDma<'d, T, C, M> impl<'d, T, C, M, DmaMode> embedded_hal_02::blocking::spi::Transfer<u8>
for SpiDma<'d, T, C, M, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
DmaMode: Mode,
{ {
type Error = super::Error; type Error = super::Error;
@ -1234,12 +1310,14 @@ pub mod dma {
} }
#[cfg(feature = "embedded-hal-02")] #[cfg(feature = "embedded-hal-02")]
impl<'d, T, C, M> embedded_hal_02::blocking::spi::Write<u8> for SpiDma<'d, T, C, M> impl<'d, T, C, M, DmaMode> embedded_hal_02::blocking::spi::Write<u8>
for SpiDma<'d, T, C, M, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
DmaMode: Mode,
{ {
type Error = super::Error; type Error = super::Error;
@ -1308,7 +1386,7 @@ pub mod dma {
mod asynch { mod asynch {
use super::*; 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -1468,7 +1546,7 @@ pub mod dma {
use super::*; 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -1478,7 +1556,7 @@ pub mod dma {
type Error = Error; 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -2361,6 +2439,72 @@ pub trait Instance: crate::private::Sealed {
.write(|w| unsafe { w.bits(reg_val) }); .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<SpiInterrupt>) {
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<SpiInterrupt>) {
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<SpiInterrupt> {
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<SpiInterrupt>) {
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))] #[cfg(not(esp32))]
fn set_data_mode(&mut self, data_mode: SpiMode) -> &mut Self { fn set_data_mode(&mut self, data_mode: SpiMode) -> &mut Self {
let reg_block = self.register_block(); let reg_block = self.register_block();
@ -2837,6 +2981,12 @@ impl Instance for crate::peripherals::SPI2 {
self 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)] #[inline(always)]
fn sclk_signal(&self) -> OutputSignal { fn sclk_signal(&self) -> OutputSignal {
OutputSignal::FSPICLK_MUX OutputSignal::FSPICLK_MUX
@ -2908,6 +3058,12 @@ impl Instance for crate::peripherals::SPI2 {
self 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)] #[inline(always)]
fn sclk_signal(&self) -> OutputSignal { fn sclk_signal(&self) -> OutputSignal {
OutputSignal::HSPICLK OutputSignal::HSPICLK
@ -2973,6 +3129,12 @@ impl Instance for crate::peripherals::SPI3 {
self 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)] #[inline(always)]
fn sclk_signal(&self) -> OutputSignal { fn sclk_signal(&self) -> OutputSignal {
OutputSignal::VSPICLK OutputSignal::VSPICLK
@ -3011,6 +3173,12 @@ impl Instance for crate::peripherals::SPI2 {
self 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)] #[inline(always)]
fn sclk_signal(&self) -> OutputSignal { fn sclk_signal(&self) -> OutputSignal {
OutputSignal::FSPICLK OutputSignal::FSPICLK
@ -3082,6 +3250,12 @@ impl Instance for crate::peripherals::SPI3 {
self 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)] #[inline(always)]
fn sclk_signal(&self) -> OutputSignal { fn sclk_signal(&self) -> OutputSignal {
OutputSignal::SPI3_CLK OutputSignal::SPI3_CLK

View File

@ -142,41 +142,57 @@ pub mod dma {
use super::*; use super::*;
#[cfg(spi3)] #[cfg(spi3)]
use crate::dma::Spi3Peripheral; use crate::dma::Spi3Peripheral;
use crate::dma::{ use crate::{
Channel, dma::{
ChannelTypes, Channel,
DmaError, ChannelTypes,
DmaTransfer, DmaError,
DmaTransferRxTx, DmaTransfer,
RxPrivate, DmaTransferRxTx,
Spi2Peripheral, RxPrivate,
SpiPeripheral, Spi2Peripheral,
TxPrivate, SpiPeripheral,
TxPrivate,
},
Mode,
}; };
pub trait WithDmaSpi2<'d, C> pub trait WithDmaSpi2<'d, C, DmaMode>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, 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)] #[cfg(spi3)]
pub trait WithDmaSpi3<'d, C> pub trait WithDmaSpi3<'d, C, DmaMode>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, 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 where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral + Spi2Peripheral, 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 channel.tx.init_channel(); // no need to call this for both, TX and RX
#[cfg(esp32)] #[cfg(esp32)]
@ -195,12 +211,17 @@ pub mod dma {
} }
#[cfg(spi3)] #[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 where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral + Spi3Peripheral, 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 channel.tx.init_channel(); // no need to call this for both, TX and RX
#[cfg(esp32)] #[cfg(esp32)]
@ -219,20 +240,22 @@ pub mod dma {
} }
/// An in-progress DMA transfer /// An in-progress DMA transfer
#[must_use] #[must_use]
pub struct SpiDmaTransferRxTx<'t, 'd, T, C> pub struct SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> { 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
while !self.is_done() {} while !self.is_done() {}
@ -269,20 +293,22 @@ pub mod dma {
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
#[must_use] #[must_use]
pub struct SpiDmaTransferRx<'t, 'd, T, C> pub struct SpiDmaTransferRx<'t, 'd, T, C, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> { 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
while !self.is_done() {} while !self.is_done() {}
@ -318,20 +345,22 @@ pub mod dma {
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
#[must_use] #[must_use]
pub struct SpiDmaTransferTx<'t, 'd, T, C> pub struct SpiDmaTransferTx<'t, 'd, T, C, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
/// Wait for the DMA transfer to complete /// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> { 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 where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
while !self.is_done() {} while !self.is_done() {}
@ -368,30 +398,33 @@ pub mod dma {
} }
/// A DMA capable SPI instance. /// A DMA capable SPI instance.
pub struct SpiDma<'d, T, C> pub struct SpiDma<'d, T, C, DmaMode>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, 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 where
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SpiDma").finish() f.debug_struct("SpiDma").finish()
} }
} }
impl<'d, T, C> SpiDma<'d, T, C> impl<'d, T, C, DmaMode> SpiDma<'d, T, C, DmaMode>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
DmaMode: Mode,
{ {
/// Register a buffer for a DMA write. /// Register a buffer for a DMA write.
/// ///
@ -403,7 +436,7 @@ pub mod dma {
pub fn dma_write<'t, TXBUF>( pub fn dma_write<'t, TXBUF>(
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
) -> Result<SpiDmaTransferTx<'t, 'd, T, C>, Error> ) -> Result<SpiDmaTransferTx<'t, 'd, T, C, DmaMode>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -428,7 +461,7 @@ pub mod dma {
pub fn dma_read<'t, RXBUF>( pub fn dma_read<'t, RXBUF>(
&'t mut self, &'t mut self,
words: &'t mut RXBUF, words: &'t mut RXBUF,
) -> Result<SpiDmaTransferRx<'t, 'd, T, C>, Error> ) -> Result<SpiDmaTransferRx<'t, 'd, T, C, DmaMode>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -455,7 +488,7 @@ pub mod dma {
&'t mut self, &'t mut self,
words: &'t TXBUF, words: &'t TXBUF,
read_buffer: &'t mut RXBUF, read_buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C>, Error> ) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,

View File

@ -57,8 +57,8 @@ async fn main(_spawner: Spawner) {
peripherals.I2S0, peripherals.I2S0,
Standard::Philips, Standard::Philips,
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
44100.Hz(), 44100u32.Hz(),
dma_channel.configure( dma_channel.configure_for_async(
false, false,
&mut tx_descriptors, &mut tx_descriptors,
&mut rx_descriptors, &mut rx_descriptors,

View File

@ -80,8 +80,8 @@ async fn main(_spawner: Spawner) {
peripherals.I2S0, peripherals.I2S0,
Standard::Philips, Standard::Philips,
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
44100.Hz(), 44100u32.Hz(),
dma_channel.configure( dma_channel.configure_for_async(
false, false,
&mut tx_descriptors, &mut tx_descriptors,
&mut rx_descriptors, &mut rx_descriptors,

View File

@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) {
let parl_io = ParlIoRxOnly::new( let parl_io = ParlIoRxOnly::new(
peripherals.PARL_IO, peripherals.PARL_IO,
dma_channel.configure( dma_channel.configure_for_async(
false, false,
&mut tx_descriptors, &mut tx_descriptors,
&mut rx_descriptors, &mut rx_descriptors,

View File

@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) {
let parl_io = ParlIoTxOnly::new( let parl_io = ParlIoTxOnly::new(
peripherals.PARL_IO, peripherals.PARL_IO,
dma_channel.configure( dma_channel.configure_for_async(
false, false,
&mut tx_descriptors, &mut tx_descriptors,
&mut rx_descriptors, &mut rx_descriptors,

View File

@ -2,9 +2,9 @@
//! //!
//! Folowing pins are used: //! Folowing pins are used:
//! SCLK GPIO0 //! SCLK GPIO0
//! MISO GPIO1 //! MISO GPIO2
//! MOSI GPIO2 //! MOSI GPIO4
//! CS GPIO3 //! CS GPIO5
//! //!
//! Depending on your target and the board you are using you have to change the //! Depending on your target and the board you are using you have to change the
//! pins. //! pins.
@ -51,9 +51,9 @@ async fn main(_spawner: Spawner) {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio0; let sclk = io.pins.gpio0;
let miso = io.pins.gpio1; let miso = io.pins.gpio2;
let mosi = io.pins.gpio2; let mosi = io.pins.gpio4;
let cs = io.pins.gpio3; let cs = io.pins.gpio5;
let dma = Dma::new(peripherals.DMA); 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) let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0, &clocks)
.with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs)) .with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs))
.with_dma(dma_channel.configure( .with_dma(dma_channel.configure_for_async(
false, false,
&mut descriptors, &mut descriptors,
&mut rx_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) embedded_hal_async::spi::SpiBus::transfer(&mut spi, &mut buffer, &send_buffer)
.await .await
.unwrap(); .unwrap();
esp_println::println!("Bytes recieved: {:?}", buffer); esp_println::println!("Bytes received: {:?}", buffer);
Timer::after(Duration::from_millis(5_000)).await; Timer::after(Duration::from_millis(5_000)).await;
} }
} }