mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 06:40:47 +00:00
[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:
parent
f81b5f6c7f
commit
3a4a7632b1
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
```
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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::*;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
)
|
)
|
||||||
|
@ -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);
|
||||||
|
@ -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(),
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user