[DMA 4/8]: Apply Peripheral pattern (#2526)

* Create DMA Channels inside peripherals

* Add PARL_IO into_async functions

* Update tests and examples

* Restore configurable priority via DmaChannel

* Add mode param to DPI driver

* Fix test by raising SPI frequency

* Fix split

* Changelog

* Update esp-hal/CHANGELOG.md

Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>

---------

Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>
This commit is contained in:
Dániel Buga 2024-11-22 10:05:22 +01:00 committed by GitHub
parent f81b5f6c7f
commit 3a4a7632b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 815 additions and 639 deletions

View File

@ -10,15 +10,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- ESP32-S3: Added SDMMC signals (#2556) - ESP32-S3: Added SDMMC signals (#2556)
- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403) - Added `set_priority` to the `DmaChannel` trait on GDMA devices (#2403, #2526)
- Added `into_async` and `into_blocking` functions for `ParlIoTxOnly`, `ParlIoRxOnly` (#2526)
- ESP32-C6, H2, S3: Added `split` function to the `DmaChannel` trait. (#2526)
### Changed ### Changed
- DMA channel objects now implement `Peripheral` (#2526)
- DMA channel objects are no longer wrapped in `Channel`. The `Channel` drivers are now managed by DMA enabled peripheral drivers. (#2526)
- The `Dpi` driver and `DpiTransfer` now have a `Mode` type parameter. The driver's asyncness is determined by the asyncness of the `Lcd` used to create it. (#2526)
### Fixed ### Fixed
### Removed ### Removed
- The `configure` and `configure_for_async` DMA channel functions has been removed (#2403) - The `configure` and `configure_for_async` DMA channel functions has been removed (#2403)
- The DMA channel objects no longer have `tx` and `rx` fields. (#2526)
## [0.22.0] - 2024-11-20 ## [0.22.0] - 2024-11-20

View File

@ -15,3 +15,14 @@
-.with_dma(dma_channel.configure(false, DmaPriority::Priority0)); -.with_dma(dma_channel.configure(false, DmaPriority::Priority0));
+.with_dma(dma_channel); +.with_dma(dma_channel);
``` ```
```diff
+dma_channel.set_priority(DmaPriority::Priority1);
let mut spi = Spi::new_with_config(
peripherals.SPI2,
Config::default(),
)
// other setup
-.with_dma(dma_channel.configure(false, DmaPriority::Priority1));
+.with_dma(dma_channel);
```

View File

@ -242,15 +242,18 @@ pub mod dma {
ChannelTx, ChannelTx,
DescriptorChain, DescriptorChain,
DmaChannelConvert, DmaChannelConvert,
DmaChannelFor,
DmaDescriptor, DmaDescriptor,
DmaEligible,
DmaPeripheral, DmaPeripheral,
DmaTransferRxTx, DmaTransferRxTx,
ReadBuffer, ReadBuffer,
Rx, Rx,
RxChannelFor,
Tx, Tx,
TxChannelFor,
WriteBuffer, WriteBuffer,
}, },
peripheral::Peripheral,
peripherals::AES, peripherals::AES,
Blocking, Blocking,
}; };
@ -278,7 +281,7 @@ pub mod dma {
/// The underlying [`Aes`](super::Aes) driver /// The underlying [`Aes`](super::Aes) driver
pub aes: super::Aes<'d>, pub aes: super::Aes<'d>,
channel: Channel<'d, Blocking, <AES as DmaEligible>::Dma>, channel: Channel<'d, Blocking, DmaChannelFor<AES>>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
} }
@ -287,16 +290,18 @@ pub mod dma {
/// Enable DMA for the current instance of the AES driver /// Enable DMA for the current instance of the AES driver
pub fn with_dma<CH>( pub fn with_dma<CH>(
self, self,
channel: Channel<'d, Blocking, CH>, channel: impl Peripheral<P = CH> + 'd,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> AesDma<'d> ) -> AesDma<'d>
where where
CH: DmaChannelConvert<<AES as DmaEligible>::Dma>, CH: DmaChannelConvert<DmaChannelFor<AES>>,
{ {
let channel = Channel::new(channel.map(|ch| ch.degrade()));
channel.runtime_ensure_compatible(&self.aes);
AesDma { AesDma {
aes: self, aes: self,
channel: channel.degrade(), channel,
rx_chain: DescriptorChain::new(rx_descriptors), rx_chain: DescriptorChain::new(rx_descriptors),
tx_chain: DescriptorChain::new(tx_descriptors), tx_chain: DescriptorChain::new(tx_descriptors),
} }
@ -326,7 +331,7 @@ pub mod dma {
} }
impl<'d> DmaSupportTx for AesDma<'d> { impl<'d> DmaSupportTx for AesDma<'d> {
type TX = ChannelTx<'d, Blocking, <AES as DmaEligible>::Dma>; type TX = ChannelTx<'d, Blocking, TxChannelFor<AES>>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx &mut self.channel.tx
@ -338,7 +343,7 @@ pub mod dma {
} }
impl<'d> DmaSupportRx for AesDma<'d> { impl<'d> DmaSupportRx for AesDma<'d> {
type RX = ChannelRx<'d, Blocking, <AES as DmaEligible>::Dma>; type RX = ChannelRx<'d, Blocking, RxChannelFor<AES>>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx &mut self.channel.rx

View File

@ -16,105 +16,58 @@
use crate::{ use crate::{
dma::*, dma::*,
peripheral::PeripheralRef, peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt, peripherals::Interrupt,
system::{Peripheral, PeripheralClockControl}, system::{self, PeripheralClockControl},
Blocking,
}; };
#[doc(hidden)] /// An arbitrary GDMA channel
pub trait GdmaChannel { pub struct AnyGdmaChannel(u8);
fn number(&self) -> u8;
fn async_handler_out(&self) -> Option<InterruptHandler> { impl Peripheral for AnyGdmaChannel {
match self.number() { type P = Self;
0 => DmaChannel0::handler_out(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::handler_out(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::handler_out(),
#[cfg(esp32s3)]
3 => DmaChannel3::handler_out(),
#[cfg(esp32s3)]
4 => DmaChannel4::handler_out(),
_ => unreachable!(),
}
}
fn peripheral_interrupt_out(&self) -> Option<Interrupt> { unsafe fn clone_unchecked(&self) -> Self::P {
match self.number() { Self(self.0)
0 => DmaChannel0::isr_out(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::isr_out(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::isr_out(),
#[cfg(esp32s3)]
3 => DmaChannel3::isr_out(),
#[cfg(esp32s3)]
4 => DmaChannel4::isr_out(),
_ => unreachable!(),
}
}
fn async_handler_in(&self) -> Option<InterruptHandler> {
match self.number() {
0 => DmaChannel0::handler_in(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::handler_in(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::handler_in(),
#[cfg(esp32s3)]
3 => DmaChannel3::handler_in(),
#[cfg(esp32s3)]
4 => DmaChannel4::handler_in(),
_ => unreachable!(),
}
}
fn peripheral_interrupt_in(&self) -> Option<Interrupt> {
match self.number() {
0 => DmaChannel0::isr_in(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::isr_in(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::isr_in(),
#[cfg(esp32s3)]
3 => DmaChannel3::isr_in(),
#[cfg(esp32s3)]
4 => DmaChannel4::isr_in(),
_ => unreachable!(),
}
} }
} }
/// An arbitrary GDMA channel
#[non_exhaustive]
pub struct AnyGdmaChannel(u8);
impl crate::private::Sealed for AnyGdmaChannel {} impl crate::private::Sealed for AnyGdmaChannel {}
impl DmaChannel for AnyGdmaChannel { impl DmaChannel for AnyGdmaChannel {
type Rx = ChannelRxImpl<Self>; type Rx = AnyGdmaRxChannel;
type Tx = ChannelTxImpl<Self>; type Tx = AnyGdmaTxChannel;
}
#[non_exhaustive] fn set_priority(&self, priority: DmaPriority) {
#[doc(hidden)] AnyGdmaRxChannel(self.0).set_priority(priority);
pub struct SpecificGdmaChannel<const N: u8> {} AnyGdmaTxChannel(self.0).set_priority(priority);
impl GdmaChannel for AnyGdmaChannel {
fn number(&self) -> u8 {
self.0
} }
}
impl<const N: u8> GdmaChannel for SpecificGdmaChannel<N> { unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
fn number(&self) -> u8 { (AnyGdmaRxChannel(self.0), AnyGdmaTxChannel(self.0))
N
} }
} }
#[non_exhaustive] /// An arbitrary GDMA RX channel
#[doc(hidden)] pub struct AnyGdmaRxChannel(u8);
pub struct ChannelTxImpl<C: GdmaChannel>(C);
impl Peripheral for AnyGdmaRxChannel {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self(self.0)
}
}
/// An arbitrary GDMA TX channel
pub struct AnyGdmaTxChannel(u8);
impl Peripheral for AnyGdmaTxChannel {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self(self.0)
}
}
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
@ -129,40 +82,37 @@ cfg_if::cfg_if! {
} }
} }
impl<C: GdmaChannel> crate::private::Sealed for ChannelTxImpl<C> {} impl crate::private::Sealed for AnyGdmaTxChannel {}
impl DmaTxChannel for AnyGdmaTxChannel {}
impl<C: GdmaChannel> ChannelTxImpl<C> { impl AnyGdmaTxChannel {
#[inline(always)] #[inline(always)]
fn ch(&self) -> &crate::peripherals::dma::ch::CH { fn ch(&self) -> &crate::peripherals::dma::ch::CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize) dma.ch(self.0 as usize)
} }
#[cfg(any(esp32c2, esp32c3))] #[cfg(any(esp32c2, esp32c3))]
#[inline(always)] #[inline(always)]
fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH { fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.int_ch(self.0.number() as usize) dma.int_ch(self.0 as usize)
} }
#[inline(always)] #[inline(always)]
#[cfg(any(esp32c6, esp32h2))] #[cfg(any(esp32c6, esp32h2))]
fn int(&self) -> &crate::peripherals::dma::out_int_ch::OUT_INT_CH { fn int(&self) -> &crate::peripherals::dma::out_int_ch::OUT_INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.out_int_ch(self.0.number() as usize) dma.out_int_ch(self.0 as usize)
} }
#[cfg(esp32s3)] #[cfg(esp32s3)]
#[inline(always)] #[inline(always)]
fn int(&self) -> &crate::peripherals::dma::ch::out_int::OUT_INT { fn int(&self) -> &crate::peripherals::dma::ch::out_int::OUT_INT {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize).out_int() dma.ch(self.0 as usize).out_int()
}
fn degrade(self) -> ChannelTxImpl<AnyGdmaChannel> {
ChannelTxImpl(AnyGdmaChannel(self.0.number()))
} }
} }
impl<C: GdmaChannel> RegisterAccess for ChannelTxImpl<C> { impl RegisterAccess for AnyGdmaTxChannel {
fn reset(&self) { fn reset(&self) {
let conf0 = self.ch().out_conf0(); let conf0 = self.ch().out_conf0();
conf0.modify(|_, w| w.out_rst().set_bit()); conf0.modify(|_, w| w.out_rst().set_bit());
@ -231,7 +181,7 @@ impl<C: GdmaChannel> RegisterAccess for ChannelTxImpl<C> {
} }
} }
impl<C: GdmaChannel> TxRegisterAccess for ChannelTxImpl<C> { impl TxRegisterAccess for AnyGdmaTxChannel {
fn set_auto_write_back(&self, enable: bool) { fn set_auto_write_back(&self, enable: bool) {
self.ch() self.ch()
.out_conf0() .out_conf0()
@ -247,15 +197,37 @@ impl<C: GdmaChannel> TxRegisterAccess for ChannelTxImpl<C> {
} }
fn async_handler(&self) -> Option<InterruptHandler> { fn async_handler(&self) -> Option<InterruptHandler> {
self.0.async_handler_out() match self.0 {
0 => DmaChannel0::handler_out(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::handler_out(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::handler_out(),
#[cfg(esp32s3)]
3 => DmaChannel3::handler_out(),
#[cfg(esp32s3)]
4 => DmaChannel4::handler_out(),
_ => unreachable!(),
}
} }
fn peripheral_interrupt(&self) -> Option<Interrupt> { fn peripheral_interrupt(&self) -> Option<Interrupt> {
self.0.peripheral_interrupt_out() match self.0 {
0 => DmaChannel0::isr_out(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::isr_out(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::isr_out(),
#[cfg(esp32s3)]
3 => DmaChannel3::isr_out(),
#[cfg(esp32s3)]
4 => DmaChannel4::isr_out(),
_ => unreachable!(),
}
} }
} }
impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> { impl InterruptAccess<DmaTxInterrupt> for AnyGdmaTxChannel {
fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) { fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
self.int().ena().modify(|_, w| { self.int().ena().modify(|_, w| {
for interrupt in interrupts { for interrupt in interrupts {
@ -325,13 +297,13 @@ impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
} }
fn waker(&self) -> &'static AtomicWaker { fn waker(&self) -> &'static AtomicWaker {
&TX_WAKERS[self.0.number() as usize] &TX_WAKERS[self.0 as usize]
} }
fn is_async(&self) -> bool { fn is_async(&self) -> bool {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3))] { if #[cfg(any(esp32c2, esp32c3))] {
TX_IS_ASYNC[self.0.number() as usize].load(portable_atomic::Ordering::Acquire) TX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire)
} else { } else {
true true
} }
@ -341,52 +313,45 @@ impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
fn set_async(&self, _is_async: bool) { fn set_async(&self, _is_async: bool) {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3))] { if #[cfg(any(esp32c2, esp32c3))] {
TX_IS_ASYNC[self.0.number() as usize].store(_is_async, portable_atomic::Ordering::Release); TX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release);
} }
} }
} }
} }
#[non_exhaustive] impl crate::private::Sealed for AnyGdmaRxChannel {}
#[doc(hidden)] impl DmaRxChannel for AnyGdmaRxChannel {}
pub struct ChannelRxImpl<C: GdmaChannel>(C);
impl<C: GdmaChannel> crate::private::Sealed for ChannelRxImpl<C> {} impl AnyGdmaRxChannel {
impl<C: GdmaChannel> ChannelRxImpl<C> {
#[inline(always)] #[inline(always)]
fn ch(&self) -> &crate::peripherals::dma::ch::CH { fn ch(&self) -> &crate::peripherals::dma::ch::CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize) dma.ch(self.0 as usize)
} }
#[cfg(any(esp32c2, esp32c3))] #[cfg(any(esp32c2, esp32c3))]
#[inline(always)] #[inline(always)]
fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH { fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.int_ch(self.0.number() as usize) dma.int_ch(self.0 as usize)
} }
#[inline(always)] #[inline(always)]
#[cfg(any(esp32c6, esp32h2))] #[cfg(any(esp32c6, esp32h2))]
fn int(&self) -> &crate::peripherals::dma::in_int_ch::IN_INT_CH { fn int(&self) -> &crate::peripherals::dma::in_int_ch::IN_INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.in_int_ch(self.0.number() as usize) dma.in_int_ch(self.0 as usize)
} }
#[cfg(esp32s3)] #[cfg(esp32s3)]
#[inline(always)] #[inline(always)]
fn int(&self) -> &crate::peripherals::dma::ch::in_int::IN_INT { fn int(&self) -> &crate::peripherals::dma::ch::in_int::IN_INT {
let dma = unsafe { &*crate::peripherals::DMA::PTR }; let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize).in_int() dma.ch(self.0 as usize).in_int()
}
fn degrade(self) -> ChannelRxImpl<AnyGdmaChannel> {
ChannelRxImpl(AnyGdmaChannel(self.0.number()))
} }
} }
impl<C: GdmaChannel> RegisterAccess for ChannelRxImpl<C> { impl RegisterAccess for AnyGdmaRxChannel {
fn reset(&self) { fn reset(&self) {
let conf0 = self.ch().in_conf0(); let conf0 = self.ch().in_conf0();
conf0.modify(|_, w| w.in_rst().set_bit()); conf0.modify(|_, w| w.in_rst().set_bit());
@ -453,7 +418,7 @@ impl<C: GdmaChannel> RegisterAccess for ChannelRxImpl<C> {
} }
} }
impl<C: GdmaChannel> RxRegisterAccess for ChannelRxImpl<C> { impl RxRegisterAccess for AnyGdmaRxChannel {
fn set_mem2mem_mode(&self, value: bool) { fn set_mem2mem_mode(&self, value: bool) {
self.ch() self.ch()
.in_conf0() .in_conf0()
@ -461,15 +426,37 @@ impl<C: GdmaChannel> RxRegisterAccess for ChannelRxImpl<C> {
} }
fn async_handler(&self) -> Option<InterruptHandler> { fn async_handler(&self) -> Option<InterruptHandler> {
self.0.async_handler_in() match self.0 {
0 => DmaChannel0::handler_in(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::handler_in(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::handler_in(),
#[cfg(esp32s3)]
3 => DmaChannel3::handler_in(),
#[cfg(esp32s3)]
4 => DmaChannel4::handler_in(),
_ => unreachable!(),
}
} }
fn peripheral_interrupt(&self) -> Option<Interrupt> { fn peripheral_interrupt(&self) -> Option<Interrupt> {
self.0.peripheral_interrupt_in() match self.0 {
0 => DmaChannel0::isr_in(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::isr_in(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::isr_in(),
#[cfg(esp32s3)]
3 => DmaChannel3::isr_in(),
#[cfg(esp32s3)]
4 => DmaChannel4::isr_in(),
_ => unreachable!(),
}
} }
} }
impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> { impl InterruptAccess<DmaRxInterrupt> for AnyGdmaRxChannel {
fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) { fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
self.int().ena().modify(|_, w| { self.int().ena().modify(|_, w| {
for interrupt in interrupts { for interrupt in interrupts {
@ -547,13 +534,13 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
} }
fn waker(&self) -> &'static AtomicWaker { fn waker(&self) -> &'static AtomicWaker {
&RX_WAKERS[self.0.number() as usize] &RX_WAKERS[self.0 as usize]
} }
fn is_async(&self) -> bool { fn is_async(&self) -> bool {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3))] { if #[cfg(any(esp32c2, esp32c3))] {
RX_IS_ASYNC[self.0.number() as usize].load(portable_atomic::Ordering::Acquire) RX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire)
} else { } else {
true true
} }
@ -563,7 +550,7 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
fn set_async(&self, _is_async: bool) { fn set_async(&self, _is_async: bool) {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3))] { if #[cfg(any(esp32c2, esp32c3))] {
RX_IS_ASYNC[self.0.number() as usize].store(_is_async, portable_atomic::Ordering::Release); RX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release);
} }
} }
} }
@ -583,7 +570,26 @@ macro_rules! impl_channel {
#[non_exhaustive] #[non_exhaustive]
pub struct [<DmaChannel $num>] {} pub struct [<DmaChannel $num>] {}
impl crate::private::Sealed for [<DmaChannel $num>] {} impl $crate::private::Sealed for [<DmaChannel $num>] {}
impl Peripheral for [<DmaChannel $num>] {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}
impl [<DmaChannel $num>] {
/// Unsafely constructs a new DMA channel.
///
/// # Safety
///
/// The caller must ensure that only a single instance is used.
pub unsafe fn steal() -> Self {
Self {}
}
}
impl [<DmaChannel $num>] { impl [<DmaChannel $num>] {
fn handler_in() -> Option<InterruptHandler> { fn handler_in() -> Option<InterruptHandler> {
@ -604,44 +610,43 @@ macro_rules! impl_channel {
} }
impl DmaChannel for [<DmaChannel $num>] { impl DmaChannel for [<DmaChannel $num>] {
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>; type Rx = AnyGdmaRxChannel;
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>; type Tx = AnyGdmaTxChannel;
fn set_priority(&self, priority: DmaPriority) {
AnyGdmaChannel($num).set_priority(priority);
}
unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
(AnyGdmaRxChannel($num), AnyGdmaTxChannel($num))
}
} }
impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] { impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
fn degrade_rx(rx: Self::Rx) -> ChannelRxImpl<AnyGdmaChannel> { fn degrade(self) -> AnyGdmaChannel {
rx.degrade() AnyGdmaChannel($num)
} }
fn degrade_tx(tx: Self::Tx) -> ChannelTxImpl<AnyGdmaChannel> { }
tx.degrade()
impl DmaChannelConvert<AnyGdmaRxChannel> for [<DmaChannel $num>] {
fn degrade(self) -> AnyGdmaRxChannel {
AnyGdmaRxChannel($num)
}
}
impl DmaChannelConvert<AnyGdmaTxChannel> for [<DmaChannel $num>] {
fn degrade(self) -> AnyGdmaTxChannel {
AnyGdmaTxChannel($num)
} }
} }
impl DmaChannelExt for [<DmaChannel $num>] { impl DmaChannelExt for [<DmaChannel $num>] {
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> { fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
ChannelRxImpl(SpecificGdmaChannel::<$num> {}) AnyGdmaRxChannel($num)
} }
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> { fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
ChannelTxImpl(SpecificGdmaChannel::<$num> {}) AnyGdmaTxChannel($num)
}
}
impl [<DmaChannel $num>] {
/// Unsafely constructs a new DMA channel.
///
/// # Safety
///
/// The caller must ensure that only a single instance is used.
pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> {
let mut this = Channel {
tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})),
rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})),
};
this.set_priority(DmaPriority::Priority0);
this
} }
} }
} }
@ -737,30 +742,28 @@ crate::impl_dma_eligible! {
pub struct Dma<'d> { pub struct Dma<'d> {
_inner: PeripheralRef<'d, crate::peripherals::DMA>, _inner: PeripheralRef<'d, crate::peripherals::DMA>,
/// Channel 0 /// Channel 0
pub channel0: Channel<'d, Blocking, DmaChannel0>, pub channel0: DmaChannel0,
/// Channel 1 /// Channel 1
#[cfg(not(esp32c2))] #[cfg(not(esp32c2))]
pub channel1: Channel<'d, Blocking, DmaChannel1>, pub channel1: DmaChannel1,
/// Channel 2 /// Channel 2
#[cfg(not(esp32c2))] #[cfg(not(esp32c2))]
pub channel2: Channel<'d, Blocking, DmaChannel2>, pub channel2: DmaChannel2,
/// Channel 3 /// Channel 3
#[cfg(esp32s3)] #[cfg(esp32s3)]
pub channel3: Channel<'d, Blocking, DmaChannel3>, pub channel3: DmaChannel3,
/// Channel 4 /// Channel 4
#[cfg(esp32s3)] #[cfg(esp32s3)]
pub channel4: Channel<'d, Blocking, DmaChannel4>, pub channel4: DmaChannel4,
} }
impl<'d> Dma<'d> { impl<'d> Dma<'d> {
/// Create a DMA instance. /// Create a DMA instance.
pub fn new( pub fn new(dma: impl Peripheral<P = crate::peripherals::DMA> + 'd) -> Dma<'d> {
dma: impl crate::peripheral::Peripheral<P = crate::peripherals::DMA> + 'd,
) -> Dma<'d> {
crate::into_ref!(dma); crate::into_ref!(dma);
if PeripheralClockControl::enable(Peripheral::Gdma) { if PeripheralClockControl::enable(system::Peripheral::Gdma) {
PeripheralClockControl::reset(Peripheral::Gdma); PeripheralClockControl::reset(system::Peripheral::Gdma);
} }
dma.misc_conf().modify(|_, w| w.ahbm_rst_inter().set_bit()); dma.misc_conf().modify(|_, w| w.ahbm_rst_inter().set_bit());
dma.misc_conf() dma.misc_conf()

View File

@ -4,6 +4,7 @@ use crate::{
dma::{ dma::{
dma_private::{DmaSupport, DmaSupportRx}, dma_private::{DmaSupport, DmaSupportRx},
AnyGdmaChannel, AnyGdmaChannel,
AnyGdmaRxChannel,
Channel, Channel,
ChannelRx, ChannelRx,
DescriptorChain, DescriptorChain,
@ -18,6 +19,7 @@ use crate::{
Tx, Tx,
WriteBuffer, WriteBuffer,
}, },
peripheral::Peripheral,
Async, Async,
Blocking, Blocking,
Mode, Mode,
@ -40,16 +42,14 @@ where
impl<'d> Mem2Mem<'d, Blocking> { impl<'d> Mem2Mem<'d, Blocking> {
/// Create a new Mem2Mem instance. /// Create a new Mem2Mem instance.
pub fn new<CH, DM>( pub fn new<CH>(
channel: Channel<'d, DM, CH>, channel: impl Peripheral<P = CH> + 'd,
peripheral: impl DmaEligible, peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Result<Self, DmaError> ) -> Result<Self, DmaError>
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
unsafe { unsafe {
Self::new_unsafe( Self::new_unsafe(
@ -63,8 +63,8 @@ impl<'d> Mem2Mem<'d, Blocking> {
} }
/// Create a new Mem2Mem instance with specific chunk size. /// Create a new Mem2Mem instance with specific chunk size.
pub fn new_with_chunk_size<CH, DM>( pub fn new_with_chunk_size<CH>(
channel: Channel<'d, DM, CH>, channel: impl Peripheral<P = CH> + 'd,
peripheral: impl DmaEligible, peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
@ -72,8 +72,6 @@ impl<'d> Mem2Mem<'d, Blocking> {
) -> Result<Self, DmaError> ) -> Result<Self, DmaError>
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
unsafe { unsafe {
Self::new_unsafe( Self::new_unsafe(
@ -92,8 +90,8 @@ impl<'d> Mem2Mem<'d, Blocking> {
/// ///
/// You must ensure that your not using DMA for the same peripheral and /// You must ensure that your not using DMA for the same peripheral and
/// that your the only one using the DmaPeripheral. /// that your the only one using the DmaPeripheral.
pub unsafe fn new_unsafe<CH, DM>( pub unsafe fn new_unsafe<CH>(
channel: Channel<'d, DM, CH>, channel: impl Peripheral<P = CH> + 'd,
peripheral: DmaPeripheral, peripheral: DmaPeripheral,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
@ -101,8 +99,6 @@ impl<'d> Mem2Mem<'d, Blocking> {
) -> Result<Self, DmaError> ) -> Result<Self, DmaError>
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
if !(1..=4092).contains(&chunk_size) { if !(1..=4092).contains(&chunk_size) {
return Err(DmaError::InvalidChunkSize); return Err(DmaError::InvalidChunkSize);
@ -111,7 +107,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
return Err(DmaError::OutOfDescriptors); return Err(DmaError::OutOfDescriptors);
} }
Ok(Mem2Mem { Ok(Mem2Mem {
channel: Channel::<Blocking, _>::from(channel).degrade(), channel: Channel::new(channel.map(|ch| ch.degrade())),
peripheral, peripheral,
rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size), rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size),
tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size), tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size),
@ -194,7 +190,7 @@ impl<'d, M> DmaSupportRx for Mem2Mem<'d, M>
where where
M: Mode, M: Mode,
{ {
type RX = ChannelRx<'d, M, AnyGdmaChannel>; type RX = ChannelRx<'d, M, AnyGdmaRxChannel>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx &mut self.channel.rx

View File

@ -67,6 +67,7 @@ pub use self::m2m::*;
pub use self::pdma::*; pub use self::pdma::*;
use crate::{ use crate::{
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt, peripherals::Interrupt,
soc::is_slice_in_dram, soc::is_slice_in_dram,
Async, Async,
@ -943,6 +944,13 @@ pub trait DmaEligible {
fn dma_peripheral(&self) -> DmaPeripheral; fn dma_peripheral(&self) -> DmaPeripheral;
} }
/// Helper type to get the DMA (Rx and Tx) channel for a peripheral.
pub type DmaChannelFor<T> = <T as DmaEligible>::Dma;
/// Helper type to get the DMA Rx channel for a peripheral.
pub type RxChannelFor<T> = <DmaChannelFor<T> as DmaChannel>::Rx;
/// Helper type to get the DMA Tx channel for a peripheral.
pub type TxChannelFor<T> = <DmaChannelFor<T> as DmaChannel>::Tx;
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! impl_dma_eligible { macro_rules! impl_dma_eligible {
@ -1585,13 +1593,46 @@ impl RxCircularState {
} }
} }
#[doc(hidden)]
pub trait DmaRxChannel:
RxRegisterAccess + InterruptAccess<DmaRxInterrupt> + Peripheral<P = Self>
{
}
#[doc(hidden)]
pub trait DmaTxChannel:
TxRegisterAccess + InterruptAccess<DmaTxInterrupt> + Peripheral<P = Self>
{
}
/// A description of a DMA Channel. /// A description of a DMA Channel.
pub trait DmaChannel: crate::private::Sealed + Sized { pub trait DmaChannel: Peripheral<P = Self> {
/// A description of the RX half of a DMA Channel. /// A description of the RX half of a DMA Channel.
type Rx: RxRegisterAccess + InterruptAccess<DmaRxInterrupt>; type Rx: DmaRxChannel;
/// A description of the TX half of a DMA Channel. /// A description of the TX half of a DMA Channel.
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>; type Tx: DmaTxChannel;
/// Sets the priority of the DMA channel.
#[cfg(gdma)]
fn set_priority(&self, priority: DmaPriority);
/// Splits the DMA channel into its RX and TX halves.
#[cfg(any(esp32c6, esp32h2, esp32s3))] // TODO relax this to allow splitting on all chips
fn split(self) -> (Self::Rx, Self::Tx) {
// This function is exposed safely on chips that have separate IN and OUT
// interrupt handlers.
// TODO: this includes the P4 as well.
unsafe { self.split_internal(crate::private::Internal) }
}
/// Splits the DMA channel into its RX and TX halves.
///
/// # Safety
///
/// This function must only be used if the separate halves are used by the
/// same peripheral.
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx);
} }
#[doc(hidden)] #[doc(hidden)]
@ -1606,18 +1647,13 @@ pub trait DmaChannelExt: DmaChannel {
note = "Not all channels are useable with all peripherals" note = "Not all channels are useable with all peripherals"
)] )]
#[doc(hidden)] #[doc(hidden)]
pub trait DmaChannelConvert<DEG: DmaChannel>: DmaChannel { pub trait DmaChannelConvert<DEG>: DmaChannel {
fn degrade_rx(rx: Self::Rx) -> DEG::Rx; fn degrade(self) -> DEG;
fn degrade_tx(tx: Self::Tx) -> DEG::Tx;
} }
impl<DEG: DmaChannel> DmaChannelConvert<DEG> for DEG { impl<DEG: DmaChannel> DmaChannelConvert<DEG> for DEG {
fn degrade_rx(rx: Self::Rx) -> DEG::Rx { fn degrade(self) -> DEG {
rx self
}
fn degrade_tx(tx: Self::Tx) -> DEG::Tx {
tx
} }
} }
@ -1683,17 +1719,20 @@ pub trait Rx: crate::private::Sealed {
#[doc(hidden)] #[doc(hidden)]
pub struct ChannelRx<'a, M, CH> pub struct ChannelRx<'a, M, CH>
where where
CH: DmaChannel, M: Mode,
CH: DmaRxChannel,
{ {
pub(crate) rx_impl: CH::Rx, pub(crate) rx_impl: PeripheralRef<'a, CH>,
pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, pub(crate) _phantom: PhantomData<M>,
} }
impl<'a, CH> ChannelRx<'a, Blocking, CH> impl<'a, CH> ChannelRx<'a, Blocking, CH>
where where
CH: DmaChannel, CH: DmaRxChannel,
{ {
fn new(rx_impl: CH::Rx) -> Self { /// Creates a new RX channel half.
pub fn new(rx_impl: impl Peripheral<P = CH> + 'a) -> Self {
crate::into_ref!(rx_impl);
#[cfg(gdma)] #[cfg(gdma)]
// clear the mem2mem mode to avoid failed DMA if this // clear the mem2mem mode to avoid failed DMA if this
// channel was previously used for a mem2mem transfer. // channel was previously used for a mem2mem transfer.
@ -1724,10 +1763,7 @@ where
} }
} }
fn set_interrupt_handler(&mut self, handler: InterruptHandler) fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
where
CH: DmaChannel,
{
self.unlisten_in(EnumSet::all()); self.unlisten_in(EnumSet::all());
self.clear_in(EnumSet::all()); self.clear_in(EnumSet::all());
@ -1743,7 +1779,7 @@ where
impl<'a, CH> ChannelRx<'a, Async, CH> impl<'a, CH> ChannelRx<'a, Async, CH>
where where
CH: DmaChannel, CH: DmaRxChannel,
{ {
/// Converts an async channel into a blocking channel. /// Converts an async channel into a blocking channel.
pub(crate) fn into_blocking(self) -> ChannelRx<'a, Blocking, CH> { pub(crate) fn into_blocking(self) -> ChannelRx<'a, Blocking, CH> {
@ -1761,20 +1797,8 @@ where
impl<'a, M, CH> ChannelRx<'a, M, CH> impl<'a, M, CH> ChannelRx<'a, M, CH>
where where
M: Mode, M: Mode,
CH: DmaChannel, CH: DmaRxChannel,
{ {
/// Return a less specific (degraded) version of this channel.
#[doc(hidden)]
pub fn degrade<DEG: DmaChannel>(self) -> ChannelRx<'a, M, DEG>
where
CH: DmaChannelConvert<DEG>,
{
ChannelRx {
rx_impl: CH::degrade_rx(self.rx_impl),
_phantom: PhantomData,
}
}
/// Configure the channel. /// Configure the channel.
#[cfg(gdma)] #[cfg(gdma)]
pub fn set_priority(&mut self, priority: DmaPriority) { pub fn set_priority(&mut self, priority: DmaPriority) {
@ -1806,14 +1830,14 @@ where
impl<M, CH> crate::private::Sealed for ChannelRx<'_, M, CH> impl<M, CH> crate::private::Sealed for ChannelRx<'_, M, CH>
where where
M: Mode, M: Mode,
CH: DmaChannel, CH: DmaRxChannel,
{ {
} }
impl<M, CH> Rx for ChannelRx<'_, M, CH> impl<M, CH> Rx for ChannelRx<'_, M, CH>
where where
M: Mode, M: Mode,
CH: DmaChannel, CH: DmaRxChannel,
{ {
// TODO: used by I2S, which should be rewritten to use the Preparation-based // TODO: used by I2S, which should be rewritten to use the Preparation-based
// API. // API.
@ -1978,24 +2002,26 @@ pub trait Tx: crate::private::Sealed {
#[doc(hidden)] #[doc(hidden)]
pub struct ChannelTx<'a, M, CH> pub struct ChannelTx<'a, M, CH>
where where
CH: DmaChannel, M: Mode,
CH: DmaTxChannel,
{ {
pub(crate) tx_impl: CH::Tx, pub(crate) tx_impl: PeripheralRef<'a, CH>,
pub(crate) _phantom: PhantomData<(&'a (), CH, M)>, pub(crate) _phantom: PhantomData<M>,
} }
impl<'a, CH> ChannelTx<'a, Blocking, CH> impl<'a, CH> ChannelTx<'a, Blocking, CH>
where where
CH: DmaChannel, CH: DmaTxChannel,
{ {
fn new(tx_impl: CH::Tx) -> Self { /// Creates a new TX channel half.
pub fn new(tx_impl: impl Peripheral<P = CH> + 'a) -> Self {
crate::into_ref!(tx_impl);
if let Some(interrupt) = tx_impl.peripheral_interrupt() { if let Some(interrupt) = tx_impl.peripheral_interrupt() {
for cpu in Cpu::all() { for cpu in Cpu::all() {
crate::interrupt::disable(cpu, interrupt); crate::interrupt::disable(cpu, interrupt);
} }
} }
tx_impl.set_async(false); tx_impl.set_async(false);
Self { Self {
tx_impl, tx_impl,
_phantom: PhantomData, _phantom: PhantomData,
@ -2014,10 +2040,7 @@ where
} }
} }
fn set_interrupt_handler(&mut self, handler: InterruptHandler) fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
where
CH: DmaChannel,
{
self.unlisten_out(EnumSet::all()); self.unlisten_out(EnumSet::all());
self.clear_out(EnumSet::all()); self.clear_out(EnumSet::all());
@ -2033,7 +2056,7 @@ where
impl<'a, CH> ChannelTx<'a, Async, CH> impl<'a, CH> ChannelTx<'a, Async, CH>
where where
CH: DmaChannel, CH: DmaTxChannel,
{ {
/// Converts an async channel into a blocking channel. /// Converts an async channel into a blocking channel.
pub(crate) fn into_blocking(self) -> ChannelTx<'a, Blocking, CH> { pub(crate) fn into_blocking(self) -> ChannelTx<'a, Blocking, CH> {
@ -2051,20 +2074,8 @@ where
impl<'a, M, CH> ChannelTx<'a, M, CH> impl<'a, M, CH> ChannelTx<'a, M, CH>
where where
M: Mode, M: Mode,
CH: DmaChannel, CH: DmaTxChannel,
{ {
/// Return a less specific (degraded) version of this channel.
#[doc(hidden)]
pub fn degrade<DEG: DmaChannel>(self) -> ChannelTx<'a, M, DEG>
where
CH: DmaChannelConvert<DEG>,
{
ChannelTx {
tx_impl: CH::degrade_tx(self.tx_impl),
_phantom: PhantomData,
}
}
/// Configure the channel priority. /// Configure the channel priority.
#[cfg(gdma)] #[cfg(gdma)]
pub fn set_priority(&mut self, priority: DmaPriority) { pub fn set_priority(&mut self, priority: DmaPriority) {
@ -2101,14 +2112,14 @@ where
impl<M, CH> crate::private::Sealed for ChannelTx<'_, M, CH> impl<M, CH> crate::private::Sealed for ChannelTx<'_, M, CH>
where where
M: Mode, M: Mode,
CH: DmaChannel, CH: DmaTxChannel,
{ {
} }
impl<M, CH> Tx for ChannelTx<'_, M, CH> impl<M, CH> Tx for ChannelTx<'_, M, CH>
where where
M: Mode, M: Mode,
CH: DmaChannel, CH: DmaTxChannel,
{ {
// TODO: used by I2S, which should be rewritten to use the Preparation-based // TODO: used by I2S, which should be rewritten to use the Preparation-based
// API. // API.
@ -2309,28 +2320,38 @@ pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
} }
/// DMA Channel /// DMA Channel
#[non_exhaustive]
pub struct Channel<'d, M, CH> pub struct Channel<'d, M, CH>
where where
M: Mode, M: Mode,
CH: DmaChannel, CH: DmaChannel,
{ {
/// RX half of the channel /// RX half of the channel
pub rx: ChannelRx<'d, M, CH>, pub rx: ChannelRx<'d, M, CH::Rx>,
/// TX half of the channel /// TX half of the channel
pub tx: ChannelTx<'d, M, CH>, pub tx: ChannelTx<'d, M, CH::Tx>,
} }
impl<'d, CH> Channel<'d, Blocking, CH> impl<'d, CH> Channel<'d, Blocking, CH>
where where
CH: DmaChannel, CH: DmaChannel,
{ {
pub(crate) fn new(channel: impl Peripheral<P = CH>) -> Self {
let (rx, tx) = unsafe {
channel
.clone_unchecked()
.split_internal(crate::private::Internal)
};
Self {
rx: ChannelRx::new(rx),
tx: ChannelTx::new(tx),
}
}
/// Sets the interrupt handler for RX and TX interrupts. /// Sets the interrupt handler for RX and TX interrupts.
/// ///
/// Interrupts are not enabled at the peripheral level here. /// Interrupts are not enabled at the peripheral level here.
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
where
CH: DmaChannel,
{
self.rx.set_interrupt_handler(handler); self.rx.set_interrupt_handler(handler);
self.tx.set_interrupt_handler(handler); self.tx.set_interrupt_handler(handler);
} }
@ -2418,25 +2439,6 @@ impl<'d, CH: DmaChannel> From<Channel<'d, Async, CH>> for Channel<'d, Blocking,
} }
} }
impl<'d, M, CH> Channel<'d, M, CH>
where
M: Mode,
CH: DmaChannel,
{
/// Return a less specific (degraded) version of this channel (both rx and
/// tx).
#[doc(hidden)]
pub fn degrade<DEG: DmaChannel>(self) -> Channel<'d, M, DEG>
where
CH: DmaChannelConvert<DEG>,
{
Channel {
rx: self.rx.degrade(),
tx: self.tx.degrade(),
}
}
}
pub(crate) mod dma_private { pub(crate) mod dma_private {
use super::*; use super::*;

View File

@ -16,10 +16,9 @@ use portable_atomic::{AtomicBool, Ordering};
use crate::{ use crate::{
dma::*, dma::*,
peripheral::PeripheralRef, peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt, peripherals::Interrupt,
system::{Peripheral, PeripheralClockControl}, system::{self, PeripheralClockControl},
Blocking,
}; };
type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock; type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock;
@ -40,17 +39,33 @@ pub trait PdmaChannel: crate::private::Sealed {
fn tx_async_flag(&self) -> &'static AtomicBool; fn tx_async_flag(&self) -> &'static AtomicBool;
} }
#[doc(hidden)] /// The RX half of an arbitrary SPI DMA channel.
pub struct SpiDmaRxChannelImpl<C>(C); pub struct AnySpiDmaRxChannel(AnySpiDmaChannel);
impl<C> crate::private::Sealed for SpiDmaRxChannelImpl<C> {} impl crate::private::Sealed for AnySpiDmaRxChannel {}
impl DmaRxChannel for AnySpiDmaRxChannel {}
impl Peripheral for AnySpiDmaRxChannel {
type P = Self;
#[doc(hidden)] unsafe fn clone_unchecked(&self) -> Self::P {
pub struct SpiDmaTxChannelImpl<C>(C); Self(self.0.clone_unchecked())
}
}
impl<C> crate::private::Sealed for SpiDmaTxChannelImpl<C> {} /// The TX half of an arbitrary SPI DMA channel.
pub struct AnySpiDmaTxChannel(AnySpiDmaChannel);
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDmaTxChannelImpl<C> { impl crate::private::Sealed for AnySpiDmaTxChannel {}
impl DmaTxChannel for AnySpiDmaTxChannel {}
impl Peripheral for AnySpiDmaTxChannel {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self(self.0.clone_unchecked())
}
}
impl RegisterAccess for AnySpiDmaTxChannel {
fn reset(&self) { fn reset(&self) {
let spi = self.0.register_block(); let spi = self.0.register_block();
spi.dma_conf().modify(|_, w| w.out_rst().set_bit()); spi.dma_conf().modify(|_, w| w.out_rst().set_bit());
@ -107,7 +122,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDma
} }
} }
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> TxRegisterAccess for SpiDmaTxChannelImpl<C> { impl TxRegisterAccess for AnySpiDmaTxChannel {
fn set_auto_write_back(&self, enable: bool) { fn set_auto_write_back(&self, enable: bool) {
// there is no `auto_wrback` for SPI // there is no `auto_wrback` for SPI
assert!(!enable); assert!(!enable);
@ -127,9 +142,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> TxRegisterAccess for SpiD
} }
} }
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaTxInterrupt> impl InterruptAccess<DmaTxInterrupt> for AnySpiDmaTxChannel {
for SpiDmaTxChannelImpl<C>
{
fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) { fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
let reg_block = self.0.register_block(); let reg_block = self.0.register_block();
reg_block.dma_int_ena().modify(|_, w| { reg_block.dma_int_ena().modify(|_, w| {
@ -215,7 +228,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaTxInte
} }
} }
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDmaRxChannelImpl<C> { impl RegisterAccess for AnySpiDmaRxChannel {
fn reset(&self) { fn reset(&self) {
let spi = self.0.register_block(); let spi = self.0.register_block();
spi.dma_conf().modify(|_, w| w.in_rst().set_bit()); spi.dma_conf().modify(|_, w| w.in_rst().set_bit());
@ -267,7 +280,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDma
} }
} }
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RxRegisterAccess for SpiDmaRxChannelImpl<C> { impl RxRegisterAccess for AnySpiDmaRxChannel {
fn peripheral_interrupt(&self) -> Option<Interrupt> { fn peripheral_interrupt(&self) -> Option<Interrupt> {
Some(self.0.peripheral_interrupt()) Some(self.0.peripheral_interrupt())
} }
@ -277,9 +290,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RxRegisterAccess for SpiD
} }
} }
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaRxInterrupt> impl InterruptAccess<DmaRxInterrupt> for AnySpiDmaRxChannel {
for SpiDmaRxChannelImpl<C>
{
fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) { fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
let reg_block = self.0.register_block(); let reg_block = self.0.register_block();
reg_block.dma_int_ena().modify(|_, w| { reg_block.dma_int_ena().modify(|_, w| {
@ -385,17 +396,42 @@ macro_rules! ImplSpiChannel {
#[non_exhaustive] #[non_exhaustive]
pub struct [<Spi $num DmaChannel>] {} pub struct [<Spi $num DmaChannel>] {}
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
impl Peripheral for [<Spi $num DmaChannel>] {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}
impl [<Spi $num DmaChannel>] {
/// Unsafely constructs a new DMA channel.
///
/// # Safety
///
/// The caller must ensure that only a single instance is used.
pub unsafe fn steal() -> Self {
Self {}
}
}
impl DmaChannel for [<Spi $num DmaChannel>] { impl DmaChannel for [<Spi $num DmaChannel>] {
type Rx = SpiDmaRxChannelImpl<Self>; type Rx = AnySpiDmaRxChannel;
type Tx = SpiDmaTxChannelImpl<Self>; type Tx = AnySpiDmaTxChannel;
unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
(AnySpiDmaRxChannel(Self {}.into()), AnySpiDmaTxChannel(Self {}.into()))
}
} }
impl DmaChannelExt for [<Spi $num DmaChannel>] { impl DmaChannelExt for [<Spi $num DmaChannel>] {
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> { fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
SpiDmaRxChannelImpl(Self {}) AnySpiDmaRxChannel(Self {}.into())
} }
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> { fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
SpiDmaTxChannelImpl(Self {}) AnySpiDmaTxChannel(Self {}.into())
} }
} }
@ -403,7 +439,7 @@ macro_rules! ImplSpiChannel {
type RegisterBlock = SpiRegisterBlock; type RegisterBlock = SpiRegisterBlock;
fn register_block(&self) -> &SpiRegisterBlock { fn register_block(&self) -> &SpiRegisterBlock {
unsafe { &*crate::peripherals::[<SPI $num>]::PTR } unsafe { &*$crate::peripherals::[<SPI $num>]::PTR }
} }
fn tx_waker(&self) -> &'static AtomicWaker { fn tx_waker(&self) -> &'static AtomicWaker {
static WAKER: AtomicWaker = AtomicWaker::new(); static WAKER: AtomicWaker = AtomicWaker::new();
@ -436,44 +472,53 @@ macro_rules! ImplSpiChannel {
} }
impl DmaChannelConvert<AnySpiDmaChannel> for [<Spi $num DmaChannel>] { impl DmaChannelConvert<AnySpiDmaChannel> for [<Spi $num DmaChannel>] {
fn degrade_rx(rx: SpiDmaRxChannelImpl<Self>) -> SpiDmaRxChannelImpl<AnySpiDmaChannelInner> { fn degrade(self) -> AnySpiDmaChannel {
SpiDmaRxChannelImpl(rx.0.into()) self.into()
}
fn degrade_tx(tx: SpiDmaTxChannelImpl<Self>) -> SpiDmaTxChannelImpl<AnySpiDmaChannelInner> {
SpiDmaTxChannelImpl(tx.0.into())
} }
} }
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {} impl DmaChannelConvert<AnySpiDmaRxChannel> for [<Spi $num DmaChannel>] {
fn degrade(self) -> AnySpiDmaRxChannel {
AnySpiDmaRxChannel(Self {}.into())
}
}
impl [<Spi $num DmaChannel>] { impl DmaChannelConvert<AnySpiDmaTxChannel> for [<Spi $num DmaChannel>] {
/// Unsafely constructs a new DMA channel. fn degrade(self) -> AnySpiDmaTxChannel {
/// AnySpiDmaTxChannel(Self {}.into())
/// # Safety
///
/// The caller must ensure that only a single instance is used.
pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> {
Channel {
tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})),
rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})),
}
} }
} }
} }
}; };
} }
#[doc(hidden)] /// The RX half of an arbitrary I2S DMA channel.
pub struct I2sDmaRxChannelImpl<C>(C); pub struct AnyI2sDmaRxChannel(AnyI2sDmaChannel);
impl<C> crate::private::Sealed for I2sDmaRxChannelImpl<C> {} impl crate::private::Sealed for AnyI2sDmaRxChannel {}
impl DmaRxChannel for AnyI2sDmaRxChannel {}
impl Peripheral for AnyI2sDmaRxChannel {
type P = Self;
#[doc(hidden)] unsafe fn clone_unchecked(&self) -> Self::P {
pub struct I2sDmaTxChannelImpl<C>(C); Self(self.0.clone_unchecked())
}
}
impl<C> crate::private::Sealed for I2sDmaTxChannelImpl<C> {} /// The TX half of an arbitrary I2S DMA channel.
pub struct AnyI2sDmaTxChannel(AnyI2sDmaChannel);
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDmaTxChannelImpl<C> { impl crate::private::Sealed for AnyI2sDmaTxChannel {}
impl DmaTxChannel for AnyI2sDmaTxChannel {}
impl Peripheral for AnyI2sDmaTxChannel {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self(self.0.clone_unchecked())
}
}
impl RegisterAccess for AnyI2sDmaTxChannel {
fn reset(&self) { fn reset(&self) {
let reg_block = self.0.register_block(); let reg_block = self.0.register_block();
reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit()); reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit());
@ -538,7 +583,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDma
} }
} }
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> TxRegisterAccess for I2sDmaTxChannelImpl<C> { impl TxRegisterAccess for AnyI2sDmaTxChannel {
fn set_auto_write_back(&self, enable: bool) { fn set_auto_write_back(&self, enable: bool) {
let reg_block = self.0.register_block(); let reg_block = self.0.register_block();
reg_block reg_block
@ -564,9 +609,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> TxRegisterAccess for I2sD
} }
} }
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaTxInterrupt> impl InterruptAccess<DmaTxInterrupt> for AnyI2sDmaTxChannel {
for I2sDmaTxChannelImpl<C>
{
fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) { fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
let reg_block = self.0.register_block(); let reg_block = self.0.register_block();
reg_block.int_ena().modify(|_, w| { reg_block.int_ena().modify(|_, w| {
@ -652,7 +695,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaTxInte
} }
} }
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDmaRxChannelImpl<C> { impl RegisterAccess for AnyI2sDmaRxChannel {
fn reset(&self) { fn reset(&self) {
let reg_block = self.0.register_block(); let reg_block = self.0.register_block();
reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit()); reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit());
@ -710,7 +753,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDma
} }
} }
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RxRegisterAccess for I2sDmaRxChannelImpl<C> { impl RxRegisterAccess for AnyI2sDmaRxChannel {
fn peripheral_interrupt(&self) -> Option<Interrupt> { fn peripheral_interrupt(&self) -> Option<Interrupt> {
Some(self.0.peripheral_interrupt()) Some(self.0.peripheral_interrupt())
} }
@ -720,9 +763,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RxRegisterAccess for I2sD
} }
} }
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaRxInterrupt> impl InterruptAccess<DmaRxInterrupt> for AnyI2sDmaRxChannel {
for I2sDmaRxChannelImpl<C>
{
fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) { fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
let reg_block = self.0.register_block(); let reg_block = self.0.register_block();
reg_block.int_ena().modify(|_, w| { reg_block.int_ena().modify(|_, w| {
@ -824,17 +865,40 @@ macro_rules! ImplI2sChannel {
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {} impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
impl Peripheral for [<I2s $num DmaChannel>] {
type P = Self;
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}
impl [<I2s $num DmaChannel>] {
/// Unsafely constructs a new DMA channel.
///
/// # Safety
///
/// The caller must ensure that only a single instance is used.
pub unsafe fn steal() -> Self {
Self {}
}
}
impl DmaChannel for [<I2s $num DmaChannel>] { impl DmaChannel for [<I2s $num DmaChannel>] {
type Rx = I2sDmaRxChannelImpl<Self>; type Rx = AnyI2sDmaRxChannel;
type Tx = I2sDmaTxChannelImpl<Self>; type Tx = AnyI2sDmaTxChannel;
unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
(AnyI2sDmaRxChannel(Self {}.into()), AnyI2sDmaTxChannel(Self {}.into()))
}
} }
impl DmaChannelExt for [<I2s $num DmaChannel>] { impl DmaChannelExt for [<I2s $num DmaChannel>] {
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> { fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
I2sDmaRxChannelImpl(Self {}) AnyI2sDmaRxChannel(Self {}.into())
} }
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> { fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
I2sDmaTxChannelImpl(Self {}) AnyI2sDmaTxChannel(Self {}.into())
} }
} }
@ -874,25 +938,20 @@ macro_rules! ImplI2sChannel {
} }
impl DmaChannelConvert<AnyI2sDmaChannel> for [<I2s $num DmaChannel>] { impl DmaChannelConvert<AnyI2sDmaChannel> for [<I2s $num DmaChannel>] {
fn degrade_rx(rx: I2sDmaRxChannelImpl<Self>) -> I2sDmaRxChannelImpl<AnyI2sDmaChannelInner> { fn degrade(self) -> AnyI2sDmaChannel {
I2sDmaRxChannelImpl(rx.0.into()) self.into()
}
fn degrade_tx(tx: I2sDmaTxChannelImpl<Self>) -> I2sDmaTxChannelImpl<AnyI2sDmaChannelInner> {
I2sDmaTxChannelImpl(tx.0.into())
} }
} }
impl [<I2s $num DmaChannel>] { impl DmaChannelConvert<AnyI2sDmaRxChannel> for [<I2s $num DmaChannel>] {
/// Unsafely constructs a new DMA channel. fn degrade(self) -> AnyI2sDmaRxChannel {
/// AnyI2sDmaRxChannel(Self {}.into())
/// # Safety }
/// }
/// The caller must ensure that only a single instance is used.
pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> { impl DmaChannelConvert<AnyI2sDmaTxChannel> for [<I2s $num DmaChannel>] {
Channel { fn degrade(self) -> AnyI2sDmaTxChannel {
tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})), AnyI2sDmaTxChannel(Self {}.into())
rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})),
}
} }
} }
} }
@ -921,23 +980,21 @@ crate::impl_dma_eligible!([I2s1DmaChannel] I2S1 => I2s1);
pub struct Dma<'d> { pub struct Dma<'d> {
_inner: PeripheralRef<'d, crate::peripherals::DMA>, _inner: PeripheralRef<'d, crate::peripherals::DMA>,
/// DMA channel for SPI2 /// DMA channel for SPI2
pub spi2channel: Channel<'d, Blocking, Spi2DmaChannel>, pub spi2channel: Spi2DmaChannel,
/// DMA channel for SPI3 /// DMA channel for SPI3
pub spi3channel: Channel<'d, Blocking, Spi3DmaChannel>, pub spi3channel: Spi3DmaChannel,
/// DMA channel for I2S0 /// DMA channel for I2S0
pub i2s0channel: Channel<'d, Blocking, I2s0DmaChannel>, pub i2s0channel: I2s0DmaChannel,
/// DMA channel for I2S1 /// DMA channel for I2S1
#[cfg(i2s1)] #[cfg(i2s1)]
pub i2s1channel: Channel<'d, Blocking, I2s1DmaChannel>, pub i2s1channel: I2s1DmaChannel,
} }
impl<'d> Dma<'d> { impl<'d> Dma<'d> {
/// Create a DMA instance. /// Create a DMA instance.
pub fn new( pub fn new(dma: impl Peripheral<P = crate::peripherals::DMA> + 'd) -> Dma<'d> {
dma: impl crate::peripheral::Peripheral<P = crate::peripherals::DMA> + 'd, if PeripheralClockControl::enable(system::Peripheral::Dma) {
) -> Dma<'d> { PeripheralClockControl::reset(system::Peripheral::Dma);
if PeripheralClockControl::enable(Peripheral::Dma) {
PeripheralClockControl::reset(Peripheral::Dma);
} }
#[cfg(esp32)] #[cfg(esp32)]
@ -983,31 +1040,31 @@ where
} }
} }
/// A marker for SPI-compatible type-erased DMA channels. crate::any_peripheral! {
pub struct AnySpiDmaChannel; /// An SPI-compatible type-erased DMA channel.
pub peripheral AnySpiDmaChannel {
impl crate::private::Sealed for AnySpiDmaChannel {}
impl DmaChannel for AnySpiDmaChannel {
type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>;
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
}
crate::any_enum! {
#[doc(hidden)]
pub enum AnySpiDmaChannelInner {
Spi2(Spi2DmaChannel), Spi2(Spi2DmaChannel),
Spi3(Spi3DmaChannel), Spi3(Spi3DmaChannel),
} }
} }
impl crate::private::Sealed for AnySpiDmaChannelInner {} impl DmaChannel for AnySpiDmaChannel {
type Rx = AnySpiDmaRxChannel;
type Tx = AnySpiDmaTxChannel;
impl PdmaChannel for AnySpiDmaChannelInner { unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
(
AnySpiDmaRxChannel(unsafe { self.clone_unchecked() }),
AnySpiDmaTxChannel(unsafe { self.clone_unchecked() }),
)
}
}
impl PdmaChannel for AnySpiDmaChannel {
type RegisterBlock = SpiRegisterBlock; type RegisterBlock = SpiRegisterBlock;
delegate::delegate! { delegate::delegate! {
to match self { to match &self.0 {
AnySpiDmaChannelInner::Spi2(channel) => channel, AnySpiDmaChannelInner::Spi2(channel) => channel,
AnySpiDmaChannelInner::Spi3(channel) => channel, AnySpiDmaChannelInner::Spi3(channel) => channel,
} { } {
@ -1023,32 +1080,32 @@ impl PdmaChannel for AnySpiDmaChannelInner {
} }
} }
/// A marker for I2S-compatible type-erased DMA channels. crate::any_peripheral! {
pub struct AnyI2sDmaChannel; /// An I2S-compatible type-erased DMA channel.
pub peripheral AnyI2sDmaChannel {
impl crate::private::Sealed for AnyI2sDmaChannel {}
impl DmaChannel for AnyI2sDmaChannel {
type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>;
type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>;
}
crate::any_enum! {
#[doc(hidden)]
pub enum AnyI2sDmaChannelInner {
I2s0(I2s0DmaChannel), I2s0(I2s0DmaChannel),
#[cfg(i2s1)] #[cfg(i2s1)]
I2s1(I2s1DmaChannel), I2s1(I2s1DmaChannel),
} }
} }
impl crate::private::Sealed for AnyI2sDmaChannelInner {} impl DmaChannel for AnyI2sDmaChannel {
type Rx = AnyI2sDmaRxChannel;
type Tx = AnyI2sDmaTxChannel;
impl PdmaChannel for AnyI2sDmaChannelInner { unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
(
AnyI2sDmaRxChannel(unsafe { self.clone_unchecked() }),
AnyI2sDmaTxChannel(unsafe { self.clone_unchecked() }),
)
}
}
impl PdmaChannel for AnyI2sDmaChannel {
type RegisterBlock = I2sRegisterBlock; type RegisterBlock = I2sRegisterBlock;
delegate::delegate! { delegate::delegate! {
to match self { to match &self.0 {
AnyI2sDmaChannelInner::I2s0(channel) => channel, AnyI2sDmaChannelInner::I2s0(channel) => channel,
#[cfg(i2s1)] #[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(channel) => channel, AnyI2sDmaChannelInner::I2s1(channel) => channel,

View File

@ -82,6 +82,7 @@ use crate::{
ChannelTx, ChannelTx,
DescriptorChain, DescriptorChain,
DmaChannelConvert, DmaChannelConvert,
DmaChannelFor,
DmaDescriptor, DmaDescriptor,
DmaEligible, DmaEligible,
DmaError, DmaError,
@ -91,7 +92,9 @@ use crate::{
DmaTransferTxCircular, DmaTransferTxCircular,
ReadBuffer, ReadBuffer,
Rx, Rx,
RxChannelFor,
Tx, Tx,
TxChannelFor,
WriteBuffer, WriteBuffer,
}, },
gpio::interconnect::PeripheralOutput, gpio::interconnect::PeripheralOutput,
@ -258,24 +261,21 @@ where
pub i2s_tx: TxCreator<'d, M, T>, pub i2s_tx: TxCreator<'d, M, T>,
} }
impl<'d, DmaMode, T> I2s<'d, DmaMode, T> impl<'d, T> I2s<'d, Blocking, T>
where where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode,
{ {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn new_internal<CH>( fn new_internal(
i2s: PeripheralRef<'d, T>, i2s: PeripheralRef<'d, T>,
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, DmaMode, CH>, channel: PeripheralRef<'d, DmaChannelFor<T>>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self {
where let channel = Channel::new(channel);
CH: DmaChannelConvert<T::Dma>,
{
channel.runtime_ensure_compatible(&i2s); channel.runtime_ensure_compatible(&i2s);
// on ESP32-C3 / ESP32-S3 and later RX and TX are independent and // on ESP32-C3 / ESP32-S3 and later RX and TX are independent and
// could be configured totally independently but for now handle all // could be configured totally independently but for now handle all
@ -291,7 +291,6 @@ where
i2s.set_master(); i2s.set_master();
i2s.update(); i2s.update();
let channel = channel.degrade();
Self { Self {
i2s_rx: RxCreator { i2s_rx: RxCreator {
i2s: unsafe { i2s.clone_unchecked() }, i2s: unsafe { i2s.clone_unchecked() },
@ -368,19 +367,17 @@ impl<'d> I2s<'d, Blocking> {
/// Construct a new I2S peripheral driver instance for the first I2S /// Construct a new I2S peripheral driver instance for the first I2S
/// peripheral /// peripheral
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new<CH, DM>( pub fn new<CH>(
i2s: impl Peripheral<P = impl RegisterAccess> + 'd, i2s: impl Peripheral<P = impl RegisterAccess> + 'd,
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, DM, CH>, channel: impl Peripheral<P = CH> + 'd,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
where where
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>, CH: DmaChannelConvert<DmaChannelFor<AnyI2s>>,
DM: Mode,
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
Self::new_typed( Self::new_typed(
i2s.map_into(), i2s.map_into(),
@ -401,19 +398,17 @@ where
/// Construct a new I2S peripheral driver instance for the first I2S /// Construct a new I2S peripheral driver instance for the first I2S
/// peripheral /// peripheral
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new_typed<CH, DM>( pub fn new_typed<CH>(
i2s: impl Peripheral<P = T> + 'd, i2s: impl Peripheral<P = T> + 'd,
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, DM, CH>, channel: impl Peripheral<P = CH> + 'd,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<DmaChannelFor<T>>,
DM: Mode,
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
crate::into_ref!(i2s); crate::into_ref!(i2s);
Self::new_internal( Self::new_internal(
@ -421,7 +416,7 @@ where
standard, standard,
data_format, data_format,
sample_rate, sample_rate,
channel.into(), channel.map(|ch| ch.degrade()).into_ref(),
rx_descriptors, rx_descriptors,
tx_descriptors, tx_descriptors,
) )
@ -465,9 +460,10 @@ where
pub struct I2sTx<'d, DmaMode, T = AnyI2s> pub struct I2sTx<'d, DmaMode, T = AnyI2s>
where where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode,
{ {
i2s: PeripheralRef<'d, T>, i2s: PeripheralRef<'d, T>,
tx_channel: ChannelTx<'d, DmaMode, T::Dma>, tx_channel: ChannelTx<'d, DmaMode, TxChannelFor<T>>,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
_guard: PeripheralGuard, _guard: PeripheralGuard,
} }
@ -501,7 +497,7 @@ where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, DmaMode: Mode,
{ {
type TX = ChannelTx<'d, DmaMode, T::Dma>; type TX = ChannelTx<'d, DmaMode, TxChannelFor<T>>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel &mut self.tx_channel
@ -600,7 +596,7 @@ where
DmaMode: Mode, DmaMode: Mode,
{ {
i2s: PeripheralRef<'d, T>, i2s: PeripheralRef<'d, T>,
rx_channel: ChannelRx<'d, DmaMode, T::Dma>, rx_channel: ChannelRx<'d, DmaMode, RxChannelFor<T>>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
_guard: PeripheralGuard, _guard: PeripheralGuard,
} }
@ -634,7 +630,7 @@ where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, DmaMode: Mode,
{ {
type RX = ChannelRx<'d, DmaMode, T::Dma>; type RX = ChannelRx<'d, DmaMode, RxChannelFor<T>>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel &mut self.rx_channel
@ -743,16 +739,7 @@ mod private {
use enumset::EnumSet; use enumset::EnumSet;
use fugit::HertzU32; use fugit::HertzU32;
use super::{ use super::*;
DataFormat,
I2sInterrupt,
I2sRx,
I2sTx,
PeripheralGuard,
RegisterAccess,
Standard,
I2S_LL_MCLK_DIVIDER_MAX,
};
#[cfg(not(i2s1))] #[cfg(not(i2s1))]
use crate::peripherals::i2s0::RegisterBlock; use crate::peripherals::i2s0::RegisterBlock;
// on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features // on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features
@ -779,7 +766,7 @@ mod private {
M: Mode, M: Mode,
{ {
pub i2s: PeripheralRef<'d, T>, pub i2s: PeripheralRef<'d, T>,
pub tx_channel: ChannelTx<'d, M, T::Dma>, pub tx_channel: ChannelTx<'d, M, TxChannelFor<T>>,
pub descriptors: &'static mut [DmaDescriptor], pub descriptors: &'static mut [DmaDescriptor],
pub(crate) guard: PeripheralGuard, pub(crate) guard: PeripheralGuard,
} }
@ -839,7 +826,7 @@ mod private {
M: Mode, M: Mode,
{ {
pub i2s: PeripheralRef<'d, T>, pub i2s: PeripheralRef<'d, T>,
pub rx_channel: ChannelRx<'d, M, T::Dma>, pub rx_channel: ChannelRx<'d, M, RxChannelFor<T>>,
pub descriptors: &'static mut [DmaDescriptor], pub descriptors: &'static mut [DmaDescriptor],
pub(crate) guard: PeripheralGuard, pub(crate) guard: PeripheralGuard,
} }

View File

@ -47,11 +47,13 @@ use crate::{
Channel, Channel,
ChannelTx, ChannelTx,
DmaChannelConvert, DmaChannelConvert,
DmaChannelFor,
DmaEligible, DmaEligible,
DmaError, DmaError,
DmaPeripheral, DmaPeripheral,
DmaTxBuffer, DmaTxBuffer,
Tx, Tx,
TxChannelFor,
}, },
gpio::{ gpio::{
interconnect::{OutputConnection, PeripheralOutput}, interconnect::{OutputConnection, PeripheralOutput},
@ -177,7 +179,7 @@ where
I: Instance, I: Instance,
{ {
instance: PeripheralRef<'d, I>, instance: PeripheralRef<'d, I>,
tx_channel: ChannelTx<'d, DM, I::Dma>, tx_channel: ChannelTx<'d, DM, TxChannelFor<I>>,
_guard: PeripheralGuard, _guard: PeripheralGuard,
} }
@ -185,13 +187,13 @@ impl<'d> I2sParallel<'d, Blocking> {
/// Create a new I2S Parallel Interface /// Create a new I2S Parallel Interface
pub fn new<CH>( pub fn new<CH>(
i2s: impl Peripheral<P = impl Instance> + 'd, i2s: impl Peripheral<P = impl Instance> + 'd,
channel: Channel<'d, Blocking, CH>, channel: impl Peripheral<P = CH> + 'd,
frequency: impl Into<fugit::HertzU32>, frequency: impl Into<fugit::HertzU32>,
pins: impl TxPins<'d>, pins: impl TxPins<'d>,
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd, clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
) -> Self ) -> Self
where where
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>, CH: DmaChannelConvert<DmaChannelFor<AnyI2s>>,
{ {
Self::new_typed(i2s.map_into(), channel, frequency, pins, clock_pin) Self::new_typed(i2s.map_into(), channel, frequency, pins, clock_pin)
} }
@ -204,19 +206,19 @@ where
/// Create a new I2S Parallel Interface /// Create a new I2S Parallel Interface
pub fn new_typed<CH>( pub fn new_typed<CH>(
i2s: impl Peripheral<P = I> + 'd, i2s: impl Peripheral<P = I> + 'd,
channel: Channel<'d, Blocking, CH>, channel: impl Peripheral<P = CH> + 'd,
frequency: impl Into<fugit::HertzU32>, frequency: impl Into<fugit::HertzU32>,
mut pins: impl TxPins<'d>, mut pins: impl TxPins<'d>,
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd, clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
) -> Self ) -> Self
where where
CH: DmaChannelConvert<I::Dma>, CH: DmaChannelConvert<DmaChannelFor<I>>,
{ {
crate::into_ref!(i2s); crate::into_ref!(i2s);
crate::into_mapped_ref!(clock_pin); crate::into_mapped_ref!(clock_pin);
let channel = Channel::new(channel.map(|ch| ch.degrade()));
channel.runtime_ensure_compatible(&i2s); channel.runtime_ensure_compatible(&i2s);
let channel = channel.degrade();
let guard = PeripheralGuard::new(i2s.peripheral()); let guard = PeripheralGuard::new(i2s.peripheral());

View File

@ -44,7 +44,7 @@
//! let lcd_cam = LcdCam::new(peripherals.LCD_CAM); //! let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
//! let mut camera = Camera::new( //! let mut camera = Camera::new(
//! lcd_cam.cam, //! lcd_cam.cam,
//! channel.rx, //! channel,
//! data_pins, //! data_pins,
//! 20u32.MHz(), //! 20u32.MHz(),
//! ) //! )
@ -67,7 +67,7 @@ use fugit::HertzU32;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{ChannelRx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaRxBuffer, Rx}, dma::{ChannelRx, DmaChannelConvert, DmaError, DmaPeripheral, DmaRxBuffer, Rx, RxChannelFor},
gpio::{ gpio::{
interconnect::{PeripheralInput, PeripheralOutput}, interconnect::{PeripheralInput, PeripheralOutput},
InputSignal, InputSignal,
@ -123,7 +123,7 @@ pub struct Cam<'d> {
/// Represents the camera interface with DMA support. /// Represents the camera interface with DMA support.
pub struct Camera<'d> { pub struct Camera<'d> {
lcd_cam: PeripheralRef<'d, LCD_CAM>, lcd_cam: PeripheralRef<'d, LCD_CAM>,
rx_channel: ChannelRx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, Blocking, RxChannelFor<LCD_CAM>>,
_guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>, _guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>,
} }
@ -131,14 +131,15 @@ impl<'d> Camera<'d> {
/// Creates a new `Camera` instance with DMA support. /// Creates a new `Camera` instance with DMA support.
pub fn new<P, CH>( pub fn new<P, CH>(
cam: Cam<'d>, cam: Cam<'d>,
channel: ChannelRx<'d, Blocking, CH>, channel: impl Peripheral<P = CH> + 'd,
_pins: P, _pins: P,
frequency: HertzU32, frequency: HertzU32,
) -> Self ) -> Self
where where
CH: DmaChannelConvert<<LCD_CAM as DmaEligible>::Dma>, CH: DmaChannelConvert<RxChannelFor<LCD_CAM>>,
P: RxPins, P: RxPins,
{ {
let rx_channel = ChannelRx::new(channel.map(|ch| ch.degrade()));
let lcd_cam = cam.lcd_cam; let lcd_cam = cam.lcd_cam;
let clocks = Clocks::get(); let clocks = Clocks::get();
@ -184,7 +185,7 @@ impl<'d> Camera<'d> {
Self { Self {
lcd_cam, lcd_cam,
rx_channel: channel.degrade(), rx_channel,
_guard: cam._guard, _guard: cam._guard,
} }
} }

View File

@ -61,7 +61,7 @@
//! config.de_idle_level = Level::Low; //! config.de_idle_level = Level::Low;
//! config.disable_black_region = false; //! config.disable_black_region = false;
//! //!
//! let mut dpi = Dpi::new(lcd_cam.lcd, channel.tx, 1.MHz(), config) //! let mut dpi = Dpi::new(lcd_cam.lcd, channel, 1.MHz(), config)
//! .with_vsync(peripherals.GPIO3) //! .with_vsync(peripherals.GPIO3)
//! .with_hsync(peripherals.GPIO46) //! .with_hsync(peripherals.GPIO46)
//! .with_de(peripherals.GPIO17) //! .with_de(peripherals.GPIO17)
@ -97,6 +97,7 @@
//! ``` //! ```
use core::{ use core::{
marker::PhantomData,
mem::ManuallyDrop, mem::ManuallyDrop,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
@ -105,7 +106,7 @@ use fugit::HertzU32;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx}, dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor},
gpio::{interconnect::PeripheralOutput, Level, OutputSignal}, gpio::{interconnect::PeripheralOutput, Level, OutputSignal},
lcd_cam::{ lcd_cam::{
calculate_clkm, calculate_clkm,
@ -120,22 +121,27 @@ use crate::{
}; };
/// Represents the RGB LCD interface. /// Represents the RGB LCD interface.
pub struct Dpi<'d> { pub struct Dpi<'d, DM: Mode> {
lcd_cam: PeripheralRef<'d, LCD_CAM>, lcd_cam: PeripheralRef<'d, LCD_CAM>,
tx_channel: ChannelTx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, Blocking, TxChannelFor<LCD_CAM>>,
_mode: PhantomData<DM>,
} }
impl<'d> Dpi<'d> { impl<'d, DM> Dpi<'d, DM>
where
DM: Mode,
{
/// Create a new instance of the RGB/DPI driver. /// Create a new instance of the RGB/DPI driver.
pub fn new<DM: Mode, CH>( pub fn new<CH>(
lcd: Lcd<'d, DM>, lcd: Lcd<'d, DM>,
channel: ChannelTx<'d, Blocking, CH>, channel: impl Peripheral<P = CH> + 'd,
frequency: HertzU32, frequency: HertzU32,
config: Config, config: Config,
) -> Self ) -> Self
where where
CH: DmaChannelConvert<<LCD_CAM as DmaEligible>::Dma>, CH: DmaChannelConvert<TxChannelFor<LCD_CAM>>,
{ {
let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade()));
let lcd_cam = lcd.lcd_cam; let lcd_cam = lcd.lcd_cam;
let clocks = Clocks::get(); let clocks = Clocks::get();
@ -270,7 +276,8 @@ impl<'d> Dpi<'d> {
Self { Self {
lcd_cam, lcd_cam,
tx_channel: channel.degrade(), tx_channel,
_mode: PhantomData,
} }
} }
@ -522,7 +529,7 @@ impl<'d> Dpi<'d> {
mut self, mut self,
next_frame_en: bool, next_frame_en: bool,
mut buf: TX, mut buf: TX,
) -> Result<DpiTransfer<'d, TX>, (DmaError, Self, TX)> { ) -> Result<DpiTransfer<'d, TX, DM>, (DmaError, Self, TX)> {
let result = unsafe { let result = unsafe {
self.tx_channel self.tx_channel
.prepare_transfer(DmaPeripheral::LcdCam, &mut buf) .prepare_transfer(DmaPeripheral::LcdCam, &mut buf)
@ -561,12 +568,12 @@ impl<'d> Dpi<'d> {
/// Represents an ongoing (or potentially finished) transfer using the RGB LCD /// Represents an ongoing (or potentially finished) transfer using the RGB LCD
/// interface /// interface
pub struct DpiTransfer<'d, BUF: DmaTxBuffer> { pub struct DpiTransfer<'d, BUF: DmaTxBuffer, DM: Mode> {
dpi: ManuallyDrop<Dpi<'d>>, dpi: ManuallyDrop<Dpi<'d, DM>>,
buffer_view: ManuallyDrop<BUF::View>, buffer_view: ManuallyDrop<BUF::View>,
} }
impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> { impl<'d, BUF: DmaTxBuffer, DM: Mode> DpiTransfer<'d, BUF, DM> {
/// Returns true when [Self::wait] will not block. /// Returns true when [Self::wait] will not block.
pub fn is_done(&self) -> bool { pub fn is_done(&self) -> bool {
self.dpi self.dpi
@ -578,7 +585,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
} }
/// Stops this transfer on the spot and returns the peripheral and buffer. /// Stops this transfer on the spot and returns the peripheral and buffer.
pub fn stop(mut self) -> (Dpi<'d>, BUF) { pub fn stop(mut self) -> (Dpi<'d, DM>, BUF) {
self.stop_peripherals(); self.stop_peripherals();
let (dpi, view) = self.release(); let (dpi, view) = self.release();
(dpi, BUF::from_view(view)) (dpi, BUF::from_view(view))
@ -588,7 +595,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
/// ///
/// Note: If you specified `next_frame_en` as true in [Dpi::send], you're /// Note: If you specified `next_frame_en` as true in [Dpi::send], you're
/// just waiting for a DMA error when you call this. /// just waiting for a DMA error when you call this.
pub fn wait(mut self) -> (Result<(), DmaError>, Dpi<'d>, BUF) { pub fn wait(mut self) -> (Result<(), DmaError>, Dpi<'d, DM>, BUF) {
while !self.is_done() { while !self.is_done() {
core::hint::spin_loop(); core::hint::spin_loop();
} }
@ -611,7 +618,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
(result, dpi, BUF::from_view(view)) (result, dpi, BUF::from_view(view))
} }
fn release(mut self) -> (Dpi<'d>, BUF::View) { fn release(mut self) -> (Dpi<'d, DM>, BUF::View) {
// SAFETY: Since forget is called on self, we know that self.dpi and // SAFETY: Since forget is called on self, we know that self.dpi and
// self.buffer_view won't be touched again. // self.buffer_view won't be touched again.
let result = unsafe { let result = unsafe {
@ -635,7 +642,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
} }
} }
impl<'d, BUF: DmaTxBuffer> Deref for DpiTransfer<'d, BUF> { impl<'d, BUF: DmaTxBuffer, DM: Mode> Deref for DpiTransfer<'d, BUF, DM> {
type Target = BUF::View; type Target = BUF::View;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -643,13 +650,13 @@ impl<'d, BUF: DmaTxBuffer> Deref for DpiTransfer<'d, BUF> {
} }
} }
impl<'d, BUF: DmaTxBuffer> DerefMut for DpiTransfer<'d, BUF> { impl<'d, BUF: DmaTxBuffer, DM: Mode> DerefMut for DpiTransfer<'d, BUF, DM> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer_view &mut self.buffer_view
} }
} }
impl<'d, BUF: DmaTxBuffer> Drop for DpiTransfer<'d, BUF> { impl<'d, BUF: DmaTxBuffer, DM: Mode> Drop for DpiTransfer<'d, BUF, DM> {
fn drop(&mut self) { fn drop(&mut self) {
self.stop_peripherals(); self.stop_peripherals();

View File

@ -38,7 +38,7 @@
//! //!
//! let mut i8080 = I8080::new( //! let mut i8080 = I8080::new(
//! lcd_cam.lcd, //! lcd_cam.lcd,
//! channel.tx, //! channel,
//! tx_pins, //! tx_pins,
//! 20.MHz(), //! 20.MHz(),
//! Config::default(), //! Config::default(),
@ -62,7 +62,7 @@ use fugit::HertzU32;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx}, dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor},
gpio::{ gpio::{
interconnect::{OutputConnection, PeripheralOutput}, interconnect::{OutputConnection, PeripheralOutput},
OutputSignal, OutputSignal,
@ -85,7 +85,7 @@ use crate::{
/// Represents the I8080 LCD interface. /// Represents the I8080 LCD interface.
pub struct I8080<'d, DM: Mode> { pub struct I8080<'d, DM: Mode> {
lcd_cam: PeripheralRef<'d, LCD_CAM>, lcd_cam: PeripheralRef<'d, LCD_CAM>,
tx_channel: ChannelTx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, Blocking, TxChannelFor<LCD_CAM>>,
_mode: PhantomData<DM>, _mode: PhantomData<DM>,
} }
@ -96,15 +96,16 @@ where
/// Creates a new instance of the I8080 LCD interface. /// Creates a new instance of the I8080 LCD interface.
pub fn new<P, CH>( pub fn new<P, CH>(
lcd: Lcd<'d, DM>, lcd: Lcd<'d, DM>,
channel: ChannelTx<'d, Blocking, CH>, channel: impl Peripheral<P = CH> + 'd,
mut pins: P, mut pins: P,
frequency: HertzU32, frequency: HertzU32,
config: Config, config: Config,
) -> Self ) -> Self
where where
CH: DmaChannelConvert<<LCD_CAM as DmaEligible>::Dma>, CH: DmaChannelConvert<TxChannelFor<LCD_CAM>>,
P: TxPins, P: TxPins,
{ {
let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade()));
let lcd_cam = lcd.lcd_cam; let lcd_cam = lcd.lcd_cam;
let clocks = Clocks::get(); let clocks = Clocks::get();
@ -207,7 +208,7 @@ where
Self { Self {
lcd_cam, lcd_cam,
tx_channel: channel.degrade(), tx_channel,
_mode: PhantomData, _mode: PhantomData,
} }
} }

View File

@ -36,15 +36,17 @@ use crate::{
ChannelTx, ChannelTx,
DescriptorChain, DescriptorChain,
DmaChannelConvert, DmaChannelConvert,
DmaChannelFor,
DmaDescriptor, DmaDescriptor,
DmaEligible,
DmaError, DmaError,
DmaPeripheral, DmaPeripheral,
DmaTransferRx, DmaTransferRx,
DmaTransferTx, DmaTransferTx,
ReadBuffer, ReadBuffer,
Rx, Rx,
RxChannelFor,
Tx, Tx,
TxChannelFor,
WriteBuffer, WriteBuffer,
}, },
gpio::{ gpio::{
@ -53,7 +55,7 @@ use crate::{
}, },
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{self, Peripheral}, peripheral::{self, Peripheral},
peripherals::{self, Interrupt, PARL_IO}, peripherals::{Interrupt, PARL_IO},
system::{self, GenericPeripheralGuard}, system::{self, GenericPeripheralGuard},
Async, Async,
Blocking, Blocking,
@ -809,7 +811,7 @@ pub struct ParlIoTx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, DM, TxChannelFor<PARL_IO>>,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>, _guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>,
} }
@ -890,7 +892,7 @@ pub struct ParlIoRx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>, _guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>,
} }
@ -1003,31 +1005,29 @@ where
impl<'d> ParlIoFullDuplex<'d, Blocking> { impl<'d> ParlIoFullDuplex<'d, Blocking> {
/// Create a new instance of [ParlIoFullDuplex] /// Create a new instance of [ParlIoFullDuplex]
pub fn new<CH, DM>( pub fn new<CH>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = PARL_IO> + 'd,
dma_channel: Channel<'d, DM, CH>, dma_channel: impl Peripheral<P = CH> + 'd,
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32, frequency: HertzU32,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
DM: Mode, CH: DmaChannelConvert<DmaChannelFor<PARL_IO>>,
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
let tx_guard = GenericPeripheralGuard::new(); let tx_guard = GenericPeripheralGuard::new();
let rx_guard = GenericPeripheralGuard::new(); let rx_guard = GenericPeripheralGuard::new();
let dma_channel = Channel::<Blocking, CH>::from(dma_channel); let dma_channel = Channel::new(dma_channel.map(|ch| ch.degrade()));
internal_init(frequency)?; internal_init(frequency)?;
Ok(Self { Ok(Self {
tx: TxCreatorFullDuplex { tx: TxCreatorFullDuplex {
tx_channel: dma_channel.tx.degrade(), tx_channel: dma_channel.tx,
descriptors: tx_descriptors, descriptors: tx_descriptors,
_guard: tx_guard, _guard: tx_guard,
}, },
rx: RxCreatorFullDuplex { rx: RxCreatorFullDuplex {
rx_channel: dma_channel.rx.degrade(), rx_channel: dma_channel.rx,
descriptors: rx_descriptors, descriptors: rx_descriptors,
_guard: rx_guard, _guard: rx_guard,
}, },
@ -1036,6 +1036,17 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
/// Convert to an async version. /// Convert to an async version.
pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> { pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> {
for core in crate::Cpu::other() {
#[cfg(esp32c6)]
{
crate::interrupt::disable(core, Interrupt::PARL_IO);
}
#[cfg(esp32h2)]
{
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
}
ParlIoFullDuplex { ParlIoFullDuplex {
tx: TxCreatorFullDuplex { tx: TxCreatorFullDuplex {
tx_channel: self.tx.tx_channel.into_async(), tx_channel: self.tx.tx_channel.into_async(),
@ -1115,35 +1126,52 @@ where
pub tx: TxCreator<'d, DM>, pub tx: TxCreator<'d, DM>,
} }
impl<'d, DM> ParlIoTxOnly<'d, DM> impl<'d> ParlIoTxOnly<'d, Blocking> {
where /// Creates a new [ParlIoTxOnly]
DM: Mode,
{
/// Create a new [ParlIoTxOnly]
// TODO: only take a TX DMA channel?
pub fn new<CH>( pub fn new<CH>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = PARL_IO> + 'd,
dma_channel: Channel<'d, DM, CH>, dma_channel: impl Peripheral<P = CH> + 'd,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32, frequency: HertzU32,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>, CH: DmaChannelConvert<TxChannelFor<PARL_IO>>,
{ {
let guard = GenericPeripheralGuard::new(); let guard = GenericPeripheralGuard::new();
let tx_channel = ChannelTx::new(dma_channel.map(|ch| ch.degrade()));
internal_init(frequency)?; internal_init(frequency)?;
Ok(Self { Ok(Self {
tx: TxCreator { tx: TxCreator {
tx_channel: dma_channel.tx.degrade(), tx_channel,
descriptors, descriptors,
_guard: guard, _guard: guard,
}, },
}) })
} }
}
impl ParlIoTxOnly<'_, Blocking> { /// Converts to Async mode.
pub fn into_async(self) -> ParlIoTxOnly<'d, Async> {
for core in crate::Cpu::other() {
#[cfg(esp32c6)]
{
crate::interrupt::disable(core, Interrupt::PARL_IO);
}
#[cfg(esp32h2)]
{
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
}
ParlIoTxOnly {
tx: TxCreator {
tx_channel: self.tx.tx_channel.into_async(),
descriptors: self.tx.descriptors,
_guard: self.tx._guard,
},
}
}
/// Sets the interrupt handler, enables it with /// Sets the interrupt handler, enables it with
/// [crate::interrupt::Priority::min()] /// [crate::interrupt::Priority::min()]
/// ///
@ -1173,6 +1201,19 @@ impl ParlIoTxOnly<'_, Blocking> {
} }
} }
impl<'d> ParlIoTxOnly<'d, Async> {
/// Convert to a blocking version.
pub fn into_blocking(self) -> ParlIoTxOnly<'d, Blocking> {
ParlIoTxOnly {
tx: TxCreator {
tx_channel: self.tx.tx_channel.into_blocking(),
descriptors: self.tx.descriptors,
_guard: self.tx._guard,
},
}
}
}
impl crate::private::Sealed for ParlIoTxOnly<'_, Blocking> {} impl crate::private::Sealed for ParlIoTxOnly<'_, Blocking> {}
impl InterruptConfigurable for ParlIoTxOnly<'_, Blocking> { impl InterruptConfigurable for ParlIoTxOnly<'_, Blocking> {
@ -1191,35 +1232,53 @@ where
pub rx: RxCreator<'d, DM>, pub rx: RxCreator<'d, DM>,
} }
impl<'d, DM> ParlIoRxOnly<'d, DM> impl<'d> ParlIoRxOnly<'d, Blocking> {
where
DM: Mode,
{
/// Create a new [ParlIoRxOnly] instance /// Create a new [ParlIoRxOnly] instance
// TODO: only take a RX DMA channel?
pub fn new<CH>( pub fn new<CH>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = PARL_IO> + 'd,
dma_channel: Channel<'d, DM, CH>, dma_channel: impl Peripheral<P = CH> + 'd,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32, frequency: HertzU32,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>, CH: DmaChannelConvert<RxChannelFor<PARL_IO>>,
{ {
let guard = GenericPeripheralGuard::new(); let guard = GenericPeripheralGuard::new();
let rx_channel = ChannelRx::new(dma_channel.map(|ch| ch.degrade()));
internal_init(frequency)?; internal_init(frequency)?;
Ok(Self { Ok(Self {
rx: RxCreator { rx: RxCreator {
rx_channel: dma_channel.rx.degrade(), rx_channel,
descriptors, descriptors,
_guard: guard, _guard: guard,
}, },
}) })
} }
}
impl ParlIoRxOnly<'_, Blocking> { /// Converts to Async mode.
pub fn into_async(self) -> ParlIoRxOnly<'d, Async> {
for core in crate::Cpu::other() {
#[cfg(esp32c6)]
{
crate::interrupt::disable(core, Interrupt::PARL_IO);
}
#[cfg(esp32h2)]
{
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
}
ParlIoRxOnly {
rx: RxCreator {
rx_channel: self.rx.rx_channel.into_async(),
descriptors: self.rx.descriptors,
_guard: self.rx._guard,
},
}
}
/// Sets the interrupt handler, enables it with /// Sets the interrupt handler, enables it with
/// [crate::interrupt::Priority::min()] /// [crate::interrupt::Priority::min()]
/// ///
@ -1249,6 +1308,19 @@ impl ParlIoRxOnly<'_, Blocking> {
} }
} }
impl<'d> ParlIoRxOnly<'d, Async> {
/// Convert to a blocking version.
pub fn into_blocking(self) -> ParlIoRxOnly<'d, Blocking> {
ParlIoRxOnly {
rx: RxCreator {
rx_channel: self.rx.rx_channel.into_blocking(),
descriptors: self.rx.descriptors,
_guard: self.rx._guard,
},
}
}
}
impl crate::private::Sealed for ParlIoRxOnly<'_, Blocking> {} impl crate::private::Sealed for ParlIoRxOnly<'_, Blocking> {}
impl InterruptConfigurable for ParlIoRxOnly<'_, Blocking> { impl InterruptConfigurable for ParlIoRxOnly<'_, Blocking> {
@ -1361,7 +1433,7 @@ impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
type TX = ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>; type TX = ChannelTx<'d, DM, TxChannelFor<PARL_IO>>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel &mut self.tx_channel
@ -1403,7 +1475,7 @@ where
} }
fn start_receive_bytes_dma( fn start_receive_bytes_dma(
rx_channel: &mut ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>, rx_channel: &mut ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
rx_chain: &mut DescriptorChain, rx_chain: &mut DescriptorChain,
ptr: *mut u8, ptr: *mut u8,
len: usize, len: usize,
@ -1457,7 +1529,7 @@ impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
type RX = ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>; type RX = ChannelRx<'d, DM, RxChannelFor<PARL_IO>>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel &mut self.rx_channel
@ -1473,7 +1545,7 @@ pub struct TxCreator<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, DM, TxChannelFor<PARL_IO>>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
} }
@ -1483,7 +1555,7 @@ pub struct RxCreator<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
} }
@ -1493,7 +1565,7 @@ pub struct TxCreatorFullDuplex<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, DM, TxChannelFor<PARL_IO>>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
} }
@ -1503,7 +1575,7 @@ pub struct RxCreatorFullDuplex<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>, _guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
} }
@ -1529,6 +1601,25 @@ pub mod asynch {
impl TxDoneFuture { impl TxDoneFuture {
pub fn new() -> Self { pub fn new() -> Self {
Instance::listen_tx_done(); Instance::listen_tx_done();
let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
#[cfg(esp32c6)]
{
parl_io.bind_parl_io_interrupt(interrupt_handler.handler());
unwrap!(crate::interrupt::enable(
Interrupt::PARL_IO,
interrupt_handler.priority()
));
}
#[cfg(esp32h2)]
{
parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler());
unwrap!(crate::interrupt::enable(
Interrupt::PARL_IO_TX,
interrupt_handler.priority()
));
}
Self {} Self {}
} }
} }
@ -1540,20 +1631,6 @@ pub mod asynch {
self: core::pin::Pin<&mut Self>, self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>, cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> { ) -> Poll<Self::Output> {
let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
#[cfg(esp32c6)]
{
parl_io.bind_parl_io_interrupt(interrupt_handler.handler());
crate::interrupt::enable(Interrupt::PARL_IO, interrupt_handler.priority()).unwrap();
}
#[cfg(esp32h2)]
{
parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler());
crate::interrupt::enable(Interrupt::PARL_IO_TX, interrupt_handler.priority())
.unwrap();
}
TX_WAKER.register(cx.waker()); TX_WAKER.register(cx.waker());
if Instance::is_listening_tx_done() { if Instance::is_listening_tx_done() {
Poll::Pending Poll::Pending

View File

@ -63,6 +63,18 @@ impl<'a, T> PeripheralRef<'a, T> {
PeripheralRef::new(unsafe { self.inner.clone_unchecked() }) PeripheralRef::new(unsafe { self.inner.clone_unchecked() })
} }
/// Transform the inner peripheral.
///
/// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`,
/// using a user-provided impl to convert from `T` to `U`.
#[inline]
pub fn map<U>(self, transform: impl FnOnce(T) -> U) -> PeripheralRef<'a, U> {
PeripheralRef {
inner: transform(self.inner),
_lifetime: PhantomData,
}
}
/// Map the inner peripheral using `Into`. /// Map the inner peripheral using `Into`.
/// ///
/// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`,
@ -75,10 +87,7 @@ impl<'a, T> PeripheralRef<'a, T> {
where where
T: Into<U>, T: Into<U>,
{ {
PeripheralRef { self.map(Into::into)
inner: self.inner.into(),
_lifetime: PhantomData,
}
} }
} }
@ -179,7 +188,19 @@ pub trait Peripheral: Sized + crate::private::Sealed {
Self::P: Into<U>, Self::P: Into<U>,
U: Peripheral<P = U>, U: Peripheral<P = U>,
{ {
unsafe { self.clone_unchecked().into() } self.map(Into::into)
}
/// Map the peripheral using `Into`.
///
/// This converts from `Peripheral<P = T>` to `Peripheral<P = U>`,
/// using an `Into` impl to convert from `T` to `U`.
#[inline]
fn map<U>(self, transform: impl FnOnce(Self::P) -> U) -> U
where
U: Peripheral<P = U>,
{
transform(unsafe { self.clone_unchecked() })
} }
} }

View File

@ -78,7 +78,7 @@ use procmacros::ram;
use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode}; use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode};
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{Channel, DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx}, dma::{DmaChannelConvert, DmaChannelFor, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal}, gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal},
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
@ -465,26 +465,6 @@ pub struct Spi<'d, M, T = AnySpi> {
guard: PeripheralGuard, guard: PeripheralGuard,
} }
impl<'d, M, T> Spi<'d, M, T>
where
M: Mode,
T: Instance,
{
/// Configures the SPI instance to use DMA with the specified channel.
///
/// This method prepares the SPI instance for DMA transfers using SPI
/// and returns an instance of `SpiDma` that supports DMA
/// operations.
pub fn with_dma<CH, DM>(self, channel: Channel<'d, DM, CH>) -> SpiDma<'d, M, T>
where
CH: DmaChannelConvert<T::Dma>,
DM: Mode,
Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
{
SpiDma::new(self.spi, channel.into())
}
}
impl<M, T> Spi<'_, M, T> impl<M, T> Spi<'_, M, T>
where where
T: Instance, T: Instance,
@ -549,6 +529,23 @@ impl<'d> Spi<'d, Blocking> {
} }
} }
impl<'d, T> Spi<'d, Blocking, T>
where
T: Instance,
{
/// Configures the SPI instance to use DMA with the specified channel.
///
/// This method prepares the SPI instance for DMA transfers using SPI
/// and returns an instance of `SpiDma` that supports DMA
/// operations.
pub fn with_dma<CH>(self, channel: impl Peripheral<P = CH> + 'd) -> SpiDma<'d, Blocking, T>
where
CH: DmaChannelConvert<DmaChannelFor<T>>,
{
SpiDma::new(self.spi, channel.map(|ch| ch.degrade()).into_ref())
}
}
impl<'d> Spi<'d, Async> { impl<'d> Spi<'d, Async> {
/// Converts the SPI instance into blocking mode. /// Converts the SPI instance into blocking mode.
pub fn into_blocking(self) -> Spi<'d, Blocking> { pub fn into_blocking(self) -> Spi<'d, Blocking> {
@ -859,6 +856,7 @@ mod dma {
dma::{ dma::{
asynch::{DmaRxFuture, DmaTxFuture}, asynch::{DmaRxFuture, DmaTxFuture},
Channel, Channel,
DmaChannelFor,
DmaRxBuf, DmaRxBuf,
DmaRxBuffer, DmaRxBuffer,
DmaTxBuf, DmaTxBuf,
@ -885,7 +883,7 @@ mod dma {
M: Mode, M: Mode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<'d, M, T::Dma>, pub(crate) channel: Channel<'d, M, DmaChannelFor<T>>,
tx_transfer_in_progress: bool, tx_transfer_in_progress: bool,
rx_transfer_in_progress: bool, rx_transfer_in_progress: bool,
#[cfg(all(esp32, spi_address_workaround))] #[cfg(all(esp32, spi_address_workaround))]
@ -993,15 +991,15 @@ mod dma {
} }
} }
impl<'d, M, T> SpiDma<'d, M, T> impl<'d, T> SpiDma<'d, Blocking, T>
where where
T: Instance, T: Instance,
M: Mode,
{ {
pub(super) fn new<CH>(spi: PeripheralRef<'d, T>, channel: Channel<'d, M, CH>) -> Self pub(super) fn new(
where spi: PeripheralRef<'d, T>,
CH: DmaChannelConvert<T::Dma>, channel: PeripheralRef<'d, DmaChannelFor<T>>,
{ ) -> Self {
let channel = Channel::new(channel);
channel.runtime_ensure_compatible(&spi); channel.runtime_ensure_compatible(&spi);
#[cfg(all(esp32, spi_address_workaround))] #[cfg(all(esp32, spi_address_workaround))]
let address_buffer = { let address_buffer = {
@ -1027,7 +1025,7 @@ mod dma {
Self { Self {
spi, spi,
channel: channel.degrade(), channel,
#[cfg(all(esp32, spi_address_workaround))] #[cfg(all(esp32, spi_address_workaround))]
address_buffer, address_buffer,
tx_transfer_in_progress: false, tx_transfer_in_progress: false,
@ -1035,7 +1033,13 @@ mod dma {
guard, guard,
} }
} }
}
impl<'d, M, T> SpiDma<'d, M, T>
where
M: Mode,
T: Instance,
{
fn driver(&self) -> &'static Info { fn driver(&self) -> &'static Info {
self.spi.info() self.spi.info()
} }

View File

@ -177,39 +177,44 @@ pub mod dma {
ChannelRx, ChannelRx,
ChannelTx, ChannelTx,
DescriptorChain, DescriptorChain,
DmaChannelFor,
DmaDescriptor, DmaDescriptor,
DmaTransferRx, DmaTransferRx,
DmaTransferRxTx, DmaTransferRxTx,
DmaTransferTx, DmaTransferTx,
ReadBuffer, ReadBuffer,
Rx, Rx,
RxChannelFor,
Tx, Tx,
TxChannelFor,
WriteBuffer, WriteBuffer,
}, },
Mode, Mode,
}; };
impl<'d, M, T> Spi<'d, M, T> impl<'d, T> Spi<'d, Blocking, T>
where where
T: InstanceDma, T: InstanceDma,
M: Mode,
{ {
/// Configures the SPI3 peripheral with the provided DMA channel and /// Configures the SPI peripheral with the provided DMA channel and
/// descriptors. /// descriptors.
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
pub fn with_dma<CH, DM>( pub fn with_dma<CH>(
self, self,
channel: Channel<'d, DM, CH>, channel: impl Peripheral<P = CH> + 'd,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> SpiDma<'d, M, T> ) -> SpiDma<'d, Blocking, T>
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<DmaChannelFor<T>>,
DM: Mode,
Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
{ {
self.spi.info().set_data_mode(self.data_mode, true); self.spi.info().set_data_mode(self.data_mode, true);
SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors) SpiDma::new(
self.spi,
channel.map(|ch| ch.degrade()).into_ref(),
rx_descriptors,
tx_descriptors,
)
} }
} }
@ -220,7 +225,7 @@ pub mod dma {
M: Mode, M: Mode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<'d, M, T::Dma>, pub(crate) channel: Channel<'d, M, DmaChannelFor<T>>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
_guard: PeripheralGuard, _guard: PeripheralGuard,
@ -260,7 +265,7 @@ pub mod dma {
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, DmaMode: Mode,
{ {
type TX = ChannelTx<'d, DmaMode, T::Dma>; type TX = ChannelTx<'d, DmaMode, TxChannelFor<T>>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx &mut self.channel.tx
@ -276,7 +281,7 @@ pub mod dma {
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, DmaMode: Mode,
{ {
type RX = ChannelRx<'d, DmaMode, T::Dma>; type RX = ChannelRx<'d, DmaMode, RxChannelFor<T>>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx &mut self.channel.rx
@ -287,32 +292,35 @@ pub mod dma {
} }
} }
impl<'d, DmaMode, T> SpiDma<'d, DmaMode, T> impl<'d, T> SpiDma<'d, Blocking, T>
where where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode,
{ {
fn new<CH>( fn new(
spi: PeripheralRef<'d, T>, spi: PeripheralRef<'d, T>,
channel: Channel<'d, DmaMode, CH>, channel: PeripheralRef<'d, DmaChannelFor<T>>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self {
where let channel = Channel::new(channel);
CH: DmaChannelConvert<T::Dma>,
{
channel.runtime_ensure_compatible(&spi); channel.runtime_ensure_compatible(&spi);
let guard = PeripheralGuard::new(spi.info().peripheral); let guard = PeripheralGuard::new(spi.info().peripheral);
Self { Self {
spi, spi,
channel: channel.degrade(), channel,
rx_chain: DescriptorChain::new(rx_descriptors), rx_chain: DescriptorChain::new(rx_descriptors),
tx_chain: DescriptorChain::new(tx_descriptors), tx_chain: DescriptorChain::new(tx_descriptors),
_guard: guard, _guard: guard,
} }
} }
}
impl<'d, M, T> SpiDma<'d, M, T>
where
M: Mode,
T: InstanceDma,
{
fn driver(&self) -> DmaDriver { fn driver(&self) -> DmaDriver {
DmaDriver { DmaDriver {
info: self.spi.info(), info: self.spi.info(),

View File

@ -43,13 +43,9 @@ async fn main(_spawner: Spawner) {
); );
let mut rx_clk_pin = NoPin; let mut rx_clk_pin = NoPin;
let parl_io = ParlIoRxOnly::new( let parl_io = ParlIoRxOnly::new(peripherals.PARL_IO, dma.channel0, rx_descriptors, 1.MHz())
peripherals.PARL_IO, .unwrap()
dma.channel0.into_async(), .into_async();
rx_descriptors,
1.MHz(),
)
.unwrap();
let mut parl_io_rx = parl_io let mut parl_io_rx = parl_io
.rx .rx

View File

@ -54,13 +54,9 @@ async fn main(_spawner: Spawner) {
let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, peripherals.GPIO5); let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, peripherals.GPIO5);
let parl_io = ParlIoTxOnly::new( let parl_io = ParlIoTxOnly::new(peripherals.PARL_IO, dma.channel0, tx_descriptors, 1.MHz())
peripherals.PARL_IO, .unwrap()
dma.channel0.into_async(), .into_async();
tx_descriptors,
1.MHz(),
)
.unwrap();
let mut clock_pin = ClkOutPin::new(peripherals.GPIO8); let mut clock_pin = ClkOutPin::new(peripherals.GPIO8);

View File

@ -71,7 +71,7 @@ fn main() -> ! {
.with_scl(peripherals.GPIO48); .with_scl(peripherals.GPIO48);
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);
let channel = dma.channel2; let tx_channel = dma.channel2;
let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
let mut expander = Tca9554::new(i2c); let mut expander = Tca9554::new(i2c);
@ -166,7 +166,7 @@ fn main() -> ! {
config.de_idle_level = Level::Low; config.de_idle_level = Level::Low;
config.disable_black_region = false; config.disable_black_region = false;
let mut dpi = Dpi::new(lcd_cam.lcd, channel.tx, 16.MHz(), config) let mut dpi = Dpi::new(lcd_cam.lcd, tx_channel, 16.MHz(), config)
.with_vsync(vsync_pin) .with_vsync(vsync_pin)
.with_hsync(peripherals.GPIO46) .with_hsync(peripherals.GPIO46)
.with_de(peripherals.GPIO17) .with_de(peripherals.GPIO17)

View File

@ -6,11 +6,10 @@
#![no_main] #![no_main]
use esp_hal::{ use esp_hal::{
dma::{AnyGdmaChannel, Channel, Dma, DmaError, Mem2Mem}, dma::{AnyGdmaChannel, Dma, DmaChannelConvert, DmaError, Mem2Mem},
dma_buffers, dma_buffers,
dma_buffers_chunk_size, dma_buffers_chunk_size,
dma_descriptors, dma_descriptors,
Blocking,
}; };
use hil_test as _; use hil_test as _;
@ -25,7 +24,7 @@ cfg_if::cfg_if! {
} }
struct Context { struct Context {
channel: Channel<'static, Blocking, AnyGdmaChannel>, channel: AnyGdmaChannel,
dma_peripheral: DmaPeripheralType, dma_peripheral: DmaPeripheralType,
} }

View File

@ -122,7 +122,7 @@ mod test {
let mut spi = Spi::new_with_config( let mut spi = Spi::new_with_config(
peripherals.SPI2, peripherals.SPI2,
Config { Config {
frequency: 100.kHz(), frequency: 10000.kHz(),
mode: SpiMode::Mode0, mode: SpiMode::Mode0,
..Config::default() ..Config::default()
}, },
@ -137,7 +137,7 @@ mod test {
let other_peripheral = Spi::new_with_config( let other_peripheral = Spi::new_with_config(
peripherals.SPI3, peripherals.SPI3,
Config { Config {
frequency: 100.kHz(), frequency: 10000.kHz(),
mode: SpiMode::Mode0, mode: SpiMode::Mode0,
..Config::default() ..Config::default()
}, },
@ -205,7 +205,7 @@ mod test {
#[timeout(3)] #[timeout(3)]
async fn dma_does_not_lock_up_on_core_1() { async fn dma_does_not_lock_up_on_core_1() {
use embassy_time::Timer; use embassy_time::Timer;
use esp_hal::{dma::Channel, peripherals::SPI2, Blocking}; use esp_hal::peripherals::SPI2;
use portable_atomic::{AtomicU32, Ordering}; use portable_atomic::{AtomicU32, Ordering};
cfg_if::cfg_if! { cfg_if::cfg_if! {
@ -221,7 +221,7 @@ mod test {
pub struct SpiPeripherals { pub struct SpiPeripherals {
pub spi: SPI2, pub spi: SPI2,
pub dma_channel: Channel<'static, Blocking, DmaChannel>, pub dma_channel: DmaChannel,
} }
#[embassy_executor::task] #[embassy_executor::task]

View File

@ -12,14 +12,13 @@
use esp_hal::{ use esp_hal::{
delay::Delay, delay::Delay,
dma::{Channel, Dma}, dma::Dma,
dma_buffers, dma_buffers,
gpio::{AnyPin, NoPin, Pin}, gpio::{AnyPin, NoPin, Pin},
i2s::master::{DataFormat, I2s, I2sTx, Standard}, i2s::master::{DataFormat, I2s, I2sTx, Standard},
peripherals::I2S0, peripherals::I2S0,
prelude::*, prelude::*,
Async, Async,
Blocking,
}; };
use hil_test as _; use hil_test as _;
@ -105,7 +104,7 @@ mod tests {
struct Context { struct Context {
dout: AnyPin, dout: AnyPin,
dma_channel: Channel<'static, Blocking, DmaChannel0>, dma_channel: DmaChannel0,
i2s: I2S0, i2s: I2S0,
} }

View File

@ -6,7 +6,7 @@
#![no_main] #![no_main]
use esp_hal::{ use esp_hal::{
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma::{Dma, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
gpio::Level, gpio::Level,
lcd_cam::{ lcd_cam::{
@ -58,7 +58,9 @@ mod tests {
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);
let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
let channel = dma.channel2; // TODO: use split channels once supported
let tx_channel = dma.channel2;
let rx_channel = dma.channel3;
let (vsync_in, vsync_out) = peripherals.GPIO6.split(); let (vsync_in, vsync_out) = peripherals.GPIO6.split();
let (hsync_in, hsync_out) = peripherals.GPIO7.split(); let (hsync_in, hsync_out) = peripherals.GPIO7.split();
@ -101,7 +103,7 @@ mod tests {
config.de_idle_level = Level::Low; config.de_idle_level = Level::Low;
config.disable_black_region = false; config.disable_black_region = false;
let dpi = Dpi::new(lcd_cam.lcd, channel.tx, 500u32.kHz(), config) let dpi = Dpi::new(lcd_cam.lcd, tx_channel, 500u32.kHz(), config)
.with_vsync(vsync_out) .with_vsync(vsync_out)
.with_hsync(hsync_out) .with_hsync(hsync_out)
.with_de(de_out) .with_de(de_out)
@ -117,7 +119,7 @@ mod tests {
let camera = Camera::new( let camera = Camera::new(
lcd_cam.cam, lcd_cam.cam,
channel.rx, rx_channel,
RxEightBits::new(d0_in, d1_in, d2_in, d3_in, d4_in, d5_in, d6_in, d7_in), RxEightBits::new(d0_in, d1_in, d2_in, d3_in, d4_in, d5_in, d6_in, d7_in),
1u32.MHz(), 1u32.MHz(),
) )

View File

@ -78,7 +78,7 @@ mod tests {
let i8080 = I8080::new( let i8080 = I8080::new(
ctx.lcd_cam.lcd, ctx.lcd_cam.lcd,
ctx.dma.channel0.tx, ctx.dma.channel0,
pins, pins,
20.MHz(), 20.MHz(),
Config::default(), Config::default(),
@ -141,7 +141,7 @@ mod tests {
let mut i8080 = I8080::new( let mut i8080 = I8080::new(
ctx.lcd_cam.lcd, ctx.lcd_cam.lcd,
ctx.dma.channel0.tx, ctx.dma.channel0,
pins, pins,
20.MHz(), 20.MHz(),
Config::default(), Config::default(),
@ -258,15 +258,9 @@ mod tests {
unit3_signal, unit3_signal,
); );
let mut i8080 = I8080::new( let mut i8080 = I8080::new(ctx.lcd_cam.lcd, channel, pins, 20.MHz(), Config::default())
ctx.lcd_cam.lcd, .with_cs(cs_signal)
channel.tx, .with_ctrl_pins(NoPin, NoPin);
pins,
20.MHz(),
Config::default(),
)
.with_cs(cs_signal)
.with_ctrl_pins(NoPin, NoPin);
// This is to make the test values look more intuitive. // This is to make the test values look more intuitive.
i8080.set_bit_order(BitOrder::Inverted); i8080.set_bit_order(BitOrder::Inverted);

View File

@ -54,7 +54,7 @@ mod tests {
let i8080 = I8080::new( let i8080 = I8080::new(
ctx.lcd_cam.lcd, ctx.lcd_cam.lcd,
ctx.dma.channel0.tx, ctx.dma.channel0,
pins, pins,
20.MHz(), 20.MHz(),
Config::default(), Config::default(),

View File

@ -7,7 +7,7 @@
#[cfg(esp32c6)] #[cfg(esp32c6)]
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
use esp_hal::{ use esp_hal::{
dma::{Channel, Dma, DmaChannel0}, dma::{Dma, DmaChannel0},
gpio::{ gpio::{
interconnect::{InputSignal, OutputSignal}, interconnect::{InputSignal, OutputSignal},
NoPin, NoPin,
@ -27,13 +27,12 @@ use esp_hal::{
}, },
peripherals::PARL_IO, peripherals::PARL_IO,
prelude::*, prelude::*,
Blocking,
}; };
use hil_test as _; use hil_test as _;
struct Context { struct Context {
parl_io: PARL_IO, parl_io: PARL_IO,
dma_channel: Channel<'static, Blocking, DmaChannel0>, dma_channel: DmaChannel0,
clock: OutputSignal, clock: OutputSignal,
valid: OutputSignal, valid: OutputSignal,
clock_loopback: InputSignal, clock_loopback: InputSignal,

View File

@ -9,7 +9,7 @@
#[cfg(esp32c6)] #[cfg(esp32c6)]
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
use esp_hal::{ use esp_hal::{
dma::{Channel, Dma, DmaChannel0}, dma::{Dma, DmaChannel0},
gpio::{ gpio::{
interconnect::{InputSignal, OutputSignal}, interconnect::{InputSignal, OutputSignal},
NoPin, NoPin,
@ -29,13 +29,12 @@ use esp_hal::{
}, },
peripherals::PARL_IO, peripherals::PARL_IO,
prelude::*, prelude::*,
Async,
}; };
use hil_test as _; use hil_test as _;
struct Context { struct Context {
parl_io: PARL_IO, parl_io: PARL_IO,
dma_channel: Channel<'static, Async, DmaChannel0>, dma_channel: DmaChannel0,
clock: OutputSignal, clock: OutputSignal,
valid: OutputSignal, valid: OutputSignal,
clock_loopback: InputSignal, clock_loopback: InputSignal,
@ -61,7 +60,7 @@ mod tests {
let pcnt = Pcnt::new(peripherals.PCNT); let pcnt = Pcnt::new(peripherals.PCNT);
let pcnt_unit = pcnt.unit0; let pcnt_unit = pcnt.unit0;
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);
let dma_channel = dma.channel0.into_async(); let dma_channel = dma.channel0;
let parl_io = peripherals.PARL_IO; let parl_io = peripherals.PARL_IO;
@ -91,8 +90,9 @@ mod tests {
let mut pins = TxPinConfigIncludingValidPin::new(pins); let mut pins = TxPinConfigIncludingValidPin::new(pins);
let mut clock_pin = ClkOutPin::new(ctx.clock); let mut clock_pin = ClkOutPin::new(ctx.clock);
let pio = let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); .unwrap()
.into_async();
let mut pio = pio let mut pio = pio
.tx .tx
@ -152,8 +152,9 @@ mod tests {
let mut clock_pin = ClkOutPin::new(ctx.clock); let mut clock_pin = ClkOutPin::new(ctx.clock);
let pio = let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap(); .unwrap()
.into_async();
let mut pio = pio let mut pio = pio
.tx .tx
@ -166,7 +167,8 @@ mod tests {
) )
.unwrap(); .unwrap();
// use a PCNT unit to count the negitive clock edges only when valid is high // use a PCNT unit to count the negitive clock edges only when
// valid is high
let clock_unit = ctx.pcnt_unit; let clock_unit = ctx.pcnt_unit;
clock_unit.channel0.set_edge_signal(ctx.clock_loopback); clock_unit.channel0.set_edge_signal(ctx.clock_loopback);
clock_unit.channel0.set_ctrl_signal(ctx.valid_loopback); clock_unit.channel0.set_ctrl_signal(ctx.valid_loopback);

View File

@ -8,7 +8,7 @@
#[cfg(pcnt)] #[cfg(pcnt)]
use esp_hal::pcnt::{channel::EdgeMode, unit::Unit, Pcnt}; use esp_hal::pcnt::{channel::EdgeMode, unit::Unit, Pcnt};
use esp_hal::{ use esp_hal::{
dma::{Channel, Dma, DmaRxBuf, DmaTxBuf}, dma::{Dma, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
gpio::{AnyPin, Input, Level, Output, Pull}, gpio::{AnyPin, Input, Level, Output, Pull},
prelude::*, prelude::*,
@ -43,7 +43,7 @@ struct Context {
spi: Spi<'static, Blocking>, spi: Spi<'static, Blocking>,
#[cfg(pcnt)] #[cfg(pcnt)]
pcnt: esp_hal::peripherals::PCNT, pcnt: esp_hal::peripherals::PCNT,
dma_channel: Channel<'static, Blocking, DmaChannel0>, dma_channel: DmaChannel0,
gpios: [AnyPin; 3], gpios: [AnyPin; 3],
} }

View File

@ -12,7 +12,7 @@ use embedded_hal::spi::SpiBus;
#[cfg(pcnt)] #[cfg(pcnt)]
use embedded_hal_async::spi::SpiBus as SpiBusAsync; use embedded_hal_async::spi::SpiBus as SpiBusAsync;
use esp_hal::{ use esp_hal::{
dma::{Channel, Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf}, dma::{Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
gpio::{Level, NoPin}, gpio::{Level, NoPin},
peripheral::Peripheral, peripheral::Peripheral,
@ -37,7 +37,7 @@ cfg_if::cfg_if! {
struct Context { struct Context {
spi: Spi<'static, Blocking>, spi: Spi<'static, Blocking>,
dma_channel: Channel<'static, Blocking, DmaChannel>, dma_channel: DmaChannel,
// Reuse the really large buffer so we don't run out of DRAM with many tests // Reuse the really large buffer so we don't run out of DRAM with many tests
rx_buffer: &'static mut [u8], rx_buffer: &'static mut [u8],
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
@ -424,9 +424,9 @@ mod tests {
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
let mut spi = ctx let mut spi = ctx
.spi .spi
.into_async()
.with_dma(ctx.dma_channel) .with_dma(ctx.dma_channel)
.with_buffers(dma_rx_buf, dma_tx_buf); .with_buffers(dma_rx_buf, dma_tx_buf)
.into_async();
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
ctx.pcnt_unit ctx.pcnt_unit

View File

@ -9,7 +9,7 @@
#![no_main] #![no_main]
use esp_hal::{ use esp_hal::{
dma::{Channel, Dma}, dma::Dma,
dma_buffers, dma_buffers,
gpio::{Input, Level, Output, Pull}, gpio::{Input, Level, Output, Pull},
peripheral::Peripheral, peripheral::Peripheral,
@ -28,7 +28,7 @@ cfg_if::cfg_if! {
struct Context { struct Context {
spi: Spi<'static, Blocking>, spi: Spi<'static, Blocking>,
dma_channel: Channel<'static, Blocking, DmaChannel>, dma_channel: DmaChannel,
bitbang_spi: BitbangSpi, bitbang_spi: BitbangSpi,
} }

View File

@ -69,7 +69,7 @@ fn main() -> ! {
); );
let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
let camera = Camera::new(lcd_cam.cam, dma.channel0.rx, cam_data_pins, 20u32.MHz()) let camera = Camera::new(lcd_cam.cam, dma.channel0, cam_data_pins, 20u32.MHz())
.with_master_clock(cam_xclk) .with_master_clock(cam_xclk)
.with_pixel_clock(cam_pclk) .with_pixel_clock(cam_pclk)
.with_ctrl_pins(cam_vsync, cam_href); .with_ctrl_pins(cam_vsync, cam_href);

View File

@ -71,7 +71,7 @@ fn main() -> ! {
let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
let i8080 = I8080::new( let i8080 = I8080::new(
lcd_cam.lcd, lcd_cam.lcd,
dma.channel0.tx, dma.channel0,
tx_pins, tx_pins,
20.MHz(), 20.MHz(),
Config::default(), Config::default(),