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