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_attribute]
pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
use darling::ast::NestedMeta;
use darling::{ast::NestedMeta, FromMeta};
use proc_macro::Span;
use proc_macro2::Ident;
use proc_macro_crate::{crate_name, FoundCrate};
use proc_macro_error::abort;
use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type};
use self::interrupt::{check_attr_whitelist, WhiteListCaller};
#[derive(Debug, FromMeta)]
struct MacroArgs {
priority: Option<syn::Expr>,
}
let mut f: ItemFn = syn::parse(input).expect("`#[handler]` must be applied to a function");
let original_span = f.span();
@ -388,6 +392,13 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
}
};
let args = match MacroArgs::from_list(&attr_args) {
Ok(v) => v,
Err(e) => {
return TokenStream::from(e.write_errors());
}
};
let root = Ident::new(
if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
&name
@ -397,30 +408,10 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
Span::call_site().into(),
);
let priority = if attr_args.len() > 1 {
abort!(
Span::call_site(),
"This attribute accepts one optional argument"
)
} else if attr_args.len() == 1 {
match &attr_args[0] {
NestedMeta::Lit(syn::Lit::Str(priority)) => priority.value(),
_ => abort!(
Span::call_site(),
"The priority must be provided as a string"
),
}
let priority = if let Some(priority) = args.priority {
quote::quote!( #priority )
} else {
String::from("min")
};
let priority = match priority.as_str() {
"min" => quote::quote_spanned!(original_span => #root::interrupt::Priority::min()),
"max" => quote::quote_spanned!(original_span => #root::interrupt::Priority::max()),
_ => {
let priority = Ident::new(&priority, proc_macro2::Span::call_site());
quote::quote_spanned!(original_span => #root::interrupt::Priority::#priority)
}
quote::quote! { #root::interrupt::Priority::min() }
};
// XXX should we blacklist other attributes?

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)
- `Rmt` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument. (#1341)
- All `Instance` traits are now sealed, and can no longer be implemented for arbitrary types (#1346)
- DMA channels can/have to be explicitly created for async or blocking drivers, added `set_interrupt_handler` to DMA channels, SPI, I2S, PARL_IO, don't enable interrupts on startup for DMA, I2S, PARL_IO, GPIO (#1300)
### Removed

View File

@ -52,14 +52,14 @@ xtensa-lx = { version = "0.9.0", optional = true }
# IMPORTANT:
# Each supported device MUST have its PAC included below along with a
# corresponding feature.
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
[target.'cfg(target_arch = "riscv32")'.dependencies]
esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" }

View File

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

View File

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

View File

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

View File

@ -22,6 +22,18 @@ use crate::{
macro_rules! ImplSpiChannel {
($num: literal) => {
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]
pub struct [<Spi $num DmaChannel>] {}
@ -29,6 +41,7 @@ macro_rules! ImplSpiChannel {
type P = [<Spi $num DmaSuitablePeripheral>];
type Tx<'a> = ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<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>] {
@ -301,7 +314,7 @@ macro_rules! ImplSpiChannel {
pub struct [<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
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
@ -311,7 +324,7 @@ macro_rules! ImplSpiChannel {
tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>]> {
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Blocking> {
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
@ -321,6 +334,34 @@ macro_rules! ImplSpiChannel {
Channel {
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with async APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
#[cfg(feature = "async")]
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority,
) -> Channel<'a, [<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 {
($num: literal, $peripheral: literal) => {
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>] {}
impl ChannelTypes for [<I2s $num DmaChannel>] {
type P = [<I2s $num DmaSuitablePeripheral>];
type Tx<'a> = ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<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>] {
@ -587,7 +641,7 @@ macro_rules! ImplI2sChannel {
pub struct [<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
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
@ -597,7 +651,7 @@ macro_rules! ImplI2sChannel {
tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>]> {
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Blocking> {
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
@ -607,6 +661,34 @@ macro_rules! ImplI2sChannel {
Channel {
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with async APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
#[cfg(feature = "async")]
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority,
) -> Channel<'a, [<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
#[cfg(feature = "async")]
{
#[cfg(any(esp32s3, esp32c6, esp32h2))]
crate::interrupt::enable(Interrupt::DMA_IN_CH0, Priority::max()).unwrap();
#[cfg(any(esp32s3, esp32c6, esp32h2))]
crate::interrupt::enable(Interrupt::DMA_OUT_CH0, Priority::max()).unwrap();
#[cfg(any(esp32s3, esp32c6, esp32h2))]
crate::interrupt::enable(Interrupt::DMA_IN_CH1, Priority::max()).unwrap();
#[cfg(any(esp32s3, esp32c6, esp32h2))]
crate::interrupt::enable(Interrupt::DMA_OUT_CH1, Priority::max()).unwrap();
#[cfg(any(esp32s3, esp32c6, esp32h2))]
crate::interrupt::enable(Interrupt::DMA_IN_CH2, Priority::max()).unwrap();
#[cfg(any(esp32s3, esp32c6, esp32h2))]
crate::interrupt::enable(Interrupt::DMA_OUT_CH2, Priority::max()).unwrap();
#[cfg(esp32s3)]
crate::interrupt::enable(Interrupt::DMA_IN_CH3, Priority::max()).unwrap();
#[cfg(esp32s3)]
crate::interrupt::enable(Interrupt::DMA_OUT_CH3, Priority::max()).unwrap();
#[cfg(any(esp32c3, esp32c2))]
crate::interrupt::enable(Interrupt::DMA_CH0, Priority::max()).unwrap();
#[cfg(esp32c3)]
crate::interrupt::enable(Interrupt::DMA_CH1, Priority::max()).unwrap();
#[cfg(esp32c3)]
crate::interrupt::enable(Interrupt::DMA_CH2, Priority::max()).unwrap();
#[cfg(esp32)]
crate::interrupt::enable(Interrupt::SPI1_DMA, Priority::max()).unwrap();
#[cfg(any(esp32, esp32s2))]
crate::interrupt::enable(Interrupt::SPI2_DMA, Priority::max()).unwrap();
#[cfg(any(esp32, esp32s2))]
crate::interrupt::enable(Interrupt::SPI3_DMA, Priority::max()).unwrap();
#[cfg(esp32s2)]
crate::interrupt::enable(Interrupt::SPI4_DMA, Priority::max()).unwrap();
#[cfg(i2s0)]
crate::interrupt::enable(Interrupt::I2S0, Priority::min()).unwrap();
#[cfg(i2s1)]
crate::interrupt::enable(Interrupt::I2S1, Priority::min()).unwrap();
#[cfg(rmt)]
crate::interrupt::enable(Interrupt::RMT, Priority::min()).unwrap();
#[cfg(usb_device)]
crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap();
#[cfg(all(parl_io, not(esp32h2)))]
crate::interrupt::enable(Interrupt::PARL_IO, Priority::min()).unwrap();
#[cfg(all(parl_io, esp32h2))]
crate::interrupt::enable(Interrupt::PARL_IO_RX, Priority::min()).unwrap();
#[cfg(all(parl_io, esp32h2))]
crate::interrupt::enable(Interrupt::PARL_IO_TX, Priority::min()).unwrap();
crate::interrupt::enable(Interrupt::I2C_EXT0, Priority::min()).unwrap();
crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@ crate::peripherals! {
ASSIST_DEBUG <= ASSIST_DEBUG,
ATOMIC <= ATOMIC,
BT <= virtual,
DMA <= DMA,
DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2),
DS <= DS,
ECC <= ECC,
EFUSE <= EFUSE,
@ -37,7 +37,7 @@ crate::peripherals! {
HP_APM <= HP_APM,
HP_SYS <= HP_SYS,
I2C0 <= I2C0,
I2S0 <= I2S0,
I2S0 <= I2S0 (I2S0),
IEEE802154 <= virtual,
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTPRI <= INTPRI,
@ -60,7 +60,7 @@ crate::peripherals! {
MCPWM0 <= MCPWM0,
MEM_MONITOR <= MEM_MONITOR,
OTP_DEBUG <= OTP_DEBUG,
PARL_IO <= PARL_IO,
PARL_IO <= PARL_IO (PARL_IO),
PAU <= PAU,
PCNT <= PCNT,
PMU <= PMU,
@ -72,7 +72,7 @@ crate::peripherals! {
SOC_ETM <= SOC_ETM,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2,
SPI2 <= SPI2 (SPI2),
SYSTEM <= PCR,
SYSTIMER <= SYSTIMER,
TEE <= TEE,

View File

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

View File

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

View File

@ -26,7 +26,7 @@ crate::peripherals! {
APB_CTRL <= APB_CTRL,
ASSIST_DEBUG <= ASSIST_DEBUG,
BT <= virtual,
DMA <= DMA,
DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_IN_CH3,DMA_IN_CH4,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2,DMA_OUT_CH3,DMA_OUT_CH4),
DS <= DS,
EFUSE <= EFUSE,
EXTMEM <= EXTMEM,
@ -35,8 +35,8 @@ crate::peripherals! {
HMAC <= HMAC,
I2C0 <= I2C0,
I2C1 <= I2C1,
I2S0 <= I2S0,
I2S1 <= I2S1,
I2S0 <= I2S0 (I2S0),
I2S1 <= I2S1 (I2S1),
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTERRUPT_CORE1 <= INTERRUPT_CORE1,
IO_MUX <= IO_MUX,
@ -57,8 +57,8 @@ crate::peripherals! {
SHA <= SHA,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2,
SPI3 <= SPI3,
SPI2 <= SPI2 (SPI2),
SPI3 <= SPI3 (SPI3),
SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER,
TIMG0 <= TIMG0,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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