Runtime DMA interrupt binding (#1300)
This commit is contained in:
parent
65dca0025b
commit
4077734c3c
@ -369,15 +369,19 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
#[proc_macro_error::proc_macro_error]
|
#[proc_macro_error::proc_macro_error]
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
use darling::ast::NestedMeta;
|
use darling::{ast::NestedMeta, FromMeta};
|
||||||
use proc_macro::Span;
|
use proc_macro::Span;
|
||||||
use proc_macro2::Ident;
|
use proc_macro2::Ident;
|
||||||
use proc_macro_crate::{crate_name, FoundCrate};
|
use proc_macro_crate::{crate_name, FoundCrate};
|
||||||
use proc_macro_error::abort;
|
|
||||||
use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type};
|
use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type};
|
||||||
|
|
||||||
use self::interrupt::{check_attr_whitelist, WhiteListCaller};
|
use self::interrupt::{check_attr_whitelist, WhiteListCaller};
|
||||||
|
|
||||||
|
#[derive(Debug, FromMeta)]
|
||||||
|
struct MacroArgs {
|
||||||
|
priority: Option<syn::Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
let mut f: ItemFn = syn::parse(input).expect("`#[handler]` must be applied to a function");
|
let mut f: ItemFn = syn::parse(input).expect("`#[handler]` must be applied to a function");
|
||||||
let original_span = f.span();
|
let original_span = f.span();
|
||||||
|
|
||||||
@ -388,6 +392,13 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let args = match MacroArgs::from_list(&attr_args) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
return TokenStream::from(e.write_errors());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let root = Ident::new(
|
let root = Ident::new(
|
||||||
if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
|
if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
|
||||||
&name
|
&name
|
||||||
@ -397,30 +408,10 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
Span::call_site().into(),
|
Span::call_site().into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let priority = if attr_args.len() > 1 {
|
let priority = if let Some(priority) = args.priority {
|
||||||
abort!(
|
quote::quote!( #priority )
|
||||||
Span::call_site(),
|
|
||||||
"This attribute accepts one optional argument"
|
|
||||||
)
|
|
||||||
} else if attr_args.len() == 1 {
|
|
||||||
match &attr_args[0] {
|
|
||||||
NestedMeta::Lit(syn::Lit::Str(priority)) => priority.value(),
|
|
||||||
_ => abort!(
|
|
||||||
Span::call_site(),
|
|
||||||
"The priority must be provided as a string"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
String::from("min")
|
quote::quote! { #root::interrupt::Priority::min() }
|
||||||
};
|
|
||||||
|
|
||||||
let priority = match priority.as_str() {
|
|
||||||
"min" => quote::quote_spanned!(original_span => #root::interrupt::Priority::min()),
|
|
||||||
"max" => quote::quote_spanned!(original_span => #root::interrupt::Priority::max()),
|
|
||||||
_ => {
|
|
||||||
let priority = Ident::new(&priority, proc_macro2::Span::call_site());
|
|
||||||
quote::quote_spanned!(original_span => #root::interrupt::Priority::#priority)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX should we blacklist other attributes?
|
// XXX should we blacklist other attributes?
|
||||||
|
|||||||
@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- `Uart` structs now take a `Mode` parameter which defines how the driver is initialized (#1294)
|
- `Uart` structs now take a `Mode` parameter which defines how the driver is initialized (#1294)
|
||||||
- `Rmt` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument. (#1341)
|
- `Rmt` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument. (#1341)
|
||||||
- All `Instance` traits are now sealed, and can no longer be implemented for arbitrary types (#1346)
|
- All `Instance` traits are now sealed, and can no longer be implemented for arbitrary types (#1346)
|
||||||
|
- DMA channels can/have to be explicitly created for async or blocking drivers, added `set_interrupt_handler` to DMA channels, SPI, I2S, PARL_IO, don't enable interrupts on startup for DMA, I2S, PARL_IO, GPIO (#1300)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|||||||
@ -52,14 +52,14 @@ xtensa-lx = { version = "0.9.0", optional = true }
|
|||||||
# IMPORTANT:
|
# IMPORTANT:
|
||||||
# Each supported device MUST have its PAC included below along with a
|
# Each supported device MUST have its PAC included below along with a
|
||||||
# corresponding feature.
|
# corresponding feature.
|
||||||
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
|
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "riscv32")'.dependencies]
|
[target.'cfg(target_arch = "riscv32")'.dependencies]
|
||||||
esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" }
|
esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" }
|
||||||
|
|||||||
@ -277,7 +277,7 @@ pub mod dma {
|
|||||||
{
|
{
|
||||||
pub aes: super::Aes<'d>,
|
pub aes: super::Aes<'d>,
|
||||||
|
|
||||||
pub(crate) channel: Channel<'d, C>,
|
pub(crate) channel: Channel<'d, C, crate::Blocking>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WithDmaAes<'d, C>
|
pub trait WithDmaAes<'d, C>
|
||||||
@ -285,7 +285,7 @@ pub mod dma {
|
|||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: AesPeripheral,
|
C::P: AesPeripheral,
|
||||||
{
|
{
|
||||||
fn with_dma(self, channel: Channel<'d, C>) -> AesDma<'d, C>;
|
fn with_dma(self, channel: Channel<'d, C, crate::Blocking>) -> AesDma<'d, C>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, C> WithDmaAes<'d, C> for crate::aes::Aes<'d>
|
impl<'d, C> WithDmaAes<'d, C> for crate::aes::Aes<'d>
|
||||||
@ -293,7 +293,7 @@ pub mod dma {
|
|||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: AesPeripheral,
|
C::P: AesPeripheral,
|
||||||
{
|
{
|
||||||
fn with_dma(self, mut channel: Channel<'d, C>) -> AesDma<'d, C> {
|
fn with_dma(self, mut channel: Channel<'d, C, crate::Blocking>) -> AesDma<'d, C> {
|
||||||
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
||||||
|
|
||||||
AesDma { aes: self, channel }
|
AesDma { aes: self, channel }
|
||||||
|
|||||||
@ -31,8 +31,22 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! impl_channel {
|
macro_rules! impl_channel {
|
||||||
($num: literal) => {
|
($num: literal, $async_handler: path, $($interrupt: ident),* ) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct [<Channel $num InterruptBinder>] {}
|
||||||
|
|
||||||
|
impl InterruptBinder for [<Channel $num InterruptBinder>] {
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
|
||||||
|
let mut dma = unsafe { crate::peripherals::DMA::steal() };
|
||||||
|
$(
|
||||||
|
dma.[< bind_ $interrupt:lower _interrupt >](handler.handler());
|
||||||
|
$crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, handler.priority()).unwrap();
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct [<Channel $num>] {}
|
pub struct [<Channel $num>] {}
|
||||||
|
|
||||||
@ -40,6 +54,7 @@ macro_rules! impl_channel {
|
|||||||
type P = [<SuitablePeripheral $num>];
|
type P = [<SuitablePeripheral $num>];
|
||||||
type Tx<'a> = ChannelTx<'a, [<Channel $num TxImpl>], [<Channel $num>]>;
|
type Tx<'a> = ChannelTx<'a, [<Channel $num TxImpl>], [<Channel $num>]>;
|
||||||
type Rx<'a> = ChannelRx<'a, [<Channel $num RxImpl>], [<Channel $num>]>;
|
type Rx<'a> = ChannelRx<'a, [<Channel $num RxImpl>], [<Channel $num>]>;
|
||||||
|
type Binder = [<Channel $num InterruptBinder>];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterAccess for [<Channel $num>] {
|
impl RegisterAccess for [<Channel $num>] {
|
||||||
@ -550,7 +565,7 @@ macro_rules! impl_channel {
|
|||||||
pub struct [<ChannelCreator $num>] {}
|
pub struct [<ChannelCreator $num>] {}
|
||||||
|
|
||||||
impl [<ChannelCreator $num>] {
|
impl [<ChannelCreator $num>] {
|
||||||
/// Configure the channel for use
|
/// Configure the channel for use with blocking APIs
|
||||||
///
|
///
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
||||||
@ -560,7 +575,7 @@ macro_rules! impl_channel {
|
|||||||
tx_descriptors: &'a mut [DmaDescriptor],
|
tx_descriptors: &'a mut [DmaDescriptor],
|
||||||
rx_descriptors: &'a mut [DmaDescriptor],
|
rx_descriptors: &'a mut [DmaDescriptor],
|
||||||
priority: DmaPriority,
|
priority: DmaPriority,
|
||||||
) -> Channel<'a, [<Channel $num>]> {
|
) -> Channel<'a, [<Channel $num>], $crate::Blocking> {
|
||||||
let mut tx_impl = [<Channel $num TxImpl>] {};
|
let mut tx_impl = [<Channel $num TxImpl>] {};
|
||||||
tx_impl.init(burst_mode, priority);
|
tx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
@ -570,6 +585,34 @@ macro_rules! impl_channel {
|
|||||||
Channel {
|
Channel {
|
||||||
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
||||||
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the channel for use with async APIs
|
||||||
|
///
|
||||||
|
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
||||||
|
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn configure_for_async<'a>(
|
||||||
|
self,
|
||||||
|
burst_mode: bool,
|
||||||
|
tx_descriptors: &'a mut [DmaDescriptor],
|
||||||
|
rx_descriptors: &'a mut [DmaDescriptor],
|
||||||
|
priority: DmaPriority,
|
||||||
|
) -> Channel<'a, [<Channel $num>], $crate::Async> {
|
||||||
|
let mut tx_impl = [<Channel $num TxImpl>] {};
|
||||||
|
tx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
|
let mut rx_impl = [<Channel $num RxImpl>] {};
|
||||||
|
rx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
|
<[<Channel $num>] as ChannelTypes>::Binder::set_isr($async_handler);
|
||||||
|
|
||||||
|
Channel {
|
||||||
|
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
||||||
|
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,15 +639,25 @@ macro_rules! impl_channel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_channel!(0);
|
cfg_if::cfg_if! {
|
||||||
#[cfg(not(esp32c2))]
|
if #[cfg(esp32c2)] {
|
||||||
impl_channel!(1);
|
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0);
|
||||||
#[cfg(not(esp32c2))]
|
} else if #[cfg(esp32c3)] {
|
||||||
impl_channel!(2);
|
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0);
|
||||||
#[cfg(esp32s3)]
|
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_CH1);
|
||||||
impl_channel!(3);
|
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_CH2);
|
||||||
#[cfg(esp32s3)]
|
} else if #[cfg(any(esp32c6, esp32h2))] {
|
||||||
impl_channel!(4);
|
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0);
|
||||||
|
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1);
|
||||||
|
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2);
|
||||||
|
} else if #[cfg(esp32s3)] {
|
||||||
|
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0);
|
||||||
|
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1);
|
||||||
|
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2);
|
||||||
|
impl_channel!(3, super::asynch::interrupt::interrupt_handler_ch3, DMA_IN_CH3, DMA_OUT_CH3);
|
||||||
|
impl_channel!(4, super::asynch::interrupt::interrupt_handler_ch4, DMA_IN_CH4, DMA_OUT_CH4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// GDMA Peripheral
|
/// GDMA Peripheral
|
||||||
///
|
///
|
||||||
|
|||||||
@ -131,16 +131,25 @@ impl DmaDescriptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use enumset::{EnumSet, EnumSetType};
|
||||||
|
|
||||||
#[cfg(gdma)]
|
#[cfg(gdma)]
|
||||||
pub use self::gdma::*;
|
pub use self::gdma::*;
|
||||||
#[cfg(pdma)]
|
#[cfg(pdma)]
|
||||||
pub use self::pdma::*;
|
pub use self::pdma::*;
|
||||||
|
use crate::{interrupt::InterruptHandler, Mode};
|
||||||
|
|
||||||
#[cfg(gdma)]
|
#[cfg(gdma)]
|
||||||
mod gdma;
|
mod gdma;
|
||||||
#[cfg(pdma)]
|
#[cfg(pdma)]
|
||||||
mod pdma;
|
mod pdma;
|
||||||
|
|
||||||
|
#[derive(EnumSetType)]
|
||||||
|
pub enum DmaInterrupt {
|
||||||
|
TxDone,
|
||||||
|
RxDone,
|
||||||
|
}
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 4092;
|
const CHUNK_SIZE: usize = 4092;
|
||||||
|
|
||||||
/// Convenience macro to create DMA buffers and descriptors
|
/// Convenience macro to create DMA buffers and descriptors
|
||||||
@ -1285,15 +1294,79 @@ pub trait ChannelTypes {
|
|||||||
type P: PeripheralMarker;
|
type P: PeripheralMarker;
|
||||||
type Tx<'a>: Tx;
|
type Tx<'a>: Tx;
|
||||||
type Rx<'a>: Rx;
|
type Rx<'a>: Rx;
|
||||||
|
type Binder: InterruptBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InterruptBinder {
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
fn set_isr(handler: InterruptHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DMA Channel
|
/// DMA Channel
|
||||||
pub struct Channel<'d, C>
|
pub struct Channel<'d, C, MODE>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
|
MODE: Mode,
|
||||||
{
|
{
|
||||||
pub tx: C::Tx<'d>,
|
pub tx: C::Tx<'d>,
|
||||||
pub(crate) rx: C::Rx<'d>,
|
pub(crate) rx: C::Rx<'d>,
|
||||||
|
phantom: PhantomData<MODE>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, C> Channel<'d, C, crate::Blocking>
|
||||||
|
where
|
||||||
|
C: ChannelTypes,
|
||||||
|
{
|
||||||
|
/// Sets the interrupt handler for TX and RX interrupts, enables them
|
||||||
|
/// with [crate::interrupt::Priority::max()]
|
||||||
|
///
|
||||||
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
C::Binder::set_isr(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Listen for the given interrupts
|
||||||
|
pub fn listen(&mut self, interrupts: EnumSet<DmaInterrupt>) {
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
DmaInterrupt::TxDone => self.tx.listen_ch_out_done(),
|
||||||
|
DmaInterrupt::RxDone => self.rx.listen_ch_in_done(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlisten the given interrupts
|
||||||
|
pub fn unlisten(&mut self, interrupts: EnumSet<DmaInterrupt>) {
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
DmaInterrupt::TxDone => self.tx.unlisten_ch_out_done(),
|
||||||
|
DmaInterrupt::RxDone => self.rx.unlisten_ch_in_done(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets asserted interrupts
|
||||||
|
pub fn interrupts(&mut self) -> EnumSet<DmaInterrupt> {
|
||||||
|
let mut res = EnumSet::new();
|
||||||
|
if self.tx.is_done() {
|
||||||
|
res.insert(DmaInterrupt::TxDone);
|
||||||
|
}
|
||||||
|
if self.rx.is_done() {
|
||||||
|
res.insert(DmaInterrupt::RxDone);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets asserted interrupts
|
||||||
|
pub fn clear_interrupts(&mut self, interrupts: EnumSet<DmaInterrupt>) {
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
DmaInterrupt::TxDone => self.tx.clear_ch_out_done(),
|
||||||
|
DmaInterrupt::RxDone => self.rx.clear_ch_in_done(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait to be implemented for an in progress dma transfer.
|
/// Trait to be implemented for an in progress dma transfer.
|
||||||
@ -1319,7 +1392,6 @@ pub(crate) mod asynch {
|
|||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::macros::interrupt;
|
|
||||||
|
|
||||||
pub struct DmaTxFuture<'a, TX> {
|
pub struct DmaTxFuture<'a, TX> {
|
||||||
pub(crate) tx: &'a mut TX,
|
pub(crate) tx: &'a mut TX,
|
||||||
@ -1461,12 +1533,14 @@ pub(crate) mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(esp32c2)]
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
mod interrupt {
|
pub(crate) mod interrupt {
|
||||||
|
use procmacros::handler;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[interrupt]
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
fn DMA_CH0() {
|
pub(crate) fn interrupt_handler_ch0() {
|
||||||
use crate::dma::gdma::{
|
use crate::dma::gdma::{
|
||||||
Channel0 as Channel,
|
Channel0 as Channel,
|
||||||
Channel0RxImpl as ChannelRxImpl,
|
Channel0RxImpl as ChannelRxImpl,
|
||||||
@ -1479,59 +1553,28 @@ pub(crate) mod asynch {
|
|||||||
ChannelRxImpl::waker().wake()
|
ChannelRxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
|
||||||
Channel::clear_out_interrupts();
|
|
||||||
Channel::unlisten_out_eof();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_out_done_set() {
|
|
||||||
Channel::clear_ch_out_done();
|
|
||||||
Channel::unlisten_ch_out_done();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(esp32c3)]
|
|
||||||
mod interrupt {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_CH0() {
|
|
||||||
use crate::dma::gdma::{
|
|
||||||
Channel0 as Channel,
|
|
||||||
Channel0RxImpl as ChannelRxImpl,
|
|
||||||
Channel0TxImpl as ChannelTxImpl,
|
|
||||||
};
|
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
|
||||||
Channel::clear_in_interrupts();
|
|
||||||
Channel::unlisten_in_eof();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
|
||||||
Channel::clear_out_interrupts();
|
|
||||||
Channel::unlisten_out_eof();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_out_done_set() {
|
|
||||||
Channel::clear_ch_out_done();
|
|
||||||
Channel::unlisten_ch_out_done();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
if Channel::is_ch_in_done_set() {
|
||||||
Channel::clear_ch_in_done();
|
Channel::clear_ch_in_done();
|
||||||
Channel::unlisten_ch_in_done();
|
Channel::unlisten_ch_in_done();
|
||||||
ChannelRxImpl::waker().wake()
|
ChannelRxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if Channel::is_out_done() {
|
||||||
|
Channel::clear_out_interrupts();
|
||||||
|
Channel::unlisten_out_eof();
|
||||||
|
ChannelTxImpl::waker().wake()
|
||||||
|
}
|
||||||
|
|
||||||
|
if Channel::is_ch_out_done_set() {
|
||||||
|
Channel::clear_ch_out_done();
|
||||||
|
Channel::unlisten_ch_out_done();
|
||||||
|
ChannelTxImpl::waker().wake()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[cfg(not(esp32c2))]
|
||||||
fn DMA_CH1() {
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
|
pub(crate) fn interrupt_handler_ch1() {
|
||||||
use crate::dma::gdma::{
|
use crate::dma::gdma::{
|
||||||
Channel1 as Channel,
|
Channel1 as Channel,
|
||||||
Channel1RxImpl as ChannelRxImpl,
|
Channel1RxImpl as ChannelRxImpl,
|
||||||
@ -1544,6 +1587,12 @@ pub(crate) mod asynch {
|
|||||||
ChannelRxImpl::waker().wake()
|
ChannelRxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if Channel::is_ch_in_done_set() {
|
||||||
|
Channel::clear_ch_in_done();
|
||||||
|
Channel::unlisten_ch_in_done();
|
||||||
|
ChannelRxImpl::waker().wake()
|
||||||
|
}
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
if Channel::is_out_done() {
|
||||||
Channel::clear_out_interrupts();
|
Channel::clear_out_interrupts();
|
||||||
Channel::unlisten_out_eof();
|
Channel::unlisten_out_eof();
|
||||||
@ -1555,16 +1604,11 @@ pub(crate) mod asynch {
|
|||||||
Channel::unlisten_ch_out_done();
|
Channel::unlisten_ch_out_done();
|
||||||
ChannelTxImpl::waker().wake()
|
ChannelTxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
|
||||||
Channel::clear_ch_in_done();
|
|
||||||
Channel::unlisten_ch_in_done();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[cfg(not(esp32c2))]
|
||||||
fn DMA_CH2() {
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
|
pub(crate) fn interrupt_handler_ch2() {
|
||||||
use crate::dma::gdma::{
|
use crate::dma::gdma::{
|
||||||
Channel2 as Channel,
|
Channel2 as Channel,
|
||||||
Channel2RxImpl as ChannelRxImpl,
|
Channel2RxImpl as ChannelRxImpl,
|
||||||
@ -1577,50 +1621,11 @@ pub(crate) mod asynch {
|
|||||||
ChannelRxImpl::waker().wake()
|
ChannelRxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
|
||||||
Channel::clear_out_interrupts();
|
|
||||||
Channel::unlisten_out_eof();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_out_done_set() {
|
|
||||||
Channel::clear_ch_out_done();
|
|
||||||
Channel::unlisten_ch_out_done();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
if Channel::is_ch_in_done_set() {
|
||||||
Channel::clear_ch_in_done();
|
Channel::clear_ch_in_done();
|
||||||
Channel::unlisten_ch_in_done();
|
Channel::unlisten_ch_in_done();
|
||||||
ChannelRxImpl::waker().wake()
|
ChannelRxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
|
||||||
mod interrupt {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_IN_CH0() {
|
|
||||||
use crate::dma::gdma::{Channel0 as Channel, Channel0RxImpl as ChannelRxImpl};
|
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
|
||||||
Channel::clear_in_interrupts();
|
|
||||||
Channel::unlisten_in_eof();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
|
||||||
Channel::clear_ch_in_done();
|
|
||||||
Channel::unlisten_ch_in_done();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_OUT_CH0() {
|
|
||||||
use crate::dma::gdma::{Channel0 as Channel, Channel0TxImpl as ChannelTxImpl};
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
if Channel::is_out_done() {
|
||||||
Channel::clear_out_interrupts();
|
Channel::clear_out_interrupts();
|
||||||
@ -1635,9 +1640,14 @@ pub(crate) mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[cfg(esp32s3)]
|
||||||
fn DMA_IN_CH1() {
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
use crate::dma::gdma::{Channel1 as Channel, Channel1RxImpl as ChannelRxImpl};
|
pub(crate) fn interrupt_handler_ch3() {
|
||||||
|
use crate::dma::gdma::{
|
||||||
|
Channel3 as Channel,
|
||||||
|
Channel3RxImpl as ChannelRxImpl,
|
||||||
|
Channel3TxImpl as ChannelTxImpl,
|
||||||
|
};
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
||||||
Channel::clear_in_interrupts();
|
Channel::clear_in_interrupts();
|
||||||
@ -1650,11 +1660,6 @@ pub(crate) mod asynch {
|
|||||||
Channel::unlisten_ch_in_done();
|
Channel::unlisten_ch_in_done();
|
||||||
ChannelRxImpl::waker().wake()
|
ChannelRxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_OUT_CH1() {
|
|
||||||
use crate::dma::gdma::{Channel1 as Channel, Channel1TxImpl as ChannelTxImpl};
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
if Channel::is_out_done() {
|
||||||
Channel::clear_out_interrupts();
|
Channel::clear_out_interrupts();
|
||||||
@ -1669,9 +1674,14 @@ pub(crate) mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[cfg(esp32s3)]
|
||||||
fn DMA_IN_CH2() {
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
use crate::dma::gdma::{Channel2 as Channel, Channel2RxImpl as ChannelRxImpl};
|
pub(crate) fn interrupt_handler_ch4() {
|
||||||
|
use crate::dma::gdma::{
|
||||||
|
Channel4 as Channel,
|
||||||
|
Channel4RxImpl as ChannelRxImpl,
|
||||||
|
Channel4TxImpl as ChannelTxImpl,
|
||||||
|
};
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
||||||
Channel::clear_in_interrupts();
|
Channel::clear_in_interrupts();
|
||||||
@ -1684,152 +1694,6 @@ pub(crate) mod asynch {
|
|||||||
Channel::unlisten_ch_in_done();
|
Channel::unlisten_ch_in_done();
|
||||||
ChannelRxImpl::waker().wake()
|
ChannelRxImpl::waker().wake()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_OUT_CH2() {
|
|
||||||
use crate::dma::gdma::{Channel2 as Channel, Channel2TxImpl as ChannelTxImpl};
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
|
||||||
Channel::clear_out_interrupts();
|
|
||||||
Channel::unlisten_out_eof();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_out_done_set() {
|
|
||||||
Channel::clear_ch_out_done();
|
|
||||||
Channel::unlisten_ch_out_done();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(esp32s3)]
|
|
||||||
mod interrupt {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_IN_CH0() {
|
|
||||||
use crate::dma::gdma::{Channel0 as Channel, Channel0RxImpl as ChannelRxImpl};
|
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
|
||||||
Channel::clear_in_interrupts();
|
|
||||||
Channel::unlisten_in_eof();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
|
||||||
Channel::clear_ch_in_done();
|
|
||||||
Channel::unlisten_ch_in_done();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_OUT_CH0() {
|
|
||||||
use crate::dma::gdma::{Channel0 as Channel, Channel0TxImpl as ChannelTxImpl};
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
|
||||||
Channel::clear_out_interrupts();
|
|
||||||
Channel::unlisten_out_eof();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_out_done_set() {
|
|
||||||
Channel::clear_ch_out_done();
|
|
||||||
Channel::unlisten_ch_out_done();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_IN_CH1() {
|
|
||||||
use crate::dma::gdma::{Channel1 as Channel, Channel1RxImpl as ChannelRxImpl};
|
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
|
||||||
Channel::clear_in_interrupts();
|
|
||||||
Channel::unlisten_in_eof();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
|
||||||
Channel::clear_ch_in_done();
|
|
||||||
Channel::unlisten_ch_in_done();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_OUT_CH1() {
|
|
||||||
use crate::dma::gdma::{Channel1 as Channel, Channel1TxImpl as ChannelTxImpl};
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
|
||||||
Channel::clear_out_interrupts();
|
|
||||||
Channel::unlisten_out_eof();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_out_done_set() {
|
|
||||||
Channel::clear_ch_out_done();
|
|
||||||
Channel::unlisten_ch_out_done();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_IN_CH3() {
|
|
||||||
use crate::dma::gdma::{Channel3 as Channel, Channel3RxImpl as ChannelRxImpl};
|
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
|
||||||
Channel::clear_in_interrupts();
|
|
||||||
Channel::unlisten_in_eof();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
|
||||||
Channel::clear_ch_in_done();
|
|
||||||
Channel::unlisten_ch_in_done();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_OUT_CH3() {
|
|
||||||
use crate::dma::gdma::{Channel3 as Channel, Channel3TxImpl as ChannelTxImpl};
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
|
||||||
Channel::clear_out_interrupts();
|
|
||||||
Channel::unlisten_out_eof();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_out_done_set() {
|
|
||||||
Channel::clear_ch_out_done();
|
|
||||||
Channel::unlisten_ch_out_done();
|
|
||||||
ChannelTxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_IN_CH4() {
|
|
||||||
use crate::dma::gdma::{Channel4 as Channel, Channel4RxImpl as ChannelRxImpl};
|
|
||||||
|
|
||||||
if Channel::is_in_done() && Channel::is_listening_in_eof() {
|
|
||||||
Channel::clear_in_interrupts();
|
|
||||||
Channel::unlisten_in_eof();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Channel::is_ch_in_done_set() {
|
|
||||||
Channel::clear_ch_in_done();
|
|
||||||
Channel::unlisten_ch_in_done();
|
|
||||||
ChannelRxImpl::waker().wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn DMA_OUT_CH4() {
|
|
||||||
use crate::dma::gdma::{Channel4 as Channel, Channel4TxImpl as ChannelTxImpl};
|
|
||||||
|
|
||||||
if Channel::is_out_done() {
|
if Channel::is_out_done() {
|
||||||
Channel::clear_out_interrupts();
|
Channel::clear_out_interrupts();
|
||||||
@ -1846,11 +1710,13 @@ pub(crate) mod asynch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(esp32, esp32s2))]
|
#[cfg(any(esp32, esp32s2))]
|
||||||
mod interrupt {
|
pub(crate) mod interrupt {
|
||||||
|
use procmacros::handler;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[interrupt]
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
fn SPI2_DMA() {
|
pub(crate) fn interrupt_handler_spi2_dma() {
|
||||||
use crate::dma::pdma::{
|
use crate::dma::pdma::{
|
||||||
Spi2DmaChannel as Channel,
|
Spi2DmaChannel as Channel,
|
||||||
Spi2DmaChannelRxImpl as ChannelRxImpl,
|
Spi2DmaChannelRxImpl as ChannelRxImpl,
|
||||||
@ -1882,8 +1748,8 @@ pub(crate) mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
fn SPI3_DMA() {
|
pub(crate) fn interrupt_handler_spi3_dma() {
|
||||||
use crate::dma::pdma::{
|
use crate::dma::pdma::{
|
||||||
Spi3DmaChannel as Channel,
|
Spi3DmaChannel as Channel,
|
||||||
Spi3DmaChannelRxImpl as ChannelRxImpl,
|
Spi3DmaChannelRxImpl as ChannelRxImpl,
|
||||||
@ -1915,8 +1781,8 @@ pub(crate) mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
fn I2S0() {
|
pub(crate) fn interrupt_handler_i2s0() {
|
||||||
use crate::dma::pdma::{
|
use crate::dma::pdma::{
|
||||||
I2s0DmaChannel as Channel,
|
I2s0DmaChannel as Channel,
|
||||||
I2s0DmaChannelRxImpl as ChannelRxImpl,
|
I2s0DmaChannelRxImpl as ChannelRxImpl,
|
||||||
@ -1948,9 +1814,9 @@ pub(crate) mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(esp32)]
|
#[cfg(i2s1)]
|
||||||
#[interrupt]
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
fn I2S1() {
|
pub(crate) fn interrupt_handler_i2s1() {
|
||||||
use crate::dma::pdma::{
|
use crate::dma::pdma::{
|
||||||
I2s1DmaChannel as Channel,
|
I2s1DmaChannel as Channel,
|
||||||
I2s1DmaChannelRxImpl as ChannelRxImpl,
|
I2s1DmaChannelRxImpl as ChannelRxImpl,
|
||||||
|
|||||||
@ -22,6 +22,18 @@ use crate::{
|
|||||||
macro_rules! ImplSpiChannel {
|
macro_rules! ImplSpiChannel {
|
||||||
($num: literal) => {
|
($num: literal) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct [<Channel $num InterruptBinder>] {}
|
||||||
|
|
||||||
|
impl InterruptBinder for [<Channel $num InterruptBinder>] {
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
|
||||||
|
let mut spi = unsafe { $crate::peripherals::[< SPI $num >]::steal() };
|
||||||
|
spi.[< bind_spi $num _dma_interrupt>](handler.handler());
|
||||||
|
$crate::interrupt::enable($crate::peripherals::Interrupt::[< SPI $num _DMA >], handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct [<Spi $num DmaChannel>] {}
|
pub struct [<Spi $num DmaChannel>] {}
|
||||||
|
|
||||||
@ -29,6 +41,7 @@ macro_rules! ImplSpiChannel {
|
|||||||
type P = [<Spi $num DmaSuitablePeripheral>];
|
type P = [<Spi $num DmaSuitablePeripheral>];
|
||||||
type Tx<'a> = ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>;
|
type Tx<'a> = ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>;
|
||||||
type Rx<'a> = ChannelRx<'a,[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>;
|
type Rx<'a> = ChannelRx<'a,[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>;
|
||||||
|
type Binder = [<Channel $num InterruptBinder>];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterAccess for [<Spi $num DmaChannel>] {
|
impl RegisterAccess for [<Spi $num DmaChannel>] {
|
||||||
@ -301,7 +314,7 @@ macro_rules! ImplSpiChannel {
|
|||||||
pub struct [<Spi $num DmaChannelCreator>] {}
|
pub struct [<Spi $num DmaChannelCreator>] {}
|
||||||
|
|
||||||
impl [<Spi $num DmaChannelCreator>] {
|
impl [<Spi $num DmaChannelCreator>] {
|
||||||
/// Configure the channel for use
|
/// Configure the channel for use with blocking APIs
|
||||||
///
|
///
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
||||||
@ -311,7 +324,7 @@ macro_rules! ImplSpiChannel {
|
|||||||
tx_descriptors: &'a mut [DmaDescriptor],
|
tx_descriptors: &'a mut [DmaDescriptor],
|
||||||
rx_descriptors: &'a mut [DmaDescriptor],
|
rx_descriptors: &'a mut [DmaDescriptor],
|
||||||
priority: DmaPriority,
|
priority: DmaPriority,
|
||||||
) -> Channel<'a, [<Spi $num DmaChannel>]> {
|
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Blocking> {
|
||||||
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
|
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
|
||||||
tx_impl.init(burst_mode, priority);
|
tx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
@ -321,6 +334,34 @@ macro_rules! ImplSpiChannel {
|
|||||||
Channel {
|
Channel {
|
||||||
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
||||||
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the channel for use with async APIs
|
||||||
|
///
|
||||||
|
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
||||||
|
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn configure_for_async<'a>(
|
||||||
|
self,
|
||||||
|
burst_mode: bool,
|
||||||
|
tx_descriptors: &'a mut [DmaDescriptor],
|
||||||
|
rx_descriptors: &'a mut [DmaDescriptor],
|
||||||
|
priority: DmaPriority,
|
||||||
|
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Async> {
|
||||||
|
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
|
||||||
|
tx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
|
let mut rx_impl = [<Spi $num DmaChannelRxImpl>] {};
|
||||||
|
rx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
|
<[<Spi $num DmaChannel>] as ChannelTypes>::Binder::set_isr(super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]);
|
||||||
|
|
||||||
|
Channel {
|
||||||
|
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
||||||
|
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,12 +372,25 @@ macro_rules! ImplSpiChannel {
|
|||||||
macro_rules! ImplI2sChannel {
|
macro_rules! ImplI2sChannel {
|
||||||
($num: literal, $peripheral: literal) => {
|
($num: literal, $peripheral: literal) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct [<Channel $num InterruptBinder>] {}
|
||||||
|
|
||||||
|
impl InterruptBinder for [<Channel $num InterruptBinder>] {
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
|
||||||
|
let mut i2s = unsafe { $crate::peripherals::[< I2S $num >]::steal() };
|
||||||
|
i2s.[< bind_i2s $num _interrupt>](handler.handler());
|
||||||
|
$crate::interrupt::enable($crate::peripherals::Interrupt::[< I2S $num >], handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct [<I2s $num DmaChannel>] {}
|
pub struct [<I2s $num DmaChannel>] {}
|
||||||
|
|
||||||
impl ChannelTypes for [<I2s $num DmaChannel>] {
|
impl ChannelTypes for [<I2s $num DmaChannel>] {
|
||||||
type P = [<I2s $num DmaSuitablePeripheral>];
|
type P = [<I2s $num DmaSuitablePeripheral>];
|
||||||
type Tx<'a> = ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>;
|
type Tx<'a> = ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>;
|
||||||
type Rx<'a> = ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>;
|
type Rx<'a> = ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>;
|
||||||
|
type Binder = [<Channel $num InterruptBinder>];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterAccess for [<I2s $num DmaChannel>] {
|
impl RegisterAccess for [<I2s $num DmaChannel>] {
|
||||||
@ -587,7 +641,7 @@ macro_rules! ImplI2sChannel {
|
|||||||
pub struct [<I2s $num DmaChannelCreator>] {}
|
pub struct [<I2s $num DmaChannelCreator>] {}
|
||||||
|
|
||||||
impl [<I2s $num DmaChannelCreator>] {
|
impl [<I2s $num DmaChannelCreator>] {
|
||||||
/// Configure the channel for use
|
/// Configure the channel for use with blocking APIs
|
||||||
///
|
///
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
||||||
@ -597,7 +651,7 @@ macro_rules! ImplI2sChannel {
|
|||||||
tx_descriptors: &'a mut [DmaDescriptor],
|
tx_descriptors: &'a mut [DmaDescriptor],
|
||||||
rx_descriptors: &'a mut [DmaDescriptor],
|
rx_descriptors: &'a mut [DmaDescriptor],
|
||||||
priority: DmaPriority,
|
priority: DmaPriority,
|
||||||
) -> Channel<'a, [<I2s $num DmaChannel>]> {
|
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Blocking> {
|
||||||
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
|
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
|
||||||
tx_impl.init(burst_mode, priority);
|
tx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
@ -607,6 +661,34 @@ macro_rules! ImplI2sChannel {
|
|||||||
Channel {
|
Channel {
|
||||||
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
||||||
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure the channel for use with async APIs
|
||||||
|
///
|
||||||
|
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
||||||
|
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn configure_for_async<'a>(
|
||||||
|
self,
|
||||||
|
burst_mode: bool,
|
||||||
|
tx_descriptors: &'a mut [DmaDescriptor],
|
||||||
|
rx_descriptors: &'a mut [DmaDescriptor],
|
||||||
|
priority: DmaPriority,
|
||||||
|
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Async> {
|
||||||
|
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
|
||||||
|
tx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
|
let mut rx_impl = [<I2s $num DmaChannelRxImpl>] {};
|
||||||
|
rx_impl.init(burst_mode, priority);
|
||||||
|
|
||||||
|
<[<I2s $num DmaChannel>] as ChannelTypes>::Binder::set_isr(super::asynch::interrupt::[< interrupt_handler_i2s $num >]);
|
||||||
|
|
||||||
|
Channel {
|
||||||
|
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
|
||||||
|
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,55 +111,12 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) {
|
|||||||
// only enable interrupts if the async feature is present
|
// only enable interrupts if the async feature is present
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
{
|
{
|
||||||
#[cfg(any(esp32s3, esp32c6, esp32h2))]
|
#[cfg(rmt)]
|
||||||
crate::interrupt::enable(Interrupt::DMA_IN_CH0, Priority::max()).unwrap();
|
crate::interrupt::enable(Interrupt::RMT, Priority::min()).unwrap();
|
||||||
#[cfg(any(esp32s3, esp32c6, esp32h2))]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_OUT_CH0, Priority::max()).unwrap();
|
|
||||||
#[cfg(any(esp32s3, esp32c6, esp32h2))]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_IN_CH1, Priority::max()).unwrap();
|
|
||||||
#[cfg(any(esp32s3, esp32c6, esp32h2))]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_OUT_CH1, Priority::max()).unwrap();
|
|
||||||
#[cfg(any(esp32s3, esp32c6, esp32h2))]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_IN_CH2, Priority::max()).unwrap();
|
|
||||||
#[cfg(any(esp32s3, esp32c6, esp32h2))]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_OUT_CH2, Priority::max()).unwrap();
|
|
||||||
|
|
||||||
#[cfg(esp32s3)]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_IN_CH3, Priority::max()).unwrap();
|
|
||||||
#[cfg(esp32s3)]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_OUT_CH3, Priority::max()).unwrap();
|
|
||||||
|
|
||||||
#[cfg(any(esp32c3, esp32c2))]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_CH0, Priority::max()).unwrap();
|
|
||||||
#[cfg(esp32c3)]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_CH1, Priority::max()).unwrap();
|
|
||||||
#[cfg(esp32c3)]
|
|
||||||
crate::interrupt::enable(Interrupt::DMA_CH2, Priority::max()).unwrap();
|
|
||||||
|
|
||||||
#[cfg(esp32)]
|
|
||||||
crate::interrupt::enable(Interrupt::SPI1_DMA, Priority::max()).unwrap();
|
|
||||||
#[cfg(any(esp32, esp32s2))]
|
|
||||||
crate::interrupt::enable(Interrupt::SPI2_DMA, Priority::max()).unwrap();
|
|
||||||
#[cfg(any(esp32, esp32s2))]
|
|
||||||
crate::interrupt::enable(Interrupt::SPI3_DMA, Priority::max()).unwrap();
|
|
||||||
#[cfg(esp32s2)]
|
|
||||||
crate::interrupt::enable(Interrupt::SPI4_DMA, Priority::max()).unwrap();
|
|
||||||
|
|
||||||
#[cfg(i2s0)]
|
|
||||||
crate::interrupt::enable(Interrupt::I2S0, Priority::min()).unwrap();
|
|
||||||
#[cfg(i2s1)]
|
|
||||||
crate::interrupt::enable(Interrupt::I2S1, Priority::min()).unwrap();
|
|
||||||
|
|
||||||
#[cfg(usb_device)]
|
#[cfg(usb_device)]
|
||||||
crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap();
|
crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap();
|
||||||
|
|
||||||
#[cfg(all(parl_io, not(esp32h2)))]
|
|
||||||
crate::interrupt::enable(Interrupt::PARL_IO, Priority::min()).unwrap();
|
|
||||||
#[cfg(all(parl_io, esp32h2))]
|
|
||||||
crate::interrupt::enable(Interrupt::PARL_IO_RX, Priority::min()).unwrap();
|
|
||||||
#[cfg(all(parl_io, esp32h2))]
|
|
||||||
crate::interrupt::enable(Interrupt::PARL_IO_TX, Priority::min()).unwrap();
|
|
||||||
|
|
||||||
crate::interrupt::enable(Interrupt::I2C_EXT0, Priority::min()).unwrap();
|
crate::interrupt::enable(Interrupt::I2C_EXT0, Priority::min()).unwrap();
|
||||||
crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap();
|
crate::interrupt::enable(Interrupt::GPIO, Priority::min()).unwrap();
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
use core::{cell::Cell, convert::Infallible, marker::PhantomData};
|
use core::{cell::Cell, convert::Infallible, marker::PhantomData};
|
||||||
|
|
||||||
use critical_section::Mutex;
|
use critical_section::Mutex;
|
||||||
use procmacros::handler;
|
|
||||||
|
|
||||||
#[cfg(any(adc, dac))]
|
#[cfg(any(adc, dac))]
|
||||||
pub(crate) use crate::analog;
|
pub(crate) use crate::analog;
|
||||||
@ -1876,7 +1875,8 @@ pub struct IO {
|
|||||||
impl IO {
|
impl IO {
|
||||||
/// Initialize the I/O driver.
|
/// Initialize the I/O driver.
|
||||||
pub fn new(mut gpio: GPIO, io_mux: IO_MUX) -> Self {
|
pub fn new(mut gpio: GPIO, io_mux: IO_MUX) -> Self {
|
||||||
gpio.bind_gpio_interrupt(gpio_interrupt_handler.handler());
|
gpio.bind_gpio_interrupt(gpio_interrupt_handler);
|
||||||
|
|
||||||
let pins = gpio.split();
|
let pins = gpio.split();
|
||||||
|
|
||||||
IO {
|
IO {
|
||||||
@ -1910,8 +1910,7 @@ impl IO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[handler]
|
extern "C" fn gpio_interrupt_handler() {
|
||||||
fn gpio_interrupt_handler() {
|
|
||||||
if let Some(user_handler) = critical_section::with(|cs| USER_INTERRUPT_HANDLER.borrow(cs).get())
|
if let Some(user_handler) = critical_section::with(|cs| USER_INTERRUPT_HANDLER.borrow(cs).get())
|
||||||
{
|
{
|
||||||
user_handler.call();
|
user_handler.call();
|
||||||
|
|||||||
@ -68,6 +68,7 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use embedded_dma::{ReadBuffer, WriteBuffer};
|
use embedded_dma::{ReadBuffer, WriteBuffer};
|
||||||
|
use enumset::{EnumSet, EnumSetType};
|
||||||
use private::*;
|
use private::*;
|
||||||
|
|
||||||
#[cfg(any(esp32, esp32s3))]
|
#[cfg(any(esp32, esp32s3))]
|
||||||
@ -85,11 +86,23 @@ use crate::{
|
|||||||
TxPrivate,
|
TxPrivate,
|
||||||
},
|
},
|
||||||
gpio::OutputPin,
|
gpio::OutputPin,
|
||||||
|
interrupt::InterruptHandler,
|
||||||
into_ref,
|
into_ref,
|
||||||
peripheral::Peripheral,
|
peripheral::Peripheral,
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(EnumSetType)]
|
||||||
|
pub enum I2sInterrupt {
|
||||||
|
TxHung,
|
||||||
|
RxHung,
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
TxDone,
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
RxDone,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||||
const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6;
|
const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6;
|
||||||
|
|
||||||
@ -199,18 +212,20 @@ impl DataFormat {
|
|||||||
|
|
||||||
/// An in-progress DMA write transfer.
|
/// An in-progress DMA write transfer.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct I2sWriteDmaTransfer<'t, 'd, T, CH>
|
pub struct I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
i2s_tx: &'t mut I2sTx<'d, T, CH>,
|
i2s_tx: &'t mut I2sTx<'d, T, CH, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, CH> I2sWriteDmaTransfer<'t, 'd, T, CH>
|
impl<'t, 'd, T, CH, DmaMode> I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Amount of bytes which can be pushed.
|
/// Amount of bytes which can be pushed.
|
||||||
/// Only useful for circular DMA transfers
|
/// Only useful for circular DMA transfers
|
||||||
@ -246,10 +261,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, CH> DmaTransfer for I2sWriteDmaTransfer<'t, 'd, T, CH>
|
impl<'t, 'd, T, CH, DmaMode> DmaTransfer for I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
fn wait(self) -> Result<(), DmaError> {
|
fn wait(self) -> Result<(), DmaError> {
|
||||||
@ -270,10 +286,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, CH> Drop for I2sWriteDmaTransfer<'t, 'd, T, CH>
|
impl<'t, 'd, T, CH, DmaMode> Drop for I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.i2s_tx.wait_tx_dma_done().ok();
|
self.i2s_tx.wait_tx_dma_done().ok();
|
||||||
@ -286,10 +303,11 @@ pub trait I2sWrite<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Initiate a DMA tx transfer
|
/// Initiate a DMA tx transfer
|
||||||
pub trait I2sWriteDma<'d, T, CH, TXBUF>
|
pub trait I2sWriteDma<'d, T, CH, TXBUF, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Write I2S.
|
/// Write I2S.
|
||||||
/// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA
|
/// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA
|
||||||
@ -297,7 +315,7 @@ where
|
|||||||
fn write_dma<'t>(
|
fn write_dma<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>;
|
TXBUF: ReadBuffer<Word = u8>;
|
||||||
|
|
||||||
@ -306,25 +324,27 @@ where
|
|||||||
fn write_dma_circular<'t>(
|
fn write_dma_circular<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>;
|
TXBUF: ReadBuffer<Word = u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An in-progress DMA read transfer.
|
/// An in-progress DMA read transfer.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct I2sReadDmaTransfer<'t, 'd, T, CH>
|
pub struct I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
i2s_rx: &'t mut I2sRx<'d, T, CH>,
|
i2s_rx: &'t mut I2sRx<'d, T, CH, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, CH> I2sReadDmaTransfer<'t, 'd, T, CH>
|
impl<'t, 'd, T, CH, DmaMode> I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Amount of bytes which can be popped
|
/// Amount of bytes which can be popped
|
||||||
pub fn available(&mut self) -> usize {
|
pub fn available(&mut self) -> usize {
|
||||||
@ -352,10 +372,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, CH> DmaTransfer for I2sReadDmaTransfer<'t, 'd, T, CH>
|
impl<'t, 'd, T, CH, DmaMode> DmaTransfer for I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
fn wait(self) -> Result<(), DmaError> {
|
fn wait(self) -> Result<(), DmaError> {
|
||||||
@ -376,10 +397,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, T, CH> Drop for I2sReadDmaTransfer<'t, '_, T, CH>
|
impl<'t, T, CH, DmaMode> Drop for I2sReadDmaTransfer<'t, '_, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.i2s_rx.wait_rx_dma_done().ok();
|
self.i2s_rx.wait_rx_dma_done().ok();
|
||||||
@ -392,10 +414,11 @@ pub trait I2sRead<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Initiate a DMA rx transfer
|
/// Initiate a DMA rx transfer
|
||||||
pub trait I2sReadDma<'d, T, CH, RXBUF>
|
pub trait I2sReadDma<'d, T, CH, RXBUF, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Read I2S.
|
/// Read I2S.
|
||||||
/// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
|
/// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
|
||||||
@ -403,7 +426,7 @@ where
|
|||||||
fn read_dma<'t>(
|
fn read_dma<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>;
|
RXBUF: WriteBuffer<Word = u8>;
|
||||||
|
|
||||||
@ -413,32 +436,35 @@ where
|
|||||||
fn read_dma_circular<'t>(
|
fn read_dma_circular<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>;
|
RXBUF: WriteBuffer<Word = u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instance of the I2S peripheral driver
|
/// Instance of the I2S peripheral driver
|
||||||
pub struct I2s<'d, I, CH>
|
pub struct I2s<'d, I, CH, DmaMode>
|
||||||
where
|
where
|
||||||
I: RegisterAccess,
|
I: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub i2s_tx: TxCreator<'d, I, CH>,
|
pub i2s_tx: TxCreator<'d, I, CH, DmaMode>,
|
||||||
pub i2s_rx: RxCreator<'d, I, CH>,
|
pub i2s_rx: RxCreator<'d, I, CH, DmaMode>,
|
||||||
|
phantom: PhantomData<DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, I, CH> I2s<'d, I, CH>
|
impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode>
|
||||||
where
|
where
|
||||||
I: RegisterAccess,
|
I: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn new_internal(
|
fn new_internal(
|
||||||
_i2s: impl Peripheral<P = I> + 'd,
|
_i2s: impl Peripheral<P = I> + 'd,
|
||||||
standard: Standard,
|
standard: Standard,
|
||||||
data_format: DataFormat,
|
data_format: DataFormat,
|
||||||
sample_rate: impl Into<fugit::HertzU32>,
|
sample_rate: impl Into<fugit::HertzU32>,
|
||||||
mut channel: Channel<'d, CH>,
|
mut channel: Channel<'d, CH, DmaMode>,
|
||||||
clocks: &Clocks,
|
clocks: &Clocks,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// on ESP32-C3 / ESP32-S3 and later RX and TX are independent and
|
// on ESP32-C3 / ESP32-S3 and later RX and TX are independent and
|
||||||
@ -461,19 +487,58 @@ where
|
|||||||
i2s_tx: TxCreator {
|
i2s_tx: TxCreator {
|
||||||
register_access: PhantomData,
|
register_access: PhantomData,
|
||||||
tx_channel: channel.tx,
|
tx_channel: channel.tx,
|
||||||
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
i2s_rx: RxCreator {
|
i2s_rx: RxCreator {
|
||||||
register_access: PhantomData,
|
register_access: PhantomData,
|
||||||
rx_channel: channel.rx,
|
rx_channel: channel.rx,
|
||||||
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, I, CH> I2s<'d, I, CH>
|
impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode>
|
||||||
where
|
where
|
||||||
I: RegisterAccess,
|
I: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
|
{
|
||||||
|
/// Sets the interrupt handler, enables it with
|
||||||
|
/// [crate::interrupt::Priority::min()]
|
||||||
|
///
|
||||||
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
|
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
I::set_interrupt_handler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Listen for the given interrupts
|
||||||
|
pub fn listen(&mut self, interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
I::listen(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlisten the given interrupts
|
||||||
|
pub fn unlisten(&mut self, interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
I::unlisten(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets asserted interrupts
|
||||||
|
pub fn interrupts(&mut self) -> EnumSet<I2sInterrupt> {
|
||||||
|
I::interrupts()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets asserted interrupts
|
||||||
|
pub fn clear_interrupts(&mut self, interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
I::clear_interrupts(interrupts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, I, CH, DmaMode> I2s<'d, I, CH, DmaMode>
|
||||||
|
where
|
||||||
|
I: RegisterAccess,
|
||||||
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Construct a new I2S peripheral driver instance for the first I2S
|
/// Construct a new I2S peripheral driver instance for the first I2S
|
||||||
/// peripheral
|
/// peripheral
|
||||||
@ -482,12 +547,13 @@ where
|
|||||||
standard: Standard,
|
standard: Standard,
|
||||||
data_format: DataFormat,
|
data_format: DataFormat,
|
||||||
sample_rate: impl Into<fugit::HertzU32>,
|
sample_rate: impl Into<fugit::HertzU32>,
|
||||||
channel: Channel<'d, CH>,
|
channel: Channel<'d, CH, DmaMode>,
|
||||||
clocks: &Clocks,
|
clocks: &Clocks,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
I: I2s0Instance,
|
I: I2s0Instance,
|
||||||
CH::P: I2sPeripheral + I2s0Peripheral,
|
CH::P: I2sPeripheral + I2s0Peripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
Self::new_internal(i2s, standard, data_format, sample_rate, channel, clocks)
|
Self::new_internal(i2s, standard, data_format, sample_rate, channel, clocks)
|
||||||
}
|
}
|
||||||
@ -500,7 +566,7 @@ where
|
|||||||
standard: Standard,
|
standard: Standard,
|
||||||
data_format: DataFormat,
|
data_format: DataFormat,
|
||||||
sample_rate: impl Into<fugit::HertzU32>,
|
sample_rate: impl Into<fugit::HertzU32>,
|
||||||
channel: Channel<'d, CH>,
|
channel: Channel<'d, CH, DmaMode>,
|
||||||
clocks: &Clocks,
|
clocks: &Clocks,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
@ -519,34 +585,38 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// I2S TX channel
|
/// I2S TX channel
|
||||||
pub struct I2sTx<'d, T, CH>
|
pub struct I2sTx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
{
|
{
|
||||||
register_access: PhantomData<T>,
|
register_access: PhantomData<T>,
|
||||||
tx_channel: CH::Tx<'d>,
|
tx_channel: CH::Tx<'d>,
|
||||||
|
phantom: PhantomData<DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> core::fmt::Debug for I2sTx<'d, T, CH>
|
impl<'d, T, CH, DmaMode> core::fmt::Debug for I2sTx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("I2sTx").finish()
|
f.debug_struct("I2sTx").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> I2sTx<'d, T, CH>
|
impl<'d, T, CH, DmaMode> I2sTx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn new(tx_channel: CH::Tx<'d>) -> Self {
|
fn new(tx_channel: CH::Tx<'d>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
register_access: PhantomData,
|
register_access: PhantomData,
|
||||||
tx_channel,
|
tx_channel,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,9 +648,10 @@ where
|
|||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
circular: bool,
|
circular: bool,
|
||||||
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
let (ptr, len) = unsafe { words.read_buffer() };
|
let (ptr, len) = unsafe { words.read_buffer() };
|
||||||
|
|
||||||
@ -635,11 +706,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, W, CH> I2sWrite<W> for I2sTx<'d, T, CH>
|
impl<'d, T, W, CH, DmaMode> I2sWrite<W> for I2sTx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
W: AcceptedWord,
|
W: AcceptedWord,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn write(&mut self, words: &[W]) -> Result<(), Error> {
|
fn write(&mut self, words: &[W]) -> Result<(), Error> {
|
||||||
self.write_bytes(unsafe {
|
self.write_bytes(unsafe {
|
||||||
@ -651,15 +723,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH, TXBUF> I2sWriteDma<'d, T, CH, TXBUF> for I2sTx<'d, T, CH>
|
impl<'d, T, CH, TXBUF, DmaMode> I2sWriteDma<'d, T, CH, TXBUF, DmaMode> for I2sTx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn write_dma<'t>(
|
fn write_dma<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -669,7 +742,7 @@ where
|
|||||||
fn write_dma_circular<'t>(
|
fn write_dma_circular<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -678,34 +751,39 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// I2S RX channel
|
/// I2S RX channel
|
||||||
pub struct I2sRx<'d, T, CH>
|
pub struct I2sRx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
register_access: PhantomData<T>,
|
register_access: PhantomData<T>,
|
||||||
rx_channel: CH::Rx<'d>,
|
rx_channel: CH::Rx<'d>,
|
||||||
|
phantom: PhantomData<DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> core::fmt::Debug for I2sRx<'d, T, CH>
|
impl<'d, T, CH, DmaMode> core::fmt::Debug for I2sRx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("I2sRx").finish()
|
f.debug_struct("I2sRx").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> I2sRx<'d, T, CH>
|
impl<'d, T, CH, DmaMode> I2sRx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn new(rx_channel: CH::Rx<'d>) -> Self {
|
fn new(rx_channel: CH::Rx<'d>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
register_access: PhantomData,
|
register_access: PhantomData,
|
||||||
rx_channel,
|
rx_channel,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,7 +815,7 @@ where
|
|||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
circular: bool,
|
circular: bool,
|
||||||
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -809,11 +887,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, W, T, CH> I2sRead<W> for I2sRx<'d, T, CH>
|
impl<'d, W, T, CH, DmaMode> I2sRead<W> for I2sRx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
W: AcceptedWord,
|
W: AcceptedWord,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
|
fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
|
||||||
if core::mem::size_of_val(words) > 4096 || words.is_empty() {
|
if core::mem::size_of_val(words) > 4096 || words.is_empty() {
|
||||||
@ -829,15 +908,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH, RXBUF> I2sReadDma<'d, T, CH, RXBUF> for I2sRx<'d, T, CH>
|
impl<'d, T, CH, RXBUF, DmaMode> I2sReadDma<'d, T, CH, RXBUF, DmaMode> for I2sRx<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn read_dma<'t>(
|
fn read_dma<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -847,7 +927,7 @@ where
|
|||||||
fn read_dma_circular<'t>(
|
fn read_dma_circular<'t>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
|
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -860,9 +940,18 @@ pub trait RegisterAccess: RegisterAccessPrivate {}
|
|||||||
mod private {
|
mod private {
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use enumset::EnumSet;
|
||||||
use fugit::HertzU32;
|
use fugit::HertzU32;
|
||||||
|
|
||||||
use super::{DataFormat, I2sRx, I2sTx, RegisterAccess, Standard, I2S_LL_MCLK_DIVIDER_MAX};
|
use super::{
|
||||||
|
DataFormat,
|
||||||
|
I2sInterrupt,
|
||||||
|
I2sRx,
|
||||||
|
I2sTx,
|
||||||
|
RegisterAccess,
|
||||||
|
Standard,
|
||||||
|
I2S_LL_MCLK_DIVIDER_MAX,
|
||||||
|
};
|
||||||
#[cfg(not(any(esp32, esp32s3)))]
|
#[cfg(not(any(esp32, esp32s3)))]
|
||||||
use crate::peripherals::i2s0::RegisterBlock;
|
use crate::peripherals::i2s0::RegisterBlock;
|
||||||
// on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features
|
// on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features
|
||||||
@ -873,26 +962,31 @@ mod private {
|
|||||||
clock::Clocks,
|
clock::Clocks,
|
||||||
dma::{ChannelTypes, DmaPeripheral},
|
dma::{ChannelTypes, DmaPeripheral},
|
||||||
gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
|
gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
|
||||||
|
interrupt::InterruptHandler,
|
||||||
into_ref,
|
into_ref,
|
||||||
peripherals::I2S0,
|
peripherals::I2S0,
|
||||||
system::Peripheral,
|
system::Peripheral,
|
||||||
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TxCreator<'d, T, CH>
|
pub struct TxCreator<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub register_access: PhantomData<T>,
|
pub register_access: PhantomData<T>,
|
||||||
pub tx_channel: CH::Tx<'d>,
|
pub tx_channel: CH::Tx<'d>,
|
||||||
|
pub(crate) phantom: PhantomData<DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> TxCreator<'d, T, CH>
|
impl<'d, T, CH, DmaMode> TxCreator<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub fn build(self) -> I2sTx<'d, T, CH> {
|
pub fn build(self) -> I2sTx<'d, T, CH, DmaMode> {
|
||||||
I2sTx::new(self.tx_channel)
|
I2sTx::new(self.tx_channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -927,21 +1021,24 @@ mod private {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RxCreator<'d, T, CH>
|
pub struct RxCreator<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub register_access: PhantomData<T>,
|
pub register_access: PhantomData<T>,
|
||||||
pub rx_channel: CH::Rx<'d>,
|
pub rx_channel: CH::Rx<'d>,
|
||||||
|
pub(crate) phantom: PhantomData<DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> RxCreator<'d, T, CH>
|
impl<'d, T, CH, DmaMode> RxCreator<'d, T, CH, DmaMode>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub fn build(self) -> I2sRx<'d, T, CH> {
|
pub fn build(self) -> I2sRx<'d, T, CH, DmaMode> {
|
||||||
I2sRx::new(self.rx_channel)
|
I2sRx::new(self.rx_channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,6 +1099,68 @@ mod private {
|
|||||||
|
|
||||||
#[cfg(any(esp32, esp32s2))]
|
#[cfg(any(esp32, esp32s2))]
|
||||||
pub trait RegisterAccessPrivate: Signals + RegBlock {
|
pub trait RegisterAccessPrivate: Signals + RegBlock {
|
||||||
|
fn set_interrupt_handler(handler: InterruptHandler);
|
||||||
|
|
||||||
|
fn listen(interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
I2sInterrupt::TxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_hung_int_ena().set_bit()),
|
||||||
|
I2sInterrupt::RxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_hung_int_ena().set_bit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlisten(interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
I2sInterrupt::TxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_hung_int_ena().clear_bit()),
|
||||||
|
I2sInterrupt::RxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_hung_int_ena().clear_bit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts() -> EnumSet<I2sInterrupt> {
|
||||||
|
let mut res = EnumSet::new();
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
let ints = reg_block.int_st().read();
|
||||||
|
|
||||||
|
if ints.tx_hung_int_st().bit() {
|
||||||
|
res.insert(I2sInterrupt::TxHung);
|
||||||
|
}
|
||||||
|
if ints.rx_hung_int_st().bit() {
|
||||||
|
res.insert(I2sInterrupt::RxHung);
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_interrupts(interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
I2sInterrupt::TxHung => {
|
||||||
|
reg_block.int_clr().write(|w| w.tx_hung_int_clr().set_bit())
|
||||||
|
}
|
||||||
|
I2sInterrupt::RxHung => {
|
||||||
|
reg_block.int_clr().write(|w| w.rx_hung_int_clr().set_bit())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_clock(clock_settings: I2sClockDividers) {
|
fn set_clock(clock_settings: I2sClockDividers) {
|
||||||
let i2s = Self::register_block();
|
let i2s = Self::register_block();
|
||||||
|
|
||||||
@ -1193,6 +1352,92 @@ mod private {
|
|||||||
|
|
||||||
#[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))]
|
#[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))]
|
||||||
pub trait RegisterAccessPrivate: Signals + RegBlock {
|
pub trait RegisterAccessPrivate: Signals + RegBlock {
|
||||||
|
fn set_interrupt_handler(handler: InterruptHandler);
|
||||||
|
|
||||||
|
fn listen(interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
I2sInterrupt::TxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_hung_int_ena().set_bit()),
|
||||||
|
I2sInterrupt::RxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_hung_int_ena().set_bit()),
|
||||||
|
I2sInterrupt::TxDone => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_done_int_ena().set_bit()),
|
||||||
|
I2sInterrupt::RxDone => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_done_int_ena().set_bit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlisten(interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
I2sInterrupt::TxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_hung_int_ena().clear_bit()),
|
||||||
|
I2sInterrupt::RxHung => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_hung_int_ena().clear_bit()),
|
||||||
|
I2sInterrupt::TxDone => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_done_int_ena().clear_bit()),
|
||||||
|
I2sInterrupt::RxDone => reg_block
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_done_int_ena().clear_bit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts() -> EnumSet<I2sInterrupt> {
|
||||||
|
let mut res = EnumSet::new();
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
let ints = reg_block.int_st().read();
|
||||||
|
|
||||||
|
if ints.tx_hung_int_st().bit() {
|
||||||
|
res.insert(I2sInterrupt::TxHung);
|
||||||
|
}
|
||||||
|
if ints.rx_hung_int_st().bit() {
|
||||||
|
res.insert(I2sInterrupt::RxHung);
|
||||||
|
}
|
||||||
|
if ints.tx_done_int_st().bit() {
|
||||||
|
res.insert(I2sInterrupt::TxDone);
|
||||||
|
}
|
||||||
|
if ints.rx_done_int_st().bit() {
|
||||||
|
res.insert(I2sInterrupt::RxDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_interrupts(interrupts: EnumSet<I2sInterrupt>) {
|
||||||
|
let reg_block = Self::register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
I2sInterrupt::TxHung => {
|
||||||
|
reg_block.int_clr().write(|w| w.tx_hung_int_clr().set_bit())
|
||||||
|
}
|
||||||
|
I2sInterrupt::RxHung => {
|
||||||
|
reg_block.int_clr().write(|w| w.rx_hung_int_clr().set_bit())
|
||||||
|
}
|
||||||
|
I2sInterrupt::TxDone => {
|
||||||
|
reg_block.int_clr().write(|w| w.tx_done_int_clr().set_bit())
|
||||||
|
}
|
||||||
|
I2sInterrupt::RxDone => {
|
||||||
|
reg_block.int_clr().write(|w| w.rx_done_int_clr().set_bit())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(esp32c3, esp32s3))]
|
#[cfg(any(esp32c3, esp32s3))]
|
||||||
fn set_clock(clock_settings: I2sClockDividers) {
|
fn set_clock(clock_settings: I2sClockDividers) {
|
||||||
let i2s = Self::register_block();
|
let i2s = Self::register_block();
|
||||||
@ -1870,11 +2115,23 @@ mod private {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterAccessPrivate for I2S0 {}
|
impl RegisterAccessPrivate for I2S0 {
|
||||||
|
fn set_interrupt_handler(handler: InterruptHandler) {
|
||||||
|
unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler());
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::I2S0, handler.priority())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
impl super::RegisterAccess for I2S0 {}
|
impl super::RegisterAccess for I2S0 {}
|
||||||
|
|
||||||
#[cfg(any(esp32s3, esp32))]
|
#[cfg(any(esp32s3, esp32))]
|
||||||
impl RegisterAccessPrivate for I2S1 {}
|
impl RegisterAccessPrivate for I2S1 {
|
||||||
|
fn set_interrupt_handler(handler: InterruptHandler) {
|
||||||
|
unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler());
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::I2S1, handler.priority())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
#[cfg(any(esp32s3, esp32))]
|
#[cfg(any(esp32s3, esp32))]
|
||||||
impl super::RegisterAccess for I2S1 {}
|
impl super::RegisterAccess for I2S1 {}
|
||||||
|
|
||||||
@ -1970,11 +2227,14 @@ pub mod asynch {
|
|||||||
use embedded_dma::{ReadBuffer, WriteBuffer};
|
use embedded_dma::{ReadBuffer, WriteBuffer};
|
||||||
|
|
||||||
use super::{Error, I2sRx, I2sTx, RegisterAccess};
|
use super::{Error, I2sRx, I2sTx, RegisterAccess};
|
||||||
use crate::dma::{
|
use crate::{
|
||||||
asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture},
|
dma::{
|
||||||
ChannelTypes,
|
asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture},
|
||||||
RxPrivate,
|
ChannelTypes,
|
||||||
TxPrivate,
|
RxPrivate,
|
||||||
|
TxPrivate,
|
||||||
|
},
|
||||||
|
Async,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initiate an async DMA tx transfer
|
/// Initiate an async DMA tx transfer
|
||||||
@ -1995,7 +2255,7 @@ pub mod asynch {
|
|||||||
TXBUF: ReadBuffer<Word = u8>;
|
TXBUF: ReadBuffer<Word = u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> I2sWriteDmaAsync<'d, T, CH> for super::I2sTx<'d, T, CH>
|
impl<'d, T, CH> I2sWriteDmaAsync<'d, T, CH> for super::I2sTx<'d, T, CH, Async>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
@ -2039,7 +2299,7 @@ pub mod asynch {
|
|||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
{
|
{
|
||||||
i2s_tx: I2sTx<'d, T, CH>,
|
i2s_tx: I2sTx<'d, T, CH, Async>,
|
||||||
_buffer: BUFFER,
|
_buffer: BUFFER,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2102,7 +2362,7 @@ pub mod asynch {
|
|||||||
RXBUF: WriteBuffer<Word = u8>;
|
RXBUF: WriteBuffer<Word = u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, CH> I2sReadDmaAsync<'d, T, CH> for super::I2sRx<'d, T, CH>
|
impl<'d, T, CH> I2sReadDmaAsync<'d, T, CH> for super::I2sRx<'d, T, CH, Async>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
@ -2146,7 +2406,7 @@ pub mod asynch {
|
|||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
{
|
{
|
||||||
i2s_rx: I2sRx<'d, T, CH>,
|
i2s_rx: I2sRx<'d, T, CH, Async>,
|
||||||
_buffer: BUFFER,
|
_buffer: BUFFER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -77,7 +77,10 @@
|
|||||||
//! transfer.wait().unwrap();
|
//! transfer.wait().unwrap();
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use embedded_dma::{ReadBuffer, WriteBuffer};
|
use embedded_dma::{ReadBuffer, WriteBuffer};
|
||||||
|
use enumset::{EnumSet, EnumSetType};
|
||||||
use fugit::HertzU32;
|
use fugit::HertzU32;
|
||||||
use peripheral::PeripheralRef;
|
use peripheral::PeripheralRef;
|
||||||
use private::*;
|
use private::*;
|
||||||
@ -86,14 +89,24 @@ use crate::{
|
|||||||
clock::Clocks,
|
clock::Clocks,
|
||||||
dma::{Channel, ChannelTypes, DmaError, DmaPeripheral, ParlIoPeripheral, RxPrivate, TxPrivate},
|
dma::{Channel, ChannelTypes, DmaError, DmaPeripheral, ParlIoPeripheral, RxPrivate, TxPrivate},
|
||||||
gpio::{InputPin, OutputPin},
|
gpio::{InputPin, OutputPin},
|
||||||
|
interrupt::InterruptHandler,
|
||||||
peripheral::{self, Peripheral},
|
peripheral::{self, Peripheral},
|
||||||
peripherals,
|
peripherals,
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
|
Blocking,
|
||||||
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
const MAX_DMA_SIZE: usize = 32736;
|
const MAX_DMA_SIZE: usize = 32736;
|
||||||
|
|
||||||
|
#[derive(EnumSetType)]
|
||||||
|
pub enum ParlIoInterrupt {
|
||||||
|
TxFifoReEmpty,
|
||||||
|
RxFifoWOvf,
|
||||||
|
TxEof,
|
||||||
|
}
|
||||||
|
|
||||||
/// Parallel IO errors
|
/// Parallel IO errors
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
@ -837,9 +850,10 @@ impl<'d, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH> TxCreatorFullDuplex<'d, CH>
|
impl<'d, CH, DM> TxCreatorFullDuplex<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub fn with_config<P, CP>(
|
pub fn with_config<P, CP>(
|
||||||
self,
|
self,
|
||||||
@ -848,7 +862,7 @@ where
|
|||||||
idle_value: u16,
|
idle_value: u16,
|
||||||
sample_edge: SampleEdge,
|
sample_edge: SampleEdge,
|
||||||
bit_order: BitPackOrder,
|
bit_order: BitPackOrder,
|
||||||
) -> Result<ParlIoTx<'d, CH, P, CP>, Error>
|
) -> Result<ParlIoTx<'d, CH, P, CP, DM>, Error>
|
||||||
where
|
where
|
||||||
P: FullDuplex + TxPins + ConfigurePins,
|
P: FullDuplex + TxPins + ConfigurePins,
|
||||||
CP: TxClkPin,
|
CP: TxClkPin,
|
||||||
@ -864,13 +878,15 @@ where
|
|||||||
tx_channel: self.tx_channel,
|
tx_channel: self.tx_channel,
|
||||||
_pins: tx_pins,
|
_pins: tx_pins,
|
||||||
_clk_pin: clk_pin,
|
_clk_pin: clk_pin,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH> TxCreator<'d, CH>
|
impl<'d, CH, DM> TxCreator<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub fn with_config<P, CP>(
|
pub fn with_config<P, CP>(
|
||||||
self,
|
self,
|
||||||
@ -879,7 +895,7 @@ where
|
|||||||
idle_value: u16,
|
idle_value: u16,
|
||||||
sample_edge: SampleEdge,
|
sample_edge: SampleEdge,
|
||||||
bit_order: BitPackOrder,
|
bit_order: BitPackOrder,
|
||||||
) -> Result<ParlIoTx<'d, CH, P, CP>, Error>
|
) -> Result<ParlIoTx<'d, CH, P, CP, DM>, Error>
|
||||||
where
|
where
|
||||||
P: TxPins + ConfigurePins,
|
P: TxPins + ConfigurePins,
|
||||||
CP: TxClkPin,
|
CP: TxClkPin,
|
||||||
@ -895,36 +911,41 @@ where
|
|||||||
tx_channel: self.tx_channel,
|
tx_channel: self.tx_channel,
|
||||||
_pins: tx_pins,
|
_pins: tx_pins,
|
||||||
_clk_pin: clk_pin,
|
_clk_pin: clk_pin,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parallel IO TX channel
|
/// Parallel IO TX channel
|
||||||
pub struct ParlIoTx<'d, CH, P, CP>
|
pub struct ParlIoTx<'d, CH, P, CP, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
P: TxPins + ConfigurePins,
|
P: TxPins + ConfigurePins,
|
||||||
CP: TxClkPin,
|
CP: TxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
tx_channel: CH::Tx<'d>,
|
tx_channel: CH::Tx<'d>,
|
||||||
_pins: P,
|
_pins: P,
|
||||||
_clk_pin: CP,
|
_clk_pin: CP,
|
||||||
|
phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH, P, CP> core::fmt::Debug for ParlIoTx<'d, CH, P, CP>
|
impl<'d, CH, P, CP, DM> core::fmt::Debug for ParlIoTx<'d, CH, P, CP, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
P: TxPins + ConfigurePins,
|
P: TxPins + ConfigurePins,
|
||||||
CP: TxClkPin,
|
CP: TxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("ParlIoTx").finish()
|
f.debug_struct("ParlIoTx").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH> RxCreatorFullDuplex<'d, CH>
|
impl<'d, CH, DM> RxCreatorFullDuplex<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub fn with_config<P, CP>(
|
pub fn with_config<P, CP>(
|
||||||
self,
|
self,
|
||||||
@ -932,7 +953,7 @@ where
|
|||||||
mut clk_pin: CP,
|
mut clk_pin: CP,
|
||||||
bit_order: BitPackOrder,
|
bit_order: BitPackOrder,
|
||||||
timeout_ticks: Option<u16>,
|
timeout_ticks: Option<u16>,
|
||||||
) -> Result<ParlIoRx<'d, CH, P, CP>, Error>
|
) -> Result<ParlIoRx<'d, CH, P, CP, DM>, Error>
|
||||||
where
|
where
|
||||||
P: FullDuplex + RxPins + ConfigurePins,
|
P: FullDuplex + RxPins + ConfigurePins,
|
||||||
CP: RxClkPin,
|
CP: RxClkPin,
|
||||||
@ -947,13 +968,15 @@ where
|
|||||||
rx_channel: self.rx_channel,
|
rx_channel: self.rx_channel,
|
||||||
_pins: rx_pins,
|
_pins: rx_pins,
|
||||||
_clk_pin: clk_pin,
|
_clk_pin: clk_pin,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH> RxCreator<'d, CH>
|
impl<'d, CH, DM> RxCreator<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub fn with_config<P, CP>(
|
pub fn with_config<P, CP>(
|
||||||
self,
|
self,
|
||||||
@ -961,7 +984,7 @@ where
|
|||||||
mut clk_pin: CP,
|
mut clk_pin: CP,
|
||||||
bit_order: BitPackOrder,
|
bit_order: BitPackOrder,
|
||||||
timeout_ticks: Option<u16>,
|
timeout_ticks: Option<u16>,
|
||||||
) -> Result<ParlIoRx<'d, CH, P, CP>, Error>
|
) -> Result<ParlIoRx<'d, CH, P, CP, DM>, Error>
|
||||||
where
|
where
|
||||||
P: RxPins + ConfigurePins,
|
P: RxPins + ConfigurePins,
|
||||||
CP: RxClkPin,
|
CP: RxClkPin,
|
||||||
@ -976,142 +999,343 @@ where
|
|||||||
rx_channel: self.rx_channel,
|
rx_channel: self.rx_channel,
|
||||||
_pins: rx_pins,
|
_pins: rx_pins,
|
||||||
_clk_pin: clk_pin,
|
_clk_pin: clk_pin,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parallel IO RX channel
|
/// Parallel IO RX channel
|
||||||
pub struct ParlIoRx<'d, CH, P, CP>
|
pub struct ParlIoRx<'d, CH, P, CP, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
P: RxPins + ConfigurePins,
|
P: RxPins + ConfigurePins,
|
||||||
CP: RxClkPin,
|
CP: RxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
rx_channel: CH::Rx<'d>,
|
rx_channel: CH::Rx<'d>,
|
||||||
_pins: P,
|
_pins: P,
|
||||||
_clk_pin: CP,
|
_clk_pin: CP,
|
||||||
|
phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH, P, CP> core::fmt::Debug for ParlIoRx<'d, CH, P, CP>
|
impl<'d, CH, P, CP, DM> core::fmt::Debug for ParlIoRx<'d, CH, P, CP, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
P: RxPins + ConfigurePins,
|
P: RxPins + ConfigurePins,
|
||||||
CP: RxClkPin,
|
CP: RxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("ParlIoTx").finish()
|
f.debug_struct("ParlIoTx").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn internal_set_interrupt_handler(handler: InterruptHandler) {
|
||||||
|
#[cfg(esp32c6)]
|
||||||
|
{
|
||||||
|
unsafe { crate::peripherals::PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler());
|
||||||
|
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::PARL_IO, handler.priority())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
#[cfg(esp32h2)]
|
||||||
|
{
|
||||||
|
unsafe { crate::peripherals::PARL_IO::steal() }
|
||||||
|
.bind_parl_io_tx_interrupt(handler.handler());
|
||||||
|
unsafe { crate::peripherals::PARL_IO::steal() }
|
||||||
|
.bind_parl_io_rx_interrupt(handler.handler());
|
||||||
|
|
||||||
|
crate::interrupt::enable(
|
||||||
|
crate::peripherals::Interrupt::PARL_IO_TX,
|
||||||
|
handler.priority(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
crate::interrupt::enable(
|
||||||
|
crate::peripherals::Interrupt::PARL_IO_RX,
|
||||||
|
handler.priority(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_listen(interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
let parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
ParlIoInterrupt::TxFifoReEmpty => parl_io
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_fifo_rempty_int_ena().set_bit()),
|
||||||
|
ParlIoInterrupt::RxFifoWOvf => parl_io
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_fifo_wovf_int_ena().set_bit()),
|
||||||
|
ParlIoInterrupt::TxEof => parl_io.int_ena().write(|w| w.tx_eof_int_ena().set_bit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_unlisten(interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
let parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
ParlIoInterrupt::TxFifoReEmpty => parl_io
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.tx_fifo_rempty_int_ena().clear_bit()),
|
||||||
|
ParlIoInterrupt::RxFifoWOvf => parl_io
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.rx_fifo_wovf_int_ena().clear_bit()),
|
||||||
|
ParlIoInterrupt::TxEof => parl_io.int_ena().write(|w| w.tx_eof_int_ena().clear_bit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
|
||||||
|
let mut res = EnumSet::new();
|
||||||
|
let parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
|
||||||
|
let ints = parl_io.int_st().read();
|
||||||
|
if ints.tx_fifo_rempty_int_st().bit() {
|
||||||
|
res.insert(ParlIoInterrupt::TxFifoReEmpty);
|
||||||
|
}
|
||||||
|
if ints.rx_fifo_wovf_int_st().bit() {
|
||||||
|
res.insert(ParlIoInterrupt::RxFifoWOvf);
|
||||||
|
}
|
||||||
|
if ints.tx_eof_int_st().bit() {
|
||||||
|
res.insert(ParlIoInterrupt::TxEof);
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_clear_interrupts(interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
let parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
ParlIoInterrupt::TxFifoReEmpty => parl_io
|
||||||
|
.int_clr()
|
||||||
|
.write(|w| w.tx_fifo_rempty_int_clr().set_bit()),
|
||||||
|
ParlIoInterrupt::RxFifoWOvf => parl_io
|
||||||
|
.int_clr()
|
||||||
|
.write(|w| w.rx_fifo_wovf_int_clr().set_bit()),
|
||||||
|
ParlIoInterrupt::TxEof => parl_io.int_clr().write(|w| w.tx_eof_int_clr().set_bit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parallel IO in full duplex mode
|
/// Parallel IO in full duplex mode
|
||||||
///
|
///
|
||||||
/// Full duplex mode might limit the maximum possible bit width.
|
/// Full duplex mode might limit the maximum possible bit width.
|
||||||
pub struct ParlIoFullDuplex<'d, CH>
|
pub struct ParlIoFullDuplex<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
_parl_io: PeripheralRef<'d, peripherals::PARL_IO>,
|
pub tx: TxCreatorFullDuplex<'d, CH, DM>,
|
||||||
pub tx: TxCreatorFullDuplex<'d, CH>,
|
pub rx: RxCreatorFullDuplex<'d, CH, DM>,
|
||||||
pub rx: RxCreatorFullDuplex<'d, CH>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH> ParlIoFullDuplex<'d, CH>
|
impl<'d, CH, DM> ParlIoFullDuplex<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
||||||
mut dma_channel: Channel<'d, CH>,
|
mut dma_channel: Channel<'d, CH, DM>,
|
||||||
frequency: HertzU32,
|
frequency: HertzU32,
|
||||||
_clocks: &Clocks,
|
_clocks: &Clocks,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
crate::into_ref!(parl_io);
|
|
||||||
internal_init(&mut dma_channel, frequency)?;
|
internal_init(&mut dma_channel, frequency)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
_parl_io: parl_io,
|
|
||||||
tx: TxCreatorFullDuplex {
|
tx: TxCreatorFullDuplex {
|
||||||
tx_channel: dma_channel.tx,
|
tx_channel: dma_channel.tx,
|
||||||
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
rx: RxCreatorFullDuplex {
|
rx: RxCreatorFullDuplex {
|
||||||
rx_channel: dma_channel.rx,
|
rx_channel: dma_channel.rx,
|
||||||
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d, CH> ParlIoFullDuplex<'d, CH, Blocking>
|
||||||
|
where
|
||||||
|
CH: ChannelTypes,
|
||||||
|
CH::P: ParlIoPeripheral,
|
||||||
|
{
|
||||||
|
/// Sets the interrupt handler, enables it with
|
||||||
|
/// [crate::interrupt::Priority::min()]
|
||||||
|
///
|
||||||
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
|
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
internal_set_interrupt_handler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Listen for the given interrupts
|
||||||
|
pub fn listen(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_listen(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlisten the given interrupts
|
||||||
|
pub fn unlisten(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_unlisten(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets asserted interrupts
|
||||||
|
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
|
||||||
|
internal_interrupts()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets asserted interrupts
|
||||||
|
pub fn clear_interrupts(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_clear_interrupts(interrupts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parallel IO in half duplex / TX only mode
|
/// Parallel IO in half duplex / TX only mode
|
||||||
pub struct ParlIoTxOnly<'d, CH>
|
pub struct ParlIoTxOnly<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
_parl_io: PeripheralRef<'d, peripherals::PARL_IO>,
|
pub tx: TxCreator<'d, CH, DM>,
|
||||||
pub tx: TxCreator<'d, CH>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH> ParlIoTxOnly<'d, CH>
|
impl<'d, CH, DM> ParlIoTxOnly<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
||||||
mut dma_channel: Channel<'d, CH>,
|
mut dma_channel: Channel<'d, CH, DM>,
|
||||||
frequency: HertzU32,
|
frequency: HertzU32,
|
||||||
_clocks: &Clocks,
|
_clocks: &Clocks,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
crate::into_ref!(parl_io);
|
|
||||||
internal_init(&mut dma_channel, frequency)?;
|
internal_init(&mut dma_channel, frequency)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
_parl_io: parl_io,
|
|
||||||
tx: TxCreator {
|
tx: TxCreator {
|
||||||
tx_channel: dma_channel.tx,
|
tx_channel: dma_channel.tx,
|
||||||
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d, CH> ParlIoTxOnly<'d, CH, Blocking>
|
||||||
|
where
|
||||||
|
CH: ChannelTypes,
|
||||||
|
CH::P: ParlIoPeripheral,
|
||||||
|
{
|
||||||
|
/// Sets the interrupt handler, enables it with
|
||||||
|
/// [crate::interrupt::Priority::min()]
|
||||||
|
///
|
||||||
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
|
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
internal_set_interrupt_handler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Listen for the given interrupts
|
||||||
|
pub fn listen(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_listen(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlisten the given interrupts
|
||||||
|
pub fn unlisten(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_unlisten(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets asserted interrupts
|
||||||
|
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
|
||||||
|
internal_interrupts()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets asserted interrupts
|
||||||
|
pub fn clear_interrupts(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_clear_interrupts(interrupts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parallel IO in half duplex / RX only mode
|
/// Parallel IO in half duplex / RX only mode
|
||||||
pub struct ParlIoRxOnly<'d, CH>
|
pub struct ParlIoRxOnly<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
_parl_io: PeripheralRef<'d, peripherals::PARL_IO>,
|
pub rx: RxCreator<'d, CH, DM>,
|
||||||
pub rx: RxCreator<'d, CH>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH> ParlIoRxOnly<'d, CH>
|
impl<'d, CH, DM> ParlIoRxOnly<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
||||||
mut dma_channel: Channel<'d, CH>,
|
mut dma_channel: Channel<'d, CH, DM>,
|
||||||
frequency: HertzU32,
|
frequency: HertzU32,
|
||||||
_clocks: &Clocks,
|
_clocks: &Clocks,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
crate::into_ref!(parl_io);
|
|
||||||
internal_init(&mut dma_channel, frequency)?;
|
internal_init(&mut dma_channel, frequency)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
_parl_io: parl_io,
|
|
||||||
rx: RxCreator {
|
rx: RxCreator {
|
||||||
rx_channel: dma_channel.rx,
|
rx_channel: dma_channel.rx,
|
||||||
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_init<CH>(dma_channel: &mut Channel<'_, CH>, frequency: HertzU32) -> Result<(), Error>
|
impl<'d, CH> ParlIoRxOnly<'d, CH, Blocking>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
|
{
|
||||||
|
/// Sets the interrupt handler, enables it with
|
||||||
|
/// [crate::interrupt::Priority::min()]
|
||||||
|
///
|
||||||
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
|
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
internal_set_interrupt_handler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Listen for the given interrupts
|
||||||
|
pub fn listen(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_listen(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlisten the given interrupts
|
||||||
|
pub fn unlisten(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_unlisten(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets asserted interrupts
|
||||||
|
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
|
||||||
|
internal_interrupts()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets asserted interrupts
|
||||||
|
pub fn clear_interrupts(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
|
internal_clear_interrupts(interrupts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_init<CH, DM>(
|
||||||
|
dma_channel: &mut Channel<'_, CH, DM>,
|
||||||
|
frequency: HertzU32,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
CH: ChannelTypes,
|
||||||
|
CH::P: ParlIoPeripheral,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
if frequency.raw() > 40_000_000 {
|
if frequency.raw() > 40_000_000 {
|
||||||
return Err(Error::UnreachableClockRate);
|
return Err(Error::UnreachableClockRate);
|
||||||
@ -1152,12 +1376,13 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP>
|
impl<'d, CH, P, CP, DM> ParlIoTx<'d, CH, P, CP, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
P: TxPins + ConfigurePins,
|
P: TxPins + ConfigurePins,
|
||||||
CP: TxClkPin,
|
CP: TxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
/// Perform a DMA write.
|
/// Perform a DMA write.
|
||||||
///
|
///
|
||||||
@ -1168,7 +1393,7 @@ where
|
|||||||
pub fn write_dma<'t, TXBUF>(
|
pub fn write_dma<'t, TXBUF>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
) -> Result<DmaTransfer<'t, 'd, CH, P, CP>, Error>
|
) -> Result<DmaTransfer<'t, 'd, CH, P, CP, DM>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -1212,22 +1437,24 @@ where
|
|||||||
|
|
||||||
/// An in-progress DMA transfer.
|
/// An in-progress DMA transfer.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct DmaTransfer<'t, 'd, C, P, CP>
|
pub struct DmaTransfer<'t, 'd, C, P, CP, DM>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: ParlIoPeripheral,
|
C::P: ParlIoPeripheral,
|
||||||
P: TxPins + ConfigurePins,
|
P: TxPins + ConfigurePins,
|
||||||
CP: TxClkPin,
|
CP: TxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
instance: &'t mut ParlIoTx<'d, C, P, CP>,
|
instance: &'t mut ParlIoTx<'d, C, P, CP, DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, C, P, CP> DmaTransfer<'t, 'd, C, P, CP>
|
impl<'t, 'd, C, P, CP, DM> DmaTransfer<'t, 'd, C, P, CP, DM>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: ParlIoPeripheral,
|
C::P: ParlIoPeripheral,
|
||||||
P: TxPins + ConfigurePins,
|
P: TxPins + ConfigurePins,
|
||||||
CP: TxClkPin,
|
CP: TxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
@ -1252,12 +1479,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH, P, CP> ParlIoRx<'d, CH, P, CP>
|
impl<'d, CH, P, CP, DM> ParlIoRx<'d, CH, P, CP, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
P: RxPins + ConfigurePins,
|
P: RxPins + ConfigurePins,
|
||||||
CP: RxClkPin,
|
CP: RxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
/// Perform a DMA read.
|
/// Perform a DMA read.
|
||||||
///
|
///
|
||||||
@ -1271,7 +1499,7 @@ where
|
|||||||
pub fn read_dma<'t, RXBUF>(
|
pub fn read_dma<'t, RXBUF>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
) -> Result<RxDmaTransfer<'t, 'd, CH, P, CP>, Error>
|
) -> Result<RxDmaTransfer<'t, 'd, CH, P, CP, DM>, Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -1308,22 +1536,24 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An in-progress DMA transfer.
|
/// An in-progress DMA transfer.
|
||||||
pub struct RxDmaTransfer<'t, 'd, C, P, CP>
|
pub struct RxDmaTransfer<'t, 'd, C, P, CP, DM>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: ParlIoPeripheral,
|
C::P: ParlIoPeripheral,
|
||||||
P: RxPins + ConfigurePins,
|
P: RxPins + ConfigurePins,
|
||||||
CP: RxClkPin,
|
CP: RxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
instance: &'t mut ParlIoRx<'d, C, P, CP>,
|
instance: &'t mut ParlIoRx<'d, C, P, CP, DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, C, P, CP> RxDmaTransfer<'t, 'd, C, P, CP>
|
impl<'t, 'd, C, P, CP, DM> RxDmaTransfer<'t, 'd, C, P, CP, DM>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: ParlIoPeripheral,
|
C::P: ParlIoPeripheral,
|
||||||
P: RxPins + ConfigurePins,
|
P: RxPins + ConfigurePins,
|
||||||
CP: RxClkPin,
|
CP: RxClkPin,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
@ -1362,6 +1592,7 @@ pub mod asynch {
|
|||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
use procmacros::handler;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
private::{ConfigurePins, Instance, RxClkPin, RxPins, TxClkPin, TxPins},
|
private::{ConfigurePins, Instance, RxClkPin, RxPins, TxClkPin, TxPins},
|
||||||
@ -1372,7 +1603,7 @@ pub mod asynch {
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
dma::{asynch::DmaRxDoneChFuture, ChannelTypes, ParlIoPeripheral},
|
dma::{asynch::DmaRxDoneChFuture, ChannelTypes, ParlIoPeripheral},
|
||||||
macros::interrupt,
|
peripherals::Interrupt,
|
||||||
};
|
};
|
||||||
|
|
||||||
static TX_WAKER: AtomicWaker = AtomicWaker::new();
|
static TX_WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
@ -1393,6 +1624,20 @@ pub mod asynch {
|
|||||||
self: core::pin::Pin<&mut Self>,
|
self: core::pin::Pin<&mut Self>,
|
||||||
cx: &mut core::task::Context<'_>,
|
cx: &mut core::task::Context<'_>,
|
||||||
) -> Poll<Self::Output> {
|
) -> Poll<Self::Output> {
|
||||||
|
let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
|
||||||
|
|
||||||
|
#[cfg(esp32c6)]
|
||||||
|
{
|
||||||
|
parl_io.bind_parl_io_interrupt(interrupt_handler.handler());
|
||||||
|
crate::interrupt::enable(Interrupt::PARL_IO, interrupt_handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
#[cfg(esp32h2)]
|
||||||
|
{
|
||||||
|
parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler());
|
||||||
|
crate::interrupt::enable(Interrupt::PARL_IO_TX, interrupt_handler.priority())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
TX_WAKER.register(cx.waker());
|
TX_WAKER.register(cx.waker());
|
||||||
if Instance::is_listening_tx_done() {
|
if Instance::is_listening_tx_done() {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -1402,9 +1647,8 @@ pub mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(esp32c6)]
|
#[handler]
|
||||||
#[interrupt]
|
fn interrupt_handler() {
|
||||||
fn PARL_IO() {
|
|
||||||
if Instance::is_tx_done_set() {
|
if Instance::is_tx_done_set() {
|
||||||
Instance::clear_is_tx_done();
|
Instance::clear_is_tx_done();
|
||||||
Instance::unlisten_tx_done();
|
Instance::unlisten_tx_done();
|
||||||
@ -1412,17 +1656,7 @@ pub mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(esp32h2)]
|
impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP, crate::Async>
|
||||||
#[interrupt]
|
|
||||||
fn PARL_IO_TX() {
|
|
||||||
if Instance::is_tx_done_set() {
|
|
||||||
Instance::clear_is_tx_done();
|
|
||||||
Instance::unlisten_tx_done();
|
|
||||||
TX_WAKER.wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, CH, P, CP> ParlIoTx<'d, CH, P, CP>
|
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
@ -1447,7 +1681,7 @@ pub mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH, P, CP> ParlIoRx<'d, CH, P, CP>
|
impl<'d, CH, P, CP> ParlIoRx<'d, CH, P, CP, crate::Async>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
CH::P: ParlIoPeripheral,
|
CH::P: ParlIoPeripheral,
|
||||||
@ -1476,8 +1710,10 @@ pub mod asynch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use super::{BitPackOrder, EofMode, Error, SampleEdge};
|
use super::{BitPackOrder, EofMode, Error, SampleEdge};
|
||||||
use crate::dma::ChannelTypes;
|
use crate::{dma::ChannelTypes, Mode};
|
||||||
|
|
||||||
pub trait FullDuplex {}
|
pub trait FullDuplex {}
|
||||||
|
|
||||||
@ -1501,32 +1737,40 @@ mod private {
|
|||||||
fn configure(&mut self) -> Result<(), Error>;
|
fn configure(&mut self) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TxCreator<'d, CH>
|
pub struct TxCreator<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub tx_channel: CH::Tx<'d>,
|
pub tx_channel: CH::Tx<'d>,
|
||||||
|
pub(crate) phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RxCreator<'d, CH>
|
pub struct RxCreator<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub rx_channel: CH::Rx<'d>,
|
pub rx_channel: CH::Rx<'d>,
|
||||||
|
pub(crate) phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TxCreatorFullDuplex<'d, CH>
|
pub struct TxCreatorFullDuplex<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub tx_channel: CH::Tx<'d>,
|
pub tx_channel: CH::Tx<'d>,
|
||||||
|
pub(crate) phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RxCreatorFullDuplex<'d, CH>
|
pub struct RxCreatorFullDuplex<'d, CH, DM>
|
||||||
where
|
where
|
||||||
CH: ChannelTypes,
|
CH: ChannelTypes,
|
||||||
|
DM: Mode,
|
||||||
{
|
{
|
||||||
pub rx_channel: CH::Rx<'d>,
|
pub rx_channel: CH::Rx<'d>,
|
||||||
|
pub(crate) phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(esp32c6)]
|
#[cfg(esp32c6)]
|
||||||
@ -1670,7 +1914,7 @@ mod private {
|
|||||||
|
|
||||||
reg_block
|
reg_block
|
||||||
.int_clr()
|
.int_clr()
|
||||||
.write(|w| w.rx_fifo_wfull_int_clr().set_bit());
|
.write(|w| w.rx_fifo_wovf_int_clr().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_rx_bytes(len: u16) {
|
pub fn set_rx_bytes(len: u16) {
|
||||||
|
|||||||
@ -37,8 +37,8 @@ crate::peripherals! {
|
|||||||
HINF <= HINF,
|
HINF <= HINF,
|
||||||
I2C0 <= I2C0,
|
I2C0 <= I2C0,
|
||||||
I2C1 <= I2C1,
|
I2C1 <= I2C1,
|
||||||
I2S0 <= I2S0,
|
I2S0 <= I2S0 (I2S0),
|
||||||
I2S1 <= I2S1,
|
I2S1 <= I2S1 (I2S1),
|
||||||
IO_MUX <= IO_MUX,
|
IO_MUX <= IO_MUX,
|
||||||
LEDC <= LEDC,
|
LEDC <= LEDC,
|
||||||
MCPWM0 <= MCPWM0,
|
MCPWM0 <= MCPWM0,
|
||||||
@ -58,8 +58,8 @@ crate::peripherals! {
|
|||||||
SLCHOST <= SLCHOST,
|
SLCHOST <= SLCHOST,
|
||||||
SPI0 <= SPI0,
|
SPI0 <= SPI0,
|
||||||
SPI1 <= SPI1,
|
SPI1 <= SPI1,
|
||||||
SPI2 <= SPI2,
|
SPI2 <= SPI2 (SPI2_DMA, SPI2),
|
||||||
SPI3 <= SPI3,
|
SPI3 <= SPI3 (SPI3_DMA, SPI3),
|
||||||
SYSTEM <= DPORT,
|
SYSTEM <= DPORT,
|
||||||
TIMG0 <= TIMG0,
|
TIMG0 <= TIMG0,
|
||||||
TIMG1 <= TIMG1,
|
TIMG1 <= TIMG1,
|
||||||
|
|||||||
@ -24,7 +24,7 @@ crate::peripherals! {
|
|||||||
APB_CTRL <= APB_CTRL,
|
APB_CTRL <= APB_CTRL,
|
||||||
ASSIST_DEBUG <= ASSIST_DEBUG,
|
ASSIST_DEBUG <= ASSIST_DEBUG,
|
||||||
BT <= virtual,
|
BT <= virtual,
|
||||||
DMA <= DMA,
|
DMA <= DMA (DMA_CH0),
|
||||||
ECC <= ECC,
|
ECC <= ECC,
|
||||||
EFUSE <= EFUSE,
|
EFUSE <= EFUSE,
|
||||||
EXTMEM <= EXTMEM,
|
EXTMEM <= EXTMEM,
|
||||||
@ -39,7 +39,7 @@ crate::peripherals! {
|
|||||||
SHA <= SHA,
|
SHA <= SHA,
|
||||||
SPI0 <= SPI0,
|
SPI0 <= SPI0,
|
||||||
SPI1 <= SPI1,
|
SPI1 <= SPI1,
|
||||||
SPI2 <= SPI2,
|
SPI2 <= SPI2 (SPI2),
|
||||||
SYSTEM <= SYSTEM,
|
SYSTEM <= SYSTEM,
|
||||||
SYSTIMER <= SYSTIMER,
|
SYSTIMER <= SYSTIMER,
|
||||||
TIMG0 <= TIMG0,
|
TIMG0 <= TIMG0,
|
||||||
|
|||||||
@ -26,7 +26,7 @@ crate::peripherals! {
|
|||||||
APB_CTRL <= APB_CTRL,
|
APB_CTRL <= APB_CTRL,
|
||||||
ASSIST_DEBUG <= ASSIST_DEBUG,
|
ASSIST_DEBUG <= ASSIST_DEBUG,
|
||||||
BT <= virtual,
|
BT <= virtual,
|
||||||
DMA <= DMA,
|
DMA <= DMA (DMA_CH0,DMA_CH1,DMA_CH2),
|
||||||
DS <= DS,
|
DS <= DS,
|
||||||
EFUSE <= EFUSE,
|
EFUSE <= EFUSE,
|
||||||
EXTMEM <= EXTMEM,
|
EXTMEM <= EXTMEM,
|
||||||
@ -34,7 +34,7 @@ crate::peripherals! {
|
|||||||
GPIO_SD <= GPIO_SD,
|
GPIO_SD <= GPIO_SD,
|
||||||
HMAC <= HMAC,
|
HMAC <= HMAC,
|
||||||
I2C0 <= I2C0,
|
I2C0 <= I2C0,
|
||||||
I2S0 <= I2S0,
|
I2S0 <= I2S0 (I2S0),
|
||||||
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
||||||
IO_MUX <= IO_MUX,
|
IO_MUX <= IO_MUX,
|
||||||
LEDC <= LEDC,
|
LEDC <= LEDC,
|
||||||
@ -46,7 +46,7 @@ crate::peripherals! {
|
|||||||
SHA <= SHA,
|
SHA <= SHA,
|
||||||
SPI0 <= SPI0,
|
SPI0 <= SPI0,
|
||||||
SPI1 <= SPI1,
|
SPI1 <= SPI1,
|
||||||
SPI2 <= SPI2,
|
SPI2 <= SPI2 (SPI2),
|
||||||
SYSTEM <= SYSTEM,
|
SYSTEM <= SYSTEM,
|
||||||
SYSTIMER <= SYSTIMER,
|
SYSTIMER <= SYSTIMER,
|
||||||
TIMG0 <= TIMG0,
|
TIMG0 <= TIMG0,
|
||||||
|
|||||||
@ -25,7 +25,7 @@ crate::peripherals! {
|
|||||||
ASSIST_DEBUG <= ASSIST_DEBUG,
|
ASSIST_DEBUG <= ASSIST_DEBUG,
|
||||||
ATOMIC <= ATOMIC,
|
ATOMIC <= ATOMIC,
|
||||||
BT <= virtual,
|
BT <= virtual,
|
||||||
DMA <= DMA,
|
DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2),
|
||||||
DS <= DS,
|
DS <= DS,
|
||||||
ECC <= ECC,
|
ECC <= ECC,
|
||||||
EFUSE <= EFUSE,
|
EFUSE <= EFUSE,
|
||||||
@ -37,7 +37,7 @@ crate::peripherals! {
|
|||||||
HP_APM <= HP_APM,
|
HP_APM <= HP_APM,
|
||||||
HP_SYS <= HP_SYS,
|
HP_SYS <= HP_SYS,
|
||||||
I2C0 <= I2C0,
|
I2C0 <= I2C0,
|
||||||
I2S0 <= I2S0,
|
I2S0 <= I2S0 (I2S0),
|
||||||
IEEE802154 <= virtual,
|
IEEE802154 <= virtual,
|
||||||
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
||||||
INTPRI <= INTPRI,
|
INTPRI <= INTPRI,
|
||||||
@ -60,7 +60,7 @@ crate::peripherals! {
|
|||||||
MCPWM0 <= MCPWM0,
|
MCPWM0 <= MCPWM0,
|
||||||
MEM_MONITOR <= MEM_MONITOR,
|
MEM_MONITOR <= MEM_MONITOR,
|
||||||
OTP_DEBUG <= OTP_DEBUG,
|
OTP_DEBUG <= OTP_DEBUG,
|
||||||
PARL_IO <= PARL_IO,
|
PARL_IO <= PARL_IO (PARL_IO),
|
||||||
PAU <= PAU,
|
PAU <= PAU,
|
||||||
PCNT <= PCNT,
|
PCNT <= PCNT,
|
||||||
PMU <= PMU,
|
PMU <= PMU,
|
||||||
@ -72,7 +72,7 @@ crate::peripherals! {
|
|||||||
SOC_ETM <= SOC_ETM,
|
SOC_ETM <= SOC_ETM,
|
||||||
SPI0 <= SPI0,
|
SPI0 <= SPI0,
|
||||||
SPI1 <= SPI1,
|
SPI1 <= SPI1,
|
||||||
SPI2 <= SPI2,
|
SPI2 <= SPI2 (SPI2),
|
||||||
SYSTEM <= PCR,
|
SYSTEM <= PCR,
|
||||||
SYSTIMER <= SYSTIMER,
|
SYSTIMER <= SYSTIMER,
|
||||||
TEE <= TEE,
|
TEE <= TEE,
|
||||||
|
|||||||
@ -24,7 +24,7 @@ crate::peripherals! {
|
|||||||
AES <= AES,
|
AES <= AES,
|
||||||
ASSIST_DEBUG <= ASSIST_DEBUG,
|
ASSIST_DEBUG <= ASSIST_DEBUG,
|
||||||
BT <= virtual,
|
BT <= virtual,
|
||||||
DMA <= DMA,
|
DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2),
|
||||||
DS <= DS,
|
DS <= DS,
|
||||||
ECC <= ECC,
|
ECC <= ECC,
|
||||||
EFUSE <= EFUSE,
|
EFUSE <= EFUSE,
|
||||||
@ -35,7 +35,7 @@ crate::peripherals! {
|
|||||||
HP_SYS <= HP_SYS,
|
HP_SYS <= HP_SYS,
|
||||||
I2C0 <= I2C0,
|
I2C0 <= I2C0,
|
||||||
I2C1 <= I2C1,
|
I2C1 <= I2C1,
|
||||||
I2S0 <= I2S0,
|
I2S0 <= I2S0 (I2S0),
|
||||||
IEEE802154 <= virtual,
|
IEEE802154 <= virtual,
|
||||||
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
||||||
INTPRI <= INTPRI,
|
INTPRI <= INTPRI,
|
||||||
@ -53,7 +53,7 @@ crate::peripherals! {
|
|||||||
MODEM_LPCON <= MODEM_LPCON,
|
MODEM_LPCON <= MODEM_LPCON,
|
||||||
MODEM_SYSCON <= MODEM_SYSCON,
|
MODEM_SYSCON <= MODEM_SYSCON,
|
||||||
OTP_DEBUG <= OTP_DEBUG,
|
OTP_DEBUG <= OTP_DEBUG,
|
||||||
PARL_IO <= PARL_IO,
|
PARL_IO <= PARL_IO (PARL_IO_TX, PARL_IO_RX),
|
||||||
PAU <= PAU,
|
PAU <= PAU,
|
||||||
PCNT <= PCNT,
|
PCNT <= PCNT,
|
||||||
PMU <= PMU,
|
PMU <= PMU,
|
||||||
@ -64,7 +64,7 @@ crate::peripherals! {
|
|||||||
SOC_ETM <= SOC_ETM,
|
SOC_ETM <= SOC_ETM,
|
||||||
SPI0 <= SPI0,
|
SPI0 <= SPI0,
|
||||||
SPI1 <= SPI1,
|
SPI1 <= SPI1,
|
||||||
SPI2 <= SPI2,
|
SPI2 <= SPI2 (SPI2),
|
||||||
SYSTEM <= PCR,
|
SYSTEM <= PCR,
|
||||||
SYSTIMER <= SYSTIMER,
|
SYSTIMER <= SYSTIMER,
|
||||||
TEE <= TEE,
|
TEE <= TEE,
|
||||||
|
|||||||
@ -35,7 +35,7 @@ crate::peripherals! {
|
|||||||
HMAC <= HMAC,
|
HMAC <= HMAC,
|
||||||
I2C0 <= I2C0,
|
I2C0 <= I2C0,
|
||||||
I2C1 <= I2C1,
|
I2C1 <= I2C1,
|
||||||
I2S0 <= I2S0,
|
I2S0 <= I2S0 (I2S0),
|
||||||
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
||||||
IO_MUX <= IO_MUX,
|
IO_MUX <= IO_MUX,
|
||||||
LEDC <= LEDC,
|
LEDC <= LEDC,
|
||||||
@ -51,8 +51,8 @@ crate::peripherals! {
|
|||||||
SHA <= SHA,
|
SHA <= SHA,
|
||||||
SPI0 <= SPI0,
|
SPI0 <= SPI0,
|
||||||
SPI1 <= SPI1,
|
SPI1 <= SPI1,
|
||||||
SPI2 <= SPI2,
|
SPI2 <= SPI2 (SPI2_DMA, SPI2),
|
||||||
SPI3 <= SPI3,
|
SPI3 <= SPI3 (SPI3_DMA, SPI3),
|
||||||
SPI4 <= SPI4,
|
SPI4 <= SPI4,
|
||||||
SYSCON <= SYSCON,
|
SYSCON <= SYSCON,
|
||||||
SYSTEM <= SYSTEM,
|
SYSTEM <= SYSTEM,
|
||||||
|
|||||||
@ -26,7 +26,7 @@ crate::peripherals! {
|
|||||||
APB_CTRL <= APB_CTRL,
|
APB_CTRL <= APB_CTRL,
|
||||||
ASSIST_DEBUG <= ASSIST_DEBUG,
|
ASSIST_DEBUG <= ASSIST_DEBUG,
|
||||||
BT <= virtual,
|
BT <= virtual,
|
||||||
DMA <= DMA,
|
DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_IN_CH3,DMA_IN_CH4,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2,DMA_OUT_CH3,DMA_OUT_CH4),
|
||||||
DS <= DS,
|
DS <= DS,
|
||||||
EFUSE <= EFUSE,
|
EFUSE <= EFUSE,
|
||||||
EXTMEM <= EXTMEM,
|
EXTMEM <= EXTMEM,
|
||||||
@ -35,8 +35,8 @@ crate::peripherals! {
|
|||||||
HMAC <= HMAC,
|
HMAC <= HMAC,
|
||||||
I2C0 <= I2C0,
|
I2C0 <= I2C0,
|
||||||
I2C1 <= I2C1,
|
I2C1 <= I2C1,
|
||||||
I2S0 <= I2S0,
|
I2S0 <= I2S0 (I2S0),
|
||||||
I2S1 <= I2S1,
|
I2S1 <= I2S1 (I2S1),
|
||||||
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
|
||||||
INTERRUPT_CORE1 <= INTERRUPT_CORE1,
|
INTERRUPT_CORE1 <= INTERRUPT_CORE1,
|
||||||
IO_MUX <= IO_MUX,
|
IO_MUX <= IO_MUX,
|
||||||
@ -57,8 +57,8 @@ crate::peripherals! {
|
|||||||
SHA <= SHA,
|
SHA <= SHA,
|
||||||
SPI0 <= SPI0,
|
SPI0 <= SPI0,
|
||||||
SPI1 <= SPI1,
|
SPI1 <= SPI1,
|
||||||
SPI2 <= SPI2,
|
SPI2 <= SPI2 (SPI2),
|
||||||
SPI3 <= SPI3,
|
SPI3 <= SPI3 (SPI3),
|
||||||
SYSTEM <= SYSTEM,
|
SYSTEM <= SYSTEM,
|
||||||
SYSTIMER <= SYSTIMER,
|
SYSTIMER <= SYSTIMER,
|
||||||
TIMG0 <= TIMG0,
|
TIMG0 <= TIMG0,
|
||||||
|
|||||||
@ -49,6 +49,10 @@
|
|||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
use enumset::EnumSet;
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
use enumset::EnumSetType;
|
||||||
use fugit::HertzU32;
|
use fugit::HertzU32;
|
||||||
#[cfg(feature = "place-spi-driver-in-ram")]
|
#[cfg(feature = "place-spi-driver-in-ram")]
|
||||||
use procmacros::ram;
|
use procmacros::ram;
|
||||||
@ -67,6 +71,7 @@ use crate::{
|
|||||||
clock::Clocks,
|
clock::Clocks,
|
||||||
dma::{DmaPeripheral, Rx, Tx},
|
dma::{DmaPeripheral, Rx, Tx},
|
||||||
gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
|
gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
|
||||||
|
interrupt::InterruptHandler,
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::spi2::RegisterBlock,
|
peripherals::spi2::RegisterBlock,
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
@ -83,6 +88,12 @@ pub mod prelude {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
#[derive(EnumSetType)]
|
||||||
|
pub enum SpiInterrupt {
|
||||||
|
TransDone,
|
||||||
|
}
|
||||||
|
|
||||||
/// The size of the FIFO buffer for SPI
|
/// The size of the FIFO buffer for SPI
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32s2))]
|
||||||
const FIFO_SIZE: usize = 64;
|
const FIFO_SIZE: usize = 64;
|
||||||
@ -780,37 +791,47 @@ pub mod dma {
|
|||||||
TxPrivate,
|
TxPrivate,
|
||||||
},
|
},
|
||||||
FlashSafeDma,
|
FlashSafeDma,
|
||||||
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait WithDmaSpi2<'d, C, M>
|
pub trait WithDmaSpi2<'d, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI2, C, M>;
|
fn with_dma(
|
||||||
|
self,
|
||||||
|
channel: Channel<'d, C, DmaMode>,
|
||||||
|
) -> SpiDma<'d, crate::peripherals::SPI2, C, M, DmaMode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(spi3)]
|
#[cfg(spi3)]
|
||||||
pub trait WithDmaSpi3<'d, C, M>
|
pub trait WithDmaSpi3<'d, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI3, C, M>;
|
fn with_dma(
|
||||||
|
self,
|
||||||
|
channel: Channel<'d, C, DmaMode>,
|
||||||
|
) -> SpiDma<'d, crate::peripherals::SPI3, C, M, DmaMode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, C, M> WithDmaSpi2<'d, C, M> for Spi<'d, crate::peripherals::SPI2, M>
|
impl<'d, C, M, DmaMode> WithDmaSpi2<'d, C, M, DmaMode> for Spi<'d, crate::peripherals::SPI2, M>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral + Spi2Peripheral,
|
C::P: SpiPeripheral + Spi2Peripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(
|
fn with_dma(
|
||||||
self,
|
self,
|
||||||
mut channel: Channel<'d, C>,
|
mut channel: Channel<'d, C, DmaMode>,
|
||||||
) -> SpiDma<'d, crate::peripherals::SPI2, C, M> {
|
) -> SpiDma<'d, crate::peripherals::SPI2, C, M, DmaMode> {
|
||||||
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
||||||
|
|
||||||
SpiDma {
|
SpiDma {
|
||||||
@ -822,16 +843,17 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(spi3)]
|
#[cfg(spi3)]
|
||||||
impl<'d, C, M> WithDmaSpi3<'d, C, M> for Spi<'d, crate::peripherals::SPI3, M>
|
impl<'d, C, M, DmaMode> WithDmaSpi3<'d, C, M, DmaMode> for Spi<'d, crate::peripherals::SPI3, M>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral + Spi3Peripheral,
|
C::P: SpiPeripheral + Spi3Peripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(
|
fn with_dma(
|
||||||
self,
|
self,
|
||||||
mut channel: Channel<'d, C>,
|
mut channel: Channel<'d, C, DmaMode>,
|
||||||
) -> SpiDma<'d, crate::peripherals::SPI3, C, M> {
|
) -> SpiDma<'d, crate::peripherals::SPI3, C, M, DmaMode> {
|
||||||
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
||||||
|
|
||||||
SpiDma {
|
SpiDma {
|
||||||
@ -843,22 +865,24 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
/// An in-progress DMA transfer
|
/// An in-progress DMA transfer
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M>
|
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
spi_dma: &'t mut SpiDma<'d, T, C, M>,
|
spi_dma: &'t mut SpiDma<'d, T, C, M, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C, M> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, M>
|
impl<'t, 'd, T, C, M, DmaMode> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
fn wait(self) -> Result<(), DmaError> {
|
fn wait(self) -> Result<(), DmaError> {
|
||||||
@ -880,12 +904,13 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C, M> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, M>
|
impl<'t, 'd, T, C, M, DmaMode> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.spi_dma.spi.flush().ok();
|
self.spi_dma.spi.flush().ok();
|
||||||
@ -894,22 +919,24 @@ pub mod dma {
|
|||||||
|
|
||||||
/// An in-progress DMA transfer.
|
/// An in-progress DMA transfer.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct SpiDmaTransfer<'t, 'd, T, C, M>
|
pub struct SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
spi_dma: &'t mut SpiDma<'d, T, C, M>,
|
spi_dma: &'t mut SpiDma<'d, T, C, M, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C, M> DmaTransfer for SpiDmaTransfer<'t, 'd, T, C, M>
|
impl<'t, 'd, T, C, M, DmaMode> DmaTransfer for SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
fn wait(self) -> Result<(), DmaError> {
|
fn wait(self) -> Result<(), DmaError> {
|
||||||
@ -931,12 +958,13 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C, M> Drop for SpiDmaTransfer<'t, 'd, T, C, M>
|
impl<'t, 'd, T, C, M, DmaMode> Drop for SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.spi_dma.spi.flush().ok();
|
self.spi_dma.spi.flush().ok();
|
||||||
@ -944,46 +972,91 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A DMA capable SPI instance.
|
/// A DMA capable SPI instance.
|
||||||
pub struct SpiDma<'d, T, C, M>
|
pub struct SpiDma<'d, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub(crate) spi: PeripheralRef<'d, T>,
|
pub(crate) spi: PeripheralRef<'d, T>,
|
||||||
pub(crate) channel: Channel<'d, C>,
|
pub(crate) channel: Channel<'d, C, DmaMode>,
|
||||||
_mode: PhantomData<M>,
|
_mode: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, C, M> core::fmt::Debug for SpiDma<'d, T, C, M>
|
impl<'d, T, C, M, DmaMode> core::fmt::Debug for SpiDma<'d, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("SpiDma").finish()
|
f.debug_struct("SpiDma").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, C, M> SpiDma<'d, T, C, M>
|
impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: DuplexMode,
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
|
{
|
||||||
|
/// Sets the interrupt handler, enables it with
|
||||||
|
/// [crate::interrupt::Priority::min()]
|
||||||
|
///
|
||||||
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
|
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
self.spi.set_interrupt_handler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Listen for the given interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
pub fn listen(&mut self, interrupts: EnumSet<SpiInterrupt>) {
|
||||||
|
self.spi.listen(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlisten the given interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
pub fn unlisten(&mut self, interrupts: EnumSet<SpiInterrupt>) {
|
||||||
|
self.spi.unlisten(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets asserted interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
pub fn interrupts(&mut self) -> EnumSet<SpiInterrupt> {
|
||||||
|
self.spi.interrupts()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets asserted interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
pub fn clear_interrupts(&mut self, interrupts: EnumSet<SpiInterrupt>) {
|
||||||
|
self.spi.clear_interrupts(interrupts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode>
|
||||||
|
where
|
||||||
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
|
C: ChannelTypes,
|
||||||
|
C::P: SpiPeripheral,
|
||||||
|
M: DuplexMode,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub fn change_bus_frequency(&mut self, frequency: HertzU32, clocks: &Clocks) {
|
pub fn change_bus_frequency(&mut self, frequency: HertzU32, clocks: &Clocks) {
|
||||||
self.spi.ch_bus_freq(frequency, clocks);
|
self.spi.ch_bus_freq(frequency, clocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, C, M> SpiDma<'d, T, C, M>
|
impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: IsFullDuplex,
|
M: IsFullDuplex,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Perform a DMA write.
|
/// Perform a DMA write.
|
||||||
///
|
///
|
||||||
@ -994,7 +1067,7 @@ pub mod dma {
|
|||||||
pub fn dma_write<'t, TXBUF>(
|
pub fn dma_write<'t, TXBUF>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
|
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -1018,7 +1091,7 @@ pub mod dma {
|
|||||||
pub fn dma_read<'t, RXBUF>(
|
pub fn dma_read<'t, RXBUF>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
|
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -1042,7 +1115,7 @@ pub mod dma {
|
|||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
read_buffer: &'t mut RXBUF,
|
read_buffer: &'t mut RXBUF,
|
||||||
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, M>, super::Error>
|
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>, super::Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
@ -1067,12 +1140,13 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, C, M> SpiDma<'d, T, C, M>
|
impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: IsHalfDuplex,
|
M: IsHalfDuplex,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
|
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
|
||||||
pub fn read<'t, RXBUF>(
|
pub fn read<'t, RXBUF>(
|
||||||
@ -1082,7 +1156,7 @@ pub mod dma {
|
|||||||
address: Address,
|
address: Address,
|
||||||
dummy: u8,
|
dummy: u8,
|
||||||
buffer: &'t mut RXBUF,
|
buffer: &'t mut RXBUF,
|
||||||
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
|
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -1153,7 +1227,7 @@ pub mod dma {
|
|||||||
address: Address,
|
address: Address,
|
||||||
dummy: u8,
|
dummy: u8,
|
||||||
buffer: &'t TXBUF,
|
buffer: &'t TXBUF,
|
||||||
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
|
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -1218,12 +1292,14 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-02")]
|
#[cfg(feature = "embedded-hal-02")]
|
||||||
impl<'d, T, C, M> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDma<'d, T, C, M>
|
impl<'d, T, C, M, DmaMode> embedded_hal_02::blocking::spi::Transfer<u8>
|
||||||
|
for SpiDma<'d, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: IsFullDuplex,
|
M: IsFullDuplex,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
type Error = super::Error;
|
type Error = super::Error;
|
||||||
|
|
||||||
@ -1234,12 +1310,14 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-02")]
|
#[cfg(feature = "embedded-hal-02")]
|
||||||
impl<'d, T, C, M> embedded_hal_02::blocking::spi::Write<u8> for SpiDma<'d, T, C, M>
|
impl<'d, T, C, M, DmaMode> embedded_hal_02::blocking::spi::Write<u8>
|
||||||
|
for SpiDma<'d, T, C, M, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
M: IsFullDuplex,
|
M: IsFullDuplex,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
type Error = super::Error;
|
type Error = super::Error;
|
||||||
|
|
||||||
@ -1308,7 +1386,7 @@ pub mod dma {
|
|||||||
mod asynch {
|
mod asynch {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<'d, T, C, M> embedded_hal_async::spi::SpiBus for SpiDma<'d, T, C, M>
|
impl<'d, T, C, M> embedded_hal_async::spi::SpiBus for SpiDma<'d, T, C, M, crate::Async>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
@ -1468,7 +1546,7 @@ pub mod dma {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<'d, T, C, M> ErrorType for SpiDma<'d, T, C, M>
|
impl<'d, T, C, M> ErrorType for SpiDma<'d, T, C, M, crate::Async>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
@ -1478,7 +1556,7 @@ pub mod dma {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, C, M> SpiBus for SpiDma<'d, T, C, M>
|
impl<'d, T, C, M> SpiBus for SpiDma<'d, T, C, M, crate::Async>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
@ -2361,6 +2439,72 @@ pub trait Instance: crate::private::Sealed {
|
|||||||
.write(|w| unsafe { w.bits(reg_val) });
|
.write(|w| unsafe { w.bits(reg_val) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the interrupt handler
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler);
|
||||||
|
|
||||||
|
/// Listen for the given interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
fn listen(&mut self, interrupts: EnumSet<SpiInterrupt>) {
|
||||||
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
SpiInterrupt::TransDone => {
|
||||||
|
reg_block
|
||||||
|
.dma_int_ena()
|
||||||
|
.modify(|_, w| w.trans_done_int_ena().set_bit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlisten the given interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
fn unlisten(&mut self, interrupts: EnumSet<SpiInterrupt>) {
|
||||||
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
SpiInterrupt::TransDone => {
|
||||||
|
reg_block
|
||||||
|
.dma_int_ena()
|
||||||
|
.modify(|_, w| w.trans_done_int_ena().clear_bit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets asserted interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
fn interrupts(&mut self) -> EnumSet<SpiInterrupt> {
|
||||||
|
let mut res = EnumSet::new();
|
||||||
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
|
let ints = reg_block.dma_int_st().read();
|
||||||
|
|
||||||
|
if ints.trans_done_int_st().bit() {
|
||||||
|
res.insert(SpiInterrupt::TransDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resets asserted interrupts
|
||||||
|
#[cfg(not(any(esp32, esp32s2)))]
|
||||||
|
fn clear_interrupts(&mut self, interrupts: EnumSet<SpiInterrupt>) {
|
||||||
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
|
for interrupt in interrupts {
|
||||||
|
match interrupt {
|
||||||
|
SpiInterrupt::TransDone => {
|
||||||
|
reg_block
|
||||||
|
.dma_int_clr()
|
||||||
|
.write(|w| w.trans_done_int_clr().set_bit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
fn set_data_mode(&mut self, data_mode: SpiMode) -> &mut Self {
|
fn set_data_mode(&mut self, data_mode: SpiMode) -> &mut Self {
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
@ -2837,6 +2981,12 @@ impl Instance for crate::peripherals::SPI2 {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
self.bind_spi2_interrupt(handler.handler());
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sclk_signal(&self) -> OutputSignal {
|
fn sclk_signal(&self) -> OutputSignal {
|
||||||
OutputSignal::FSPICLK_MUX
|
OutputSignal::FSPICLK_MUX
|
||||||
@ -2908,6 +3058,12 @@ impl Instance for crate::peripherals::SPI2 {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
self.bind_spi2_interrupt(handler.handler());
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sclk_signal(&self) -> OutputSignal {
|
fn sclk_signal(&self) -> OutputSignal {
|
||||||
OutputSignal::HSPICLK
|
OutputSignal::HSPICLK
|
||||||
@ -2973,6 +3129,12 @@ impl Instance for crate::peripherals::SPI3 {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
self.bind_spi3_interrupt(handler.handler());
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sclk_signal(&self) -> OutputSignal {
|
fn sclk_signal(&self) -> OutputSignal {
|
||||||
OutputSignal::VSPICLK
|
OutputSignal::VSPICLK
|
||||||
@ -3011,6 +3173,12 @@ impl Instance for crate::peripherals::SPI2 {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
self.bind_spi2_interrupt(handler.handler());
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sclk_signal(&self) -> OutputSignal {
|
fn sclk_signal(&self) -> OutputSignal {
|
||||||
OutputSignal::FSPICLK
|
OutputSignal::FSPICLK
|
||||||
@ -3082,6 +3250,12 @@ impl Instance for crate::peripherals::SPI3 {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
self.bind_spi3_interrupt(handler.handler());
|
||||||
|
crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sclk_signal(&self) -> OutputSignal {
|
fn sclk_signal(&self) -> OutputSignal {
|
||||||
OutputSignal::SPI3_CLK
|
OutputSignal::SPI3_CLK
|
||||||
|
|||||||
@ -142,41 +142,57 @@ pub mod dma {
|
|||||||
use super::*;
|
use super::*;
|
||||||
#[cfg(spi3)]
|
#[cfg(spi3)]
|
||||||
use crate::dma::Spi3Peripheral;
|
use crate::dma::Spi3Peripheral;
|
||||||
use crate::dma::{
|
use crate::{
|
||||||
Channel,
|
dma::{
|
||||||
ChannelTypes,
|
Channel,
|
||||||
DmaError,
|
ChannelTypes,
|
||||||
DmaTransfer,
|
DmaError,
|
||||||
DmaTransferRxTx,
|
DmaTransfer,
|
||||||
RxPrivate,
|
DmaTransferRxTx,
|
||||||
Spi2Peripheral,
|
RxPrivate,
|
||||||
SpiPeripheral,
|
Spi2Peripheral,
|
||||||
TxPrivate,
|
SpiPeripheral,
|
||||||
|
TxPrivate,
|
||||||
|
},
|
||||||
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait WithDmaSpi2<'d, C>
|
pub trait WithDmaSpi2<'d, C, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI2, C>;
|
fn with_dma(
|
||||||
|
self,
|
||||||
|
channel: Channel<'d, C, DmaMode>,
|
||||||
|
) -> SpiDma<'d, crate::peripherals::SPI2, C, DmaMode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(spi3)]
|
#[cfg(spi3)]
|
||||||
pub trait WithDmaSpi3<'d, C>
|
pub trait WithDmaSpi3<'d, C, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI3, C>;
|
fn with_dma(
|
||||||
|
self,
|
||||||
|
channel: Channel<'d, C, DmaMode>,
|
||||||
|
) -> SpiDma<'d, crate::peripherals::SPI3, C, DmaMode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, C> WithDmaSpi2<'d, C> for Spi<'d, crate::peripherals::SPI2, FullDuplexMode>
|
impl<'d, C, DmaMode> WithDmaSpi2<'d, C, DmaMode>
|
||||||
|
for Spi<'d, crate::peripherals::SPI2, FullDuplexMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral + Spi2Peripheral,
|
C::P: SpiPeripheral + Spi2Peripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(self, mut channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI2, C> {
|
fn with_dma(
|
||||||
|
self,
|
||||||
|
mut channel: Channel<'d, C, DmaMode>,
|
||||||
|
) -> SpiDma<'d, crate::peripherals::SPI2, C, DmaMode> {
|
||||||
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
||||||
|
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
@ -195,12 +211,17 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(spi3)]
|
#[cfg(spi3)]
|
||||||
impl<'d, C> WithDmaSpi3<'d, C> for Spi<'d, crate::peripherals::SPI3, FullDuplexMode>
|
impl<'d, C, DmaMode> WithDmaSpi3<'d, C, DmaMode>
|
||||||
|
for Spi<'d, crate::peripherals::SPI3, FullDuplexMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral + Spi3Peripheral,
|
C::P: SpiPeripheral + Spi3Peripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn with_dma(self, mut channel: Channel<'d, C>) -> SpiDma<'d, crate::peripherals::SPI3, C> {
|
fn with_dma(
|
||||||
|
self,
|
||||||
|
mut channel: Channel<'d, C, DmaMode>,
|
||||||
|
) -> SpiDma<'d, crate::peripherals::SPI3, C, DmaMode> {
|
||||||
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
channel.tx.init_channel(); // no need to call this for both, TX and RX
|
||||||
|
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
@ -219,20 +240,22 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
/// An in-progress DMA transfer
|
/// An in-progress DMA transfer
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct SpiDmaTransferRxTx<'t, 'd, T, C>
|
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
spi_dma: &'t mut SpiDma<'d, T, C>,
|
spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C>
|
impl<'t, 'd, T, C, DmaMode> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
fn wait(self) -> Result<(), DmaError> {
|
fn wait(self) -> Result<(), DmaError> {
|
||||||
@ -255,11 +278,12 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C> Drop for SpiDmaTransferRxTx<'t, 'd, T, C>
|
impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
while !self.is_done() {}
|
while !self.is_done() {}
|
||||||
@ -269,20 +293,22 @@ pub mod dma {
|
|||||||
|
|
||||||
/// An in-progress DMA transfer.
|
/// An in-progress DMA transfer.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct SpiDmaTransferRx<'t, 'd, T, C>
|
pub struct SpiDmaTransferRx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
spi_dma: &'t mut SpiDma<'d, T, C>,
|
spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C> DmaTransfer for SpiDmaTransferRx<'t, 'd, T, C>
|
impl<'t, 'd, T, C, DmaMode> DmaTransfer for SpiDmaTransferRx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
fn wait(self) -> Result<(), DmaError> {
|
fn wait(self) -> Result<(), DmaError> {
|
||||||
@ -303,11 +329,12 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C> Drop for SpiDmaTransferRx<'t, 'd, T, C>
|
impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferRx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
while !self.is_done() {}
|
while !self.is_done() {}
|
||||||
@ -318,20 +345,22 @@ pub mod dma {
|
|||||||
|
|
||||||
/// An in-progress DMA transfer.
|
/// An in-progress DMA transfer.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct SpiDmaTransferTx<'t, 'd, T, C>
|
pub struct SpiDmaTransferTx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
spi_dma: &'t mut SpiDma<'d, T, C>,
|
spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C> DmaTransfer for SpiDmaTransferTx<'t, 'd, T, C>
|
impl<'t, 'd, T, C, DmaMode> DmaTransfer for SpiDmaTransferTx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Wait for the DMA transfer to complete
|
/// Wait for the DMA transfer to complete
|
||||||
fn wait(self) -> Result<(), DmaError> {
|
fn wait(self) -> Result<(), DmaError> {
|
||||||
@ -354,11 +383,12 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, 'd, T, C> Drop for SpiDmaTransferTx<'t, 'd, T, C>
|
impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferTx<'t, 'd, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
while !self.is_done() {}
|
while !self.is_done() {}
|
||||||
@ -368,30 +398,33 @@ pub mod dma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A DMA capable SPI instance.
|
/// A DMA capable SPI instance.
|
||||||
pub struct SpiDma<'d, T, C>
|
pub struct SpiDma<'d, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
pub(crate) spi: PeripheralRef<'d, T>,
|
pub(crate) spi: PeripheralRef<'d, T>,
|
||||||
pub(crate) channel: Channel<'d, C>,
|
pub(crate) channel: Channel<'d, C, DmaMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, C> core::fmt::Debug for SpiDma<'d, T, C>
|
impl<'d, T, C, DmaMode> core::fmt::Debug for SpiDma<'d, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("SpiDma").finish()
|
f.debug_struct("SpiDma").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, C> SpiDma<'d, T, C>
|
impl<'d, T, C, DmaMode> SpiDma<'d, T, C, DmaMode>
|
||||||
where
|
where
|
||||||
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
|
||||||
C: ChannelTypes,
|
C: ChannelTypes,
|
||||||
C::P: SpiPeripheral,
|
C::P: SpiPeripheral,
|
||||||
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
/// Register a buffer for a DMA write.
|
/// Register a buffer for a DMA write.
|
||||||
///
|
///
|
||||||
@ -403,7 +436,7 @@ pub mod dma {
|
|||||||
pub fn dma_write<'t, TXBUF>(
|
pub fn dma_write<'t, TXBUF>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
) -> Result<SpiDmaTransferTx<'t, 'd, T, C>, Error>
|
) -> Result<SpiDmaTransferTx<'t, 'd, T, C, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -428,7 +461,7 @@ pub mod dma {
|
|||||||
pub fn dma_read<'t, RXBUF>(
|
pub fn dma_read<'t, RXBUF>(
|
||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t mut RXBUF,
|
words: &'t mut RXBUF,
|
||||||
) -> Result<SpiDmaTransferRx<'t, 'd, T, C>, Error>
|
) -> Result<SpiDmaTransferRx<'t, 'd, T, C, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
{
|
{
|
||||||
@ -455,7 +488,7 @@ pub mod dma {
|
|||||||
&'t mut self,
|
&'t mut self,
|
||||||
words: &'t TXBUF,
|
words: &'t TXBUF,
|
||||||
read_buffer: &'t mut RXBUF,
|
read_buffer: &'t mut RXBUF,
|
||||||
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C>, Error>
|
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>, Error>
|
||||||
where
|
where
|
||||||
TXBUF: ReadBuffer<Word = u8>,
|
TXBUF: ReadBuffer<Word = u8>,
|
||||||
RXBUF: WriteBuffer<Word = u8>,
|
RXBUF: WriteBuffer<Word = u8>,
|
||||||
|
|||||||
@ -57,8 +57,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
peripherals.I2S0,
|
peripherals.I2S0,
|
||||||
Standard::Philips,
|
Standard::Philips,
|
||||||
DataFormat::Data16Channel16,
|
DataFormat::Data16Channel16,
|
||||||
44100.Hz(),
|
44100u32.Hz(),
|
||||||
dma_channel.configure(
|
dma_channel.configure_for_async(
|
||||||
false,
|
false,
|
||||||
&mut tx_descriptors,
|
&mut tx_descriptors,
|
||||||
&mut rx_descriptors,
|
&mut rx_descriptors,
|
||||||
|
|||||||
@ -80,8 +80,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
peripherals.I2S0,
|
peripherals.I2S0,
|
||||||
Standard::Philips,
|
Standard::Philips,
|
||||||
DataFormat::Data16Channel16,
|
DataFormat::Data16Channel16,
|
||||||
44100.Hz(),
|
44100u32.Hz(),
|
||||||
dma_channel.configure(
|
dma_channel.configure_for_async(
|
||||||
false,
|
false,
|
||||||
&mut tx_descriptors,
|
&mut tx_descriptors,
|
||||||
&mut rx_descriptors,
|
&mut rx_descriptors,
|
||||||
|
|||||||
@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let parl_io = ParlIoRxOnly::new(
|
let parl_io = ParlIoRxOnly::new(
|
||||||
peripherals.PARL_IO,
|
peripherals.PARL_IO,
|
||||||
dma_channel.configure(
|
dma_channel.configure_for_async(
|
||||||
false,
|
false,
|
||||||
&mut tx_descriptors,
|
&mut tx_descriptors,
|
||||||
&mut rx_descriptors,
|
&mut rx_descriptors,
|
||||||
|
|||||||
@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let parl_io = ParlIoTxOnly::new(
|
let parl_io = ParlIoTxOnly::new(
|
||||||
peripherals.PARL_IO,
|
peripherals.PARL_IO,
|
||||||
dma_channel.configure(
|
dma_channel.configure_for_async(
|
||||||
false,
|
false,
|
||||||
&mut tx_descriptors,
|
&mut tx_descriptors,
|
||||||
&mut rx_descriptors,
|
&mut rx_descriptors,
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
//!
|
//!
|
||||||
//! Folowing pins are used:
|
//! Folowing pins are used:
|
||||||
//! SCLK GPIO0
|
//! SCLK GPIO0
|
||||||
//! MISO GPIO1
|
//! MISO GPIO2
|
||||||
//! MOSI GPIO2
|
//! MOSI GPIO4
|
||||||
//! CS GPIO3
|
//! CS GPIO5
|
||||||
//!
|
//!
|
||||||
//! Depending on your target and the board you are using you have to change the
|
//! Depending on your target and the board you are using you have to change the
|
||||||
//! pins.
|
//! pins.
|
||||||
@ -51,9 +51,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
let sclk = io.pins.gpio0;
|
let sclk = io.pins.gpio0;
|
||||||
let miso = io.pins.gpio1;
|
let miso = io.pins.gpio2;
|
||||||
let mosi = io.pins.gpio2;
|
let mosi = io.pins.gpio4;
|
||||||
let cs = io.pins.gpio3;
|
let cs = io.pins.gpio5;
|
||||||
|
|
||||||
let dma = Dma::new(peripherals.DMA);
|
let dma = Dma::new(peripherals.DMA);
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0, &clocks)
|
let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0, &clocks)
|
||||||
.with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs))
|
.with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs))
|
||||||
.with_dma(dma_channel.configure(
|
.with_dma(dma_channel.configure_for_async(
|
||||||
false,
|
false,
|
||||||
&mut descriptors,
|
&mut descriptors,
|
||||||
&mut rx_descriptors,
|
&mut rx_descriptors,
|
||||||
@ -80,7 +80,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
embedded_hal_async::spi::SpiBus::transfer(&mut spi, &mut buffer, &send_buffer)
|
embedded_hal_async::spi::SpiBus::transfer(&mut spi, &mut buffer, &send_buffer)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
esp_println::println!("Bytes recieved: {:?}", buffer);
|
esp_println::println!("Bytes received: {:?}", buffer);
|
||||||
Timer::after(Duration::from_millis(5_000)).await;
|
Timer::after(Duration::from_millis(5_000)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user