[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
- 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
- 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
### Removed
- 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

View File

@ -15,3 +15,14 @@
-.with_dma(dma_channel.configure(false, DmaPriority::Priority0));
+.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,
DescriptorChain,
DmaChannelConvert,
DmaChannelFor,
DmaDescriptor,
DmaEligible,
DmaPeripheral,
DmaTransferRxTx,
ReadBuffer,
Rx,
RxChannelFor,
Tx,
TxChannelFor,
WriteBuffer,
},
peripheral::Peripheral,
peripherals::AES,
Blocking,
};
@ -278,7 +281,7 @@ pub mod dma {
/// The underlying [`Aes`](super::Aes) driver
pub aes: super::Aes<'d>,
channel: Channel<'d, Blocking, <AES as DmaEligible>::Dma>,
channel: Channel<'d, Blocking, DmaChannelFor<AES>>,
rx_chain: DescriptorChain,
tx_chain: DescriptorChain,
}
@ -287,16 +290,18 @@ pub mod dma {
/// Enable DMA for the current instance of the AES driver
pub fn with_dma<CH>(
self,
channel: Channel<'d, Blocking, CH>,
channel: impl Peripheral<P = CH> + 'd,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> AesDma<'d>
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 {
aes: self,
channel: channel.degrade(),
channel,
rx_chain: DescriptorChain::new(rx_descriptors),
tx_chain: DescriptorChain::new(tx_descriptors),
}
@ -326,7 +331,7 @@ pub mod dma {
}
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 {
&mut self.channel.tx
@ -338,7 +343,7 @@ pub mod dma {
}
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 {
&mut self.channel.rx

View File

@ -16,105 +16,58 @@
use crate::{
dma::*,
peripheral::PeripheralRef,
peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt,
system::{Peripheral, PeripheralClockControl},
Blocking,
system::{self, PeripheralClockControl},
};
#[doc(hidden)]
pub trait GdmaChannel {
fn number(&self) -> u8;
/// An arbitrary GDMA channel
pub struct AnyGdmaChannel(u8);
fn async_handler_out(&self) -> Option<InterruptHandler> {
match self.number() {
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!(),
}
}
impl Peripheral for AnyGdmaChannel {
type P = Self;
fn peripheral_interrupt_out(&self) -> Option<Interrupt> {
match self.number() {
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!(),
}
unsafe fn clone_unchecked(&self) -> Self::P {
Self(self.0)
}
}
/// An arbitrary GDMA channel
#[non_exhaustive]
pub struct AnyGdmaChannel(u8);
impl crate::private::Sealed for AnyGdmaChannel {}
impl DmaChannel for AnyGdmaChannel {
type Rx = ChannelRxImpl<Self>;
type Tx = ChannelTxImpl<Self>;
}
type Rx = AnyGdmaRxChannel;
type Tx = AnyGdmaTxChannel;
#[non_exhaustive]
#[doc(hidden)]
pub struct SpecificGdmaChannel<const N: u8> {}
impl GdmaChannel for AnyGdmaChannel {
fn number(&self) -> u8 {
self.0
fn set_priority(&self, priority: DmaPriority) {
AnyGdmaRxChannel(self.0).set_priority(priority);
AnyGdmaTxChannel(self.0).set_priority(priority);
}
}
impl<const N: u8> GdmaChannel for SpecificGdmaChannel<N> {
fn number(&self) -> u8 {
N
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
(AnyGdmaRxChannel(self.0), AnyGdmaTxChannel(self.0))
}
}
#[non_exhaustive]
#[doc(hidden)]
pub struct ChannelTxImpl<C: GdmaChannel>(C);
/// An arbitrary GDMA RX channel
pub struct AnyGdmaRxChannel(u8);
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;
@ -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)]
fn ch(&self) -> &crate::peripherals::dma::ch::CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize)
dma.ch(self.0 as usize)
}
#[cfg(any(esp32c2, esp32c3))]
#[inline(always)]
fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.int_ch(self.0.number() as usize)
dma.int_ch(self.0 as usize)
}
#[inline(always)]
#[cfg(any(esp32c6, esp32h2))]
fn int(&self) -> &crate::peripherals::dma::out_int_ch::OUT_INT_CH {
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)]
#[inline(always)]
fn int(&self) -> &crate::peripherals::dma::ch::out_int::OUT_INT {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize).out_int()
}
fn degrade(self) -> ChannelTxImpl<AnyGdmaChannel> {
ChannelTxImpl(AnyGdmaChannel(self.0.number()))
dma.ch(self.0 as usize).out_int()
}
}
impl<C: GdmaChannel> RegisterAccess for ChannelTxImpl<C> {
impl RegisterAccess for AnyGdmaTxChannel {
fn reset(&self) {
let conf0 = self.ch().out_conf0();
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) {
self.ch()
.out_conf0()
@ -247,15 +197,37 @@ impl<C: GdmaChannel> TxRegisterAccess for ChannelTxImpl<C> {
}
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> {
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) {
self.int().ena().modify(|_, w| {
for interrupt in interrupts {
@ -325,13 +297,13 @@ impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
}
fn waker(&self) -> &'static AtomicWaker {
&TX_WAKERS[self.0.number() as usize]
&TX_WAKERS[self.0 as usize]
}
fn is_async(&self) -> bool {
cfg_if::cfg_if! {
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 {
true
}
@ -341,52 +313,45 @@ impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
fn set_async(&self, _is_async: bool) {
cfg_if::cfg_if! {
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]
#[doc(hidden)]
pub struct ChannelRxImpl<C: GdmaChannel>(C);
impl crate::private::Sealed for AnyGdmaRxChannel {}
impl DmaRxChannel for AnyGdmaRxChannel {}
impl<C: GdmaChannel> crate::private::Sealed for ChannelRxImpl<C> {}
impl<C: GdmaChannel> ChannelRxImpl<C> {
impl AnyGdmaRxChannel {
#[inline(always)]
fn ch(&self) -> &crate::peripherals::dma::ch::CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize)
dma.ch(self.0 as usize)
}
#[cfg(any(esp32c2, esp32c3))]
#[inline(always)]
fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.int_ch(self.0.number() as usize)
dma.int_ch(self.0 as usize)
}
#[inline(always)]
#[cfg(any(esp32c6, esp32h2))]
fn int(&self) -> &crate::peripherals::dma::in_int_ch::IN_INT_CH {
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)]
#[inline(always)]
fn int(&self) -> &crate::peripherals::dma::ch::in_int::IN_INT {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.ch(self.0.number() as usize).in_int()
}
fn degrade(self) -> ChannelRxImpl<AnyGdmaChannel> {
ChannelRxImpl(AnyGdmaChannel(self.0.number()))
dma.ch(self.0 as usize).in_int()
}
}
impl<C: GdmaChannel> RegisterAccess for ChannelRxImpl<C> {
impl RegisterAccess for AnyGdmaRxChannel {
fn reset(&self) {
let conf0 = self.ch().in_conf0();
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) {
self.ch()
.in_conf0()
@ -461,15 +426,37 @@ impl<C: GdmaChannel> RxRegisterAccess for ChannelRxImpl<C> {
}
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> {
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) {
self.int().ena().modify(|_, w| {
for interrupt in interrupts {
@ -547,13 +534,13 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
}
fn waker(&self) -> &'static AtomicWaker {
&RX_WAKERS[self.0.number() as usize]
&RX_WAKERS[self.0 as usize]
}
fn is_async(&self) -> bool {
cfg_if::cfg_if! {
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 {
true
}
@ -563,7 +550,7 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
fn set_async(&self, _is_async: bool) {
cfg_if::cfg_if! {
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]
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>] {
fn handler_in() -> Option<InterruptHandler> {
@ -604,44 +610,43 @@ macro_rules! impl_channel {
}
impl DmaChannel for [<DmaChannel $num>] {
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>;
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>;
type Rx = AnyGdmaRxChannel;
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>] {
fn degrade_rx(rx: Self::Rx) -> ChannelRxImpl<AnyGdmaChannel> {
rx.degrade()
fn degrade(self) -> AnyGdmaChannel {
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>] {
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
ChannelRxImpl(SpecificGdmaChannel::<$num> {})
AnyGdmaRxChannel($num)
}
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
ChannelTxImpl(SpecificGdmaChannel::<$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
AnyGdmaTxChannel($num)
}
}
}
@ -737,30 +742,28 @@ crate::impl_dma_eligible! {
pub struct Dma<'d> {
_inner: PeripheralRef<'d, crate::peripherals::DMA>,
/// Channel 0
pub channel0: Channel<'d, Blocking, DmaChannel0>,
pub channel0: DmaChannel0,
/// Channel 1
#[cfg(not(esp32c2))]
pub channel1: Channel<'d, Blocking, DmaChannel1>,
pub channel1: DmaChannel1,
/// Channel 2
#[cfg(not(esp32c2))]
pub channel2: Channel<'d, Blocking, DmaChannel2>,
pub channel2: DmaChannel2,
/// Channel 3
#[cfg(esp32s3)]
pub channel3: Channel<'d, Blocking, DmaChannel3>,
pub channel3: DmaChannel3,
/// Channel 4
#[cfg(esp32s3)]
pub channel4: Channel<'d, Blocking, DmaChannel4>,
pub channel4: DmaChannel4,
}
impl<'d> Dma<'d> {
/// Create a DMA instance.
pub fn new(
dma: impl crate::peripheral::Peripheral<P = crate::peripherals::DMA> + 'd,
) -> Dma<'d> {
pub fn new(dma: impl Peripheral<P = crate::peripherals::DMA> + 'd) -> Dma<'d> {
crate::into_ref!(dma);
if PeripheralClockControl::enable(Peripheral::Gdma) {
PeripheralClockControl::reset(Peripheral::Gdma);
if PeripheralClockControl::enable(system::Peripheral::Gdma) {
PeripheralClockControl::reset(system::Peripheral::Gdma);
}
dma.misc_conf().modify(|_, w| w.ahbm_rst_inter().set_bit());
dma.misc_conf()

View File

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

View File

@ -67,6 +67,7 @@ pub use self::m2m::*;
pub use self::pdma::*;
use crate::{
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
peripherals::Interrupt,
soc::is_slice_in_dram,
Async,
@ -943,6 +944,13 @@ pub trait DmaEligible {
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)]
#[macro_export]
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.
pub trait DmaChannel: crate::private::Sealed + Sized {
pub trait DmaChannel: Peripheral<P = Self> {
/// 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.
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)]
@ -1606,18 +1647,13 @@ pub trait DmaChannelExt: DmaChannel {
note = "Not all channels are useable with all peripherals"
)]
#[doc(hidden)]
pub trait DmaChannelConvert<DEG: DmaChannel>: DmaChannel {
fn degrade_rx(rx: Self::Rx) -> DEG::Rx;
fn degrade_tx(tx: Self::Tx) -> DEG::Tx;
pub trait DmaChannelConvert<DEG>: DmaChannel {
fn degrade(self) -> DEG;
}
impl<DEG: DmaChannel> DmaChannelConvert<DEG> for DEG {
fn degrade_rx(rx: Self::Rx) -> DEG::Rx {
rx
}
fn degrade_tx(tx: Self::Tx) -> DEG::Tx {
tx
fn degrade(self) -> DEG {
self
}
}
@ -1683,17 +1719,20 @@ pub trait Rx: crate::private::Sealed {
#[doc(hidden)]
pub struct ChannelRx<'a, M, CH>
where
CH: DmaChannel,
M: Mode,
CH: DmaRxChannel,
{
pub(crate) rx_impl: CH::Rx,
pub(crate) _phantom: PhantomData<(&'a (), CH, M)>,
pub(crate) rx_impl: PeripheralRef<'a, CH>,
pub(crate) _phantom: PhantomData<M>,
}
impl<'a, CH> ChannelRx<'a, Blocking, CH>
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)]
// clear the mem2mem mode to avoid failed DMA if this
// channel was previously used for a mem2mem transfer.
@ -1724,10 +1763,7 @@ where
}
}
fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where
CH: DmaChannel,
{
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.unlisten_in(EnumSet::all());
self.clear_in(EnumSet::all());
@ -1743,7 +1779,7 @@ where
impl<'a, CH> ChannelRx<'a, Async, CH>
where
CH: DmaChannel,
CH: DmaRxChannel,
{
/// Converts an async channel into a blocking channel.
pub(crate) fn into_blocking(self) -> ChannelRx<'a, Blocking, CH> {
@ -1761,20 +1797,8 @@ where
impl<'a, M, CH> ChannelRx<'a, M, CH>
where
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.
#[cfg(gdma)]
pub fn set_priority(&mut self, priority: DmaPriority) {
@ -1806,14 +1830,14 @@ where
impl<M, CH> crate::private::Sealed for ChannelRx<'_, M, CH>
where
M: Mode,
CH: DmaChannel,
CH: DmaRxChannel,
{
}
impl<M, CH> Rx for ChannelRx<'_, M, CH>
where
M: Mode,
CH: DmaChannel,
CH: DmaRxChannel,
{
// TODO: used by I2S, which should be rewritten to use the Preparation-based
// API.
@ -1978,24 +2002,26 @@ pub trait Tx: crate::private::Sealed {
#[doc(hidden)]
pub struct ChannelTx<'a, M, CH>
where
CH: DmaChannel,
M: Mode,
CH: DmaTxChannel,
{
pub(crate) tx_impl: CH::Tx,
pub(crate) _phantom: PhantomData<(&'a (), CH, M)>,
pub(crate) tx_impl: PeripheralRef<'a, CH>,
pub(crate) _phantom: PhantomData<M>,
}
impl<'a, CH> ChannelTx<'a, Blocking, CH>
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() {
for cpu in Cpu::all() {
crate::interrupt::disable(cpu, interrupt);
}
}
tx_impl.set_async(false);
Self {
tx_impl,
_phantom: PhantomData,
@ -2014,10 +2040,7 @@ where
}
}
fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where
CH: DmaChannel,
{
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.unlisten_out(EnumSet::all());
self.clear_out(EnumSet::all());
@ -2033,7 +2056,7 @@ where
impl<'a, CH> ChannelTx<'a, Async, CH>
where
CH: DmaChannel,
CH: DmaTxChannel,
{
/// Converts an async channel into a blocking channel.
pub(crate) fn into_blocking(self) -> ChannelTx<'a, Blocking, CH> {
@ -2051,20 +2074,8 @@ where
impl<'a, M, CH> ChannelTx<'a, M, CH>
where
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.
#[cfg(gdma)]
pub fn set_priority(&mut self, priority: DmaPriority) {
@ -2101,14 +2112,14 @@ where
impl<M, CH> crate::private::Sealed for ChannelTx<'_, M, CH>
where
M: Mode,
CH: DmaChannel,
CH: DmaTxChannel,
{
}
impl<M, CH> Tx for ChannelTx<'_, M, CH>
where
M: Mode,
CH: DmaChannel,
CH: DmaTxChannel,
{
// TODO: used by I2S, which should be rewritten to use the Preparation-based
// API.
@ -2309,28 +2320,38 @@ pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
}
/// DMA Channel
#[non_exhaustive]
pub struct Channel<'d, M, CH>
where
M: Mode,
CH: DmaChannel,
{
/// RX half of the channel
pub rx: ChannelRx<'d, M, CH>,
pub rx: ChannelRx<'d, M, CH::Rx>,
/// 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>
where
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.
///
/// Interrupts are not enabled at the peripheral level here.
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where
CH: DmaChannel,
{
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.rx.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 {
use super::*;

View File

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

View File

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

View File

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

View File

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

View File

@ -61,7 +61,7 @@
//! config.de_idle_level = Level::Low;
//! 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_hsync(peripherals.GPIO46)
//! .with_de(peripherals.GPIO17)
@ -97,6 +97,7 @@
//! ```
use core::{
marker::PhantomData,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
@ -105,7 +106,7 @@ use fugit::HertzU32;
use crate::{
clock::Clocks,
dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx},
dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor},
gpio::{interconnect::PeripheralOutput, Level, OutputSignal},
lcd_cam::{
calculate_clkm,
@ -120,22 +121,27 @@ use crate::{
};
/// Represents the RGB LCD interface.
pub struct Dpi<'d> {
pub struct Dpi<'d, DM: Mode> {
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.
pub fn new<DM: Mode, CH>(
pub fn new<CH>(
lcd: Lcd<'d, DM>,
channel: ChannelTx<'d, Blocking, CH>,
channel: impl Peripheral<P = CH> + 'd,
frequency: HertzU32,
config: Config,
) -> Self
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 clocks = Clocks::get();
@ -270,7 +276,8 @@ impl<'d> Dpi<'d> {
Self {
lcd_cam,
tx_channel: channel.degrade(),
tx_channel,
_mode: PhantomData,
}
}
@ -522,7 +529,7 @@ impl<'d> Dpi<'d> {
mut self,
next_frame_en: bool,
mut buf: TX,
) -> Result<DpiTransfer<'d, TX>, (DmaError, Self, TX)> {
) -> Result<DpiTransfer<'d, TX, DM>, (DmaError, Self, TX)> {
let result = unsafe {
self.tx_channel
.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
/// interface
pub struct DpiTransfer<'d, BUF: DmaTxBuffer> {
dpi: ManuallyDrop<Dpi<'d>>,
pub struct DpiTransfer<'d, BUF: DmaTxBuffer, DM: Mode> {
dpi: ManuallyDrop<Dpi<'d, DM>>,
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.
pub fn is_done(&self) -> bool {
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.
pub fn stop(mut self) -> (Dpi<'d>, BUF) {
pub fn stop(mut self) -> (Dpi<'d, DM>, BUF) {
self.stop_peripherals();
let (dpi, view) = self.release();
(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
/// 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() {
core::hint::spin_loop();
}
@ -611,7 +618,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
(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
// self.buffer_view won't be touched again.
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;
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 {
&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) {
self.stop_peripherals();

View File

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

View File

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

View File

@ -63,6 +63,18 @@ impl<'a, T> PeripheralRef<'a, T> {
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`.
///
/// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`,
@ -75,10 +87,7 @@ impl<'a, T> PeripheralRef<'a, T> {
where
T: Into<U>,
{
PeripheralRef {
inner: self.inner.into(),
_lifetime: PhantomData,
}
self.map(Into::into)
}
}
@ -179,7 +188,19 @@ pub trait Peripheral: Sized + crate::private::Sealed {
Self::P: Into<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 crate::{
clock::Clocks,
dma::{Channel, DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
dma::{DmaChannelConvert, DmaChannelFor, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal},
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
@ -465,26 +465,6 @@ pub struct Spi<'d, M, T = AnySpi> {
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>
where
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> {
/// Converts the SPI instance into blocking mode.
pub fn into_blocking(self) -> Spi<'d, Blocking> {
@ -859,6 +856,7 @@ mod dma {
dma::{
asynch::{DmaRxFuture, DmaTxFuture},
Channel,
DmaChannelFor,
DmaRxBuf,
DmaRxBuffer,
DmaTxBuf,
@ -885,7 +883,7 @@ mod dma {
M: Mode,
{
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,
rx_transfer_in_progress: bool,
#[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
T: Instance,
M: Mode,
{
pub(super) fn new<CH>(spi: PeripheralRef<'d, T>, channel: Channel<'d, M, CH>) -> Self
where
CH: DmaChannelConvert<T::Dma>,
{
pub(super) fn new(
spi: PeripheralRef<'d, T>,
channel: PeripheralRef<'d, DmaChannelFor<T>>,
) -> Self {
let channel = Channel::new(channel);
channel.runtime_ensure_compatible(&spi);
#[cfg(all(esp32, spi_address_workaround))]
let address_buffer = {
@ -1027,7 +1025,7 @@ mod dma {
Self {
spi,
channel: channel.degrade(),
channel,
#[cfg(all(esp32, spi_address_workaround))]
address_buffer,
tx_transfer_in_progress: false,
@ -1035,7 +1033,13 @@ mod dma {
guard,
}
}
}
impl<'d, M, T> SpiDma<'d, M, T>
where
M: Mode,
T: Instance,
{
fn driver(&self) -> &'static Info {
self.spi.info()
}

View File

@ -177,39 +177,44 @@ pub mod dma {
ChannelRx,
ChannelTx,
DescriptorChain,
DmaChannelFor,
DmaDescriptor,
DmaTransferRx,
DmaTransferRxTx,
DmaTransferTx,
ReadBuffer,
Rx,
RxChannelFor,
Tx,
TxChannelFor,
WriteBuffer,
},
Mode,
};
impl<'d, M, T> Spi<'d, M, T>
impl<'d, T> Spi<'d, Blocking, T>
where
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.
#[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,
channel: Channel<'d, DM, CH>,
channel: impl Peripheral<P = CH> + 'd,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> SpiDma<'d, M, T>
) -> SpiDma<'d, Blocking, T>
where
CH: DmaChannelConvert<T::Dma>,
DM: Mode,
Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
CH: DmaChannelConvert<DmaChannelFor<T>>,
{
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,
{
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,
tx_chain: DescriptorChain,
_guard: PeripheralGuard,
@ -260,7 +265,7 @@ pub mod dma {
T: InstanceDma,
DmaMode: Mode,
{
type TX = ChannelTx<'d, DmaMode, T::Dma>;
type TX = ChannelTx<'d, DmaMode, TxChannelFor<T>>;
fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx
@ -276,7 +281,7 @@ pub mod dma {
T: InstanceDma,
DmaMode: Mode,
{
type RX = ChannelRx<'d, DmaMode, T::Dma>;
type RX = ChannelRx<'d, DmaMode, RxChannelFor<T>>;
fn rx(&mut self) -> &mut Self::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
T: InstanceDma,
DmaMode: Mode,
{
fn new<CH>(
fn new(
spi: PeripheralRef<'d, T>,
channel: Channel<'d, DmaMode, CH>,
channel: PeripheralRef<'d, DmaChannelFor<T>>,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> Self
where
CH: DmaChannelConvert<T::Dma>,
{
) -> Self {
let channel = Channel::new(channel);
channel.runtime_ensure_compatible(&spi);
let guard = PeripheralGuard::new(spi.info().peripheral);
Self {
spi,
channel: channel.degrade(),
channel,
rx_chain: DescriptorChain::new(rx_descriptors),
tx_chain: DescriptorChain::new(tx_descriptors),
_guard: guard,
}
}
}
impl<'d, M, T> SpiDma<'d, M, T>
where
M: Mode,
T: InstanceDma,
{
fn driver(&self) -> DmaDriver {
DmaDriver {
info: self.spi.info(),

View File

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

View File

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

View File

@ -71,7 +71,7 @@ fn main() -> ! {
.with_scl(peripherals.GPIO48);
let dma = Dma::new(peripherals.DMA);
let channel = dma.channel2;
let tx_channel = dma.channel2;
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
let mut expander = Tca9554::new(i2c);
@ -166,7 +166,7 @@ fn main() -> ! {
config.de_idle_level = Level::Low;
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_hsync(peripherals.GPIO46)
.with_de(peripherals.GPIO17)

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@
#![no_main]
use esp_hal::{
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma::{Dma, DmaRxBuf, DmaTxBuf},
dma_buffers,
gpio::Level,
lcd_cam::{
@ -58,7 +58,9 @@ mod tests {
let dma = Dma::new(peripherals.DMA);
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 (hsync_in, hsync_out) = peripherals.GPIO7.split();
@ -101,7 +103,7 @@ mod tests {
config.de_idle_level = Level::Low;
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_hsync(hsync_out)
.with_de(de_out)
@ -117,7 +119,7 @@ mod tests {
let camera = Camera::new(
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),
1u32.MHz(),
)

View File

@ -78,7 +78,7 @@ mod tests {
let i8080 = I8080::new(
ctx.lcd_cam.lcd,
ctx.dma.channel0.tx,
ctx.dma.channel0,
pins,
20.MHz(),
Config::default(),
@ -141,7 +141,7 @@ mod tests {
let mut i8080 = I8080::new(
ctx.lcd_cam.lcd,
ctx.dma.channel0.tx,
ctx.dma.channel0,
pins,
20.MHz(),
Config::default(),
@ -258,13 +258,7 @@ mod tests {
unit3_signal,
);
let mut i8080 = I8080::new(
ctx.lcd_cam.lcd,
channel.tx,
pins,
20.MHz(),
Config::default(),
)
let mut i8080 = I8080::new(ctx.lcd_cam.lcd, channel, pins, 20.MHz(), Config::default())
.with_cs(cs_signal)
.with_ctrl_pins(NoPin, NoPin);

View File

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ use embedded_hal::spi::SpiBus;
#[cfg(pcnt)]
use embedded_hal_async::spi::SpiBus as SpiBusAsync;
use esp_hal::{
dma::{Channel, Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf},
dma::{Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf},
dma_buffers,
gpio::{Level, NoPin},
peripheral::Peripheral,
@ -37,7 +37,7 @@ cfg_if::cfg_if! {
struct Context {
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
rx_buffer: &'static mut [u8],
rx_descriptors: &'static mut [DmaDescriptor],
@ -424,9 +424,9 @@ mod tests {
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
let mut spi = ctx
.spi
.into_async()
.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

View File

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

View File

@ -69,7 +69,7 @@ fn main() -> ! {
);
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_pixel_clock(cam_pclk)
.with_ctrl_pins(cam_vsync, cam_href);

View File

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