mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-29 21:30:39 +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
|
||||
|
||||
- ESP32-S3: Added SDMMC signals (#2556)
|
||||
- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403)
|
||||
- Added `set_priority` to the `DmaChannel` trait on GDMA devices (#2403, #2526)
|
||||
- Added `into_async` and `into_blocking` functions for `ParlIoTxOnly`, `ParlIoRxOnly` (#2526)
|
||||
- ESP32-C6, H2, S3: Added `split` function to the `DmaChannel` trait. (#2526)
|
||||
|
||||
### Changed
|
||||
|
||||
- DMA channel objects now implement `Peripheral` (#2526)
|
||||
- DMA channel objects are no longer wrapped in `Channel`. The `Channel` drivers are now managed by DMA enabled peripheral drivers. (#2526)
|
||||
- The `Dpi` driver and `DpiTransfer` now have a `Mode` type parameter. The driver's asyncness is determined by the asyncness of the `Lcd` used to create it. (#2526)
|
||||
|
||||
### Fixed
|
||||
|
||||
### Removed
|
||||
|
||||
- The `configure` and `configure_for_async` DMA channel functions has been removed (#2403)
|
||||
- The DMA channel objects no longer have `tx` and `rx` fields. (#2526)
|
||||
|
||||
## [0.22.0] - 2024-11-20
|
||||
|
||||
|
@ -15,3 +15,14 @@
|
||||
-.with_dma(dma_channel.configure(false, DmaPriority::Priority0));
|
||||
+.with_dma(dma_channel);
|
||||
```
|
||||
|
||||
```diff
|
||||
+dma_channel.set_priority(DmaPriority::Priority1);
|
||||
let mut spi = Spi::new_with_config(
|
||||
peripherals.SPI2,
|
||||
Config::default(),
|
||||
)
|
||||
// other setup
|
||||
-.with_dma(dma_channel.configure(false, DmaPriority::Priority1));
|
||||
+.with_dma(dma_channel);
|
||||
```
|
||||
|
@ -242,15 +242,18 @@ pub mod dma {
|
||||
ChannelTx,
|
||||
DescriptorChain,
|
||||
DmaChannelConvert,
|
||||
DmaChannelFor,
|
||||
DmaDescriptor,
|
||||
DmaEligible,
|
||||
DmaPeripheral,
|
||||
DmaTransferRxTx,
|
||||
ReadBuffer,
|
||||
Rx,
|
||||
RxChannelFor,
|
||||
Tx,
|
||||
TxChannelFor,
|
||||
WriteBuffer,
|
||||
},
|
||||
peripheral::Peripheral,
|
||||
peripherals::AES,
|
||||
Blocking,
|
||||
};
|
||||
@ -278,7 +281,7 @@ pub mod dma {
|
||||
/// The underlying [`Aes`](super::Aes) driver
|
||||
pub aes: super::Aes<'d>,
|
||||
|
||||
channel: Channel<'d, Blocking, <AES as DmaEligible>::Dma>,
|
||||
channel: Channel<'d, Blocking, DmaChannelFor<AES>>,
|
||||
rx_chain: DescriptorChain,
|
||||
tx_chain: DescriptorChain,
|
||||
}
|
||||
@ -287,16 +290,18 @@ pub mod dma {
|
||||
/// Enable DMA for the current instance of the AES driver
|
||||
pub fn with_dma<CH>(
|
||||
self,
|
||||
channel: Channel<'d, Blocking, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> AesDma<'d>
|
||||
where
|
||||
CH: DmaChannelConvert<<AES as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<DmaChannelFor<AES>>,
|
||||
{
|
||||
let channel = Channel::new(channel.map(|ch| ch.degrade()));
|
||||
channel.runtime_ensure_compatible(&self.aes);
|
||||
AesDma {
|
||||
aes: self,
|
||||
channel: channel.degrade(),
|
||||
channel,
|
||||
rx_chain: DescriptorChain::new(rx_descriptors),
|
||||
tx_chain: DescriptorChain::new(tx_descriptors),
|
||||
}
|
||||
@ -326,7 +331,7 @@ pub mod dma {
|
||||
}
|
||||
|
||||
impl<'d> DmaSupportTx for AesDma<'d> {
|
||||
type TX = ChannelTx<'d, Blocking, <AES as DmaEligible>::Dma>;
|
||||
type TX = ChannelTx<'d, Blocking, TxChannelFor<AES>>;
|
||||
|
||||
fn tx(&mut self) -> &mut Self::TX {
|
||||
&mut self.channel.tx
|
||||
@ -338,7 +343,7 @@ pub mod dma {
|
||||
}
|
||||
|
||||
impl<'d> DmaSupportRx for AesDma<'d> {
|
||||
type RX = ChannelRx<'d, Blocking, <AES as DmaEligible>::Dma>;
|
||||
type RX = ChannelRx<'d, Blocking, RxChannelFor<AES>>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.channel.rx
|
||||
|
@ -16,105 +16,58 @@
|
||||
|
||||
use crate::{
|
||||
dma::*,
|
||||
peripheral::PeripheralRef,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::Interrupt,
|
||||
system::{Peripheral, PeripheralClockControl},
|
||||
Blocking,
|
||||
system::{self, PeripheralClockControl},
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait GdmaChannel {
|
||||
fn number(&self) -> u8;
|
||||
/// An arbitrary GDMA channel
|
||||
pub struct AnyGdmaChannel(u8);
|
||||
|
||||
fn async_handler_out(&self) -> Option<InterruptHandler> {
|
||||
match self.number() {
|
||||
0 => DmaChannel0::handler_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::handler_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::handler_out(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::handler_out(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::handler_out(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
impl Peripheral for AnyGdmaChannel {
|
||||
type P = Self;
|
||||
|
||||
fn peripheral_interrupt_out(&self) -> Option<Interrupt> {
|
||||
match self.number() {
|
||||
0 => DmaChannel0::isr_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::isr_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::isr_out(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::isr_out(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::isr_out(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn async_handler_in(&self) -> Option<InterruptHandler> {
|
||||
match self.number() {
|
||||
0 => DmaChannel0::handler_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::handler_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::handler_in(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::handler_in(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::handler_in(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn peripheral_interrupt_in(&self) -> Option<Interrupt> {
|
||||
match self.number() {
|
||||
0 => DmaChannel0::isr_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::isr_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::isr_in(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::isr_in(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::isr_in(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// An arbitrary GDMA channel
|
||||
#[non_exhaustive]
|
||||
pub struct AnyGdmaChannel(u8);
|
||||
|
||||
impl crate::private::Sealed for AnyGdmaChannel {}
|
||||
impl DmaChannel for AnyGdmaChannel {
|
||||
type Rx = ChannelRxImpl<Self>;
|
||||
type Tx = ChannelTxImpl<Self>;
|
||||
}
|
||||
type Rx = AnyGdmaRxChannel;
|
||||
type Tx = AnyGdmaTxChannel;
|
||||
|
||||
#[non_exhaustive]
|
||||
#[doc(hidden)]
|
||||
pub struct SpecificGdmaChannel<const N: u8> {}
|
||||
|
||||
impl GdmaChannel for AnyGdmaChannel {
|
||||
fn number(&self) -> u8 {
|
||||
self.0
|
||||
fn set_priority(&self, priority: DmaPriority) {
|
||||
AnyGdmaRxChannel(self.0).set_priority(priority);
|
||||
AnyGdmaTxChannel(self.0).set_priority(priority);
|
||||
}
|
||||
}
|
||||
impl<const N: u8> GdmaChannel for SpecificGdmaChannel<N> {
|
||||
fn number(&self) -> u8 {
|
||||
N
|
||||
|
||||
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
|
||||
(AnyGdmaRxChannel(self.0), AnyGdmaTxChannel(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[doc(hidden)]
|
||||
pub struct ChannelTxImpl<C: GdmaChannel>(C);
|
||||
/// An arbitrary GDMA RX channel
|
||||
pub struct AnyGdmaRxChannel(u8);
|
||||
|
||||
impl Peripheral for AnyGdmaRxChannel {
|
||||
type P = Self;
|
||||
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// An arbitrary GDMA TX channel
|
||||
pub struct AnyGdmaTxChannel(u8);
|
||||
|
||||
impl Peripheral for AnyGdmaTxChannel {
|
||||
type P = Self;
|
||||
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
@ -129,40 +82,37 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GdmaChannel> crate::private::Sealed for ChannelTxImpl<C> {}
|
||||
impl crate::private::Sealed for AnyGdmaTxChannel {}
|
||||
impl DmaTxChannel for AnyGdmaTxChannel {}
|
||||
|
||||
impl<C: GdmaChannel> ChannelTxImpl<C> {
|
||||
impl AnyGdmaTxChannel {
|
||||
#[inline(always)]
|
||||
fn ch(&self) -> &crate::peripherals::dma::ch::CH {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.ch(self.0.number() as usize)
|
||||
dma.ch(self.0 as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(esp32c2, esp32c3))]
|
||||
#[inline(always)]
|
||||
fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.int_ch(self.0.number() as usize)
|
||||
dma.int_ch(self.0 as usize)
|
||||
}
|
||||
#[inline(always)]
|
||||
#[cfg(any(esp32c6, esp32h2))]
|
||||
fn int(&self) -> &crate::peripherals::dma::out_int_ch::OUT_INT_CH {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.out_int_ch(self.0.number() as usize)
|
||||
dma.out_int_ch(self.0 as usize)
|
||||
}
|
||||
#[cfg(esp32s3)]
|
||||
#[inline(always)]
|
||||
fn int(&self) -> &crate::peripherals::dma::ch::out_int::OUT_INT {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.ch(self.0.number() as usize).out_int()
|
||||
}
|
||||
|
||||
fn degrade(self) -> ChannelTxImpl<AnyGdmaChannel> {
|
||||
ChannelTxImpl(AnyGdmaChannel(self.0.number()))
|
||||
dma.ch(self.0 as usize).out_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GdmaChannel> RegisterAccess for ChannelTxImpl<C> {
|
||||
impl RegisterAccess for AnyGdmaTxChannel {
|
||||
fn reset(&self) {
|
||||
let conf0 = self.ch().out_conf0();
|
||||
conf0.modify(|_, w| w.out_rst().set_bit());
|
||||
@ -231,7 +181,7 @@ impl<C: GdmaChannel> RegisterAccess for ChannelTxImpl<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GdmaChannel> TxRegisterAccess for ChannelTxImpl<C> {
|
||||
impl TxRegisterAccess for AnyGdmaTxChannel {
|
||||
fn set_auto_write_back(&self, enable: bool) {
|
||||
self.ch()
|
||||
.out_conf0()
|
||||
@ -247,15 +197,37 @@ impl<C: GdmaChannel> TxRegisterAccess for ChannelTxImpl<C> {
|
||||
}
|
||||
|
||||
fn async_handler(&self) -> Option<InterruptHandler> {
|
||||
self.0.async_handler_out()
|
||||
match self.0 {
|
||||
0 => DmaChannel0::handler_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::handler_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::handler_out(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::handler_out(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::handler_out(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn peripheral_interrupt(&self) -> Option<Interrupt> {
|
||||
self.0.peripheral_interrupt_out()
|
||||
match self.0 {
|
||||
0 => DmaChannel0::isr_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::isr_out(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::isr_out(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::isr_out(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::isr_out(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
|
||||
impl InterruptAccess<DmaTxInterrupt> for AnyGdmaTxChannel {
|
||||
fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
|
||||
self.int().ena().modify(|_, w| {
|
||||
for interrupt in interrupts {
|
||||
@ -325,13 +297,13 @@ impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
|
||||
}
|
||||
|
||||
fn waker(&self) -> &'static AtomicWaker {
|
||||
&TX_WAKERS[self.0.number() as usize]
|
||||
&TX_WAKERS[self.0 as usize]
|
||||
}
|
||||
|
||||
fn is_async(&self) -> bool {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(esp32c2, esp32c3))] {
|
||||
TX_IS_ASYNC[self.0.number() as usize].load(portable_atomic::Ordering::Acquire)
|
||||
TX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -341,52 +313,45 @@ impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
|
||||
fn set_async(&self, _is_async: bool) {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(esp32c2, esp32c3))] {
|
||||
TX_IS_ASYNC[self.0.number() as usize].store(_is_async, portable_atomic::Ordering::Release);
|
||||
TX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[doc(hidden)]
|
||||
pub struct ChannelRxImpl<C: GdmaChannel>(C);
|
||||
impl crate::private::Sealed for AnyGdmaRxChannel {}
|
||||
impl DmaRxChannel for AnyGdmaRxChannel {}
|
||||
|
||||
impl<C: GdmaChannel> crate::private::Sealed for ChannelRxImpl<C> {}
|
||||
|
||||
impl<C: GdmaChannel> ChannelRxImpl<C> {
|
||||
impl AnyGdmaRxChannel {
|
||||
#[inline(always)]
|
||||
fn ch(&self) -> &crate::peripherals::dma::ch::CH {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.ch(self.0.number() as usize)
|
||||
dma.ch(self.0 as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(esp32c2, esp32c3))]
|
||||
#[inline(always)]
|
||||
fn int(&self) -> &crate::peripherals::dma::int_ch::INT_CH {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.int_ch(self.0.number() as usize)
|
||||
dma.int_ch(self.0 as usize)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(any(esp32c6, esp32h2))]
|
||||
fn int(&self) -> &crate::peripherals::dma::in_int_ch::IN_INT_CH {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.in_int_ch(self.0.number() as usize)
|
||||
dma.in_int_ch(self.0 as usize)
|
||||
}
|
||||
|
||||
#[cfg(esp32s3)]
|
||||
#[inline(always)]
|
||||
fn int(&self) -> &crate::peripherals::dma::ch::in_int::IN_INT {
|
||||
let dma = unsafe { &*crate::peripherals::DMA::PTR };
|
||||
dma.ch(self.0.number() as usize).in_int()
|
||||
}
|
||||
|
||||
fn degrade(self) -> ChannelRxImpl<AnyGdmaChannel> {
|
||||
ChannelRxImpl(AnyGdmaChannel(self.0.number()))
|
||||
dma.ch(self.0 as usize).in_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GdmaChannel> RegisterAccess for ChannelRxImpl<C> {
|
||||
impl RegisterAccess for AnyGdmaRxChannel {
|
||||
fn reset(&self) {
|
||||
let conf0 = self.ch().in_conf0();
|
||||
conf0.modify(|_, w| w.in_rst().set_bit());
|
||||
@ -453,7 +418,7 @@ impl<C: GdmaChannel> RegisterAccess for ChannelRxImpl<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GdmaChannel> RxRegisterAccess for ChannelRxImpl<C> {
|
||||
impl RxRegisterAccess for AnyGdmaRxChannel {
|
||||
fn set_mem2mem_mode(&self, value: bool) {
|
||||
self.ch()
|
||||
.in_conf0()
|
||||
@ -461,15 +426,37 @@ impl<C: GdmaChannel> RxRegisterAccess for ChannelRxImpl<C> {
|
||||
}
|
||||
|
||||
fn async_handler(&self) -> Option<InterruptHandler> {
|
||||
self.0.async_handler_in()
|
||||
match self.0 {
|
||||
0 => DmaChannel0::handler_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::handler_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::handler_in(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::handler_in(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::handler_in(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn peripheral_interrupt(&self) -> Option<Interrupt> {
|
||||
self.0.peripheral_interrupt_in()
|
||||
match self.0 {
|
||||
0 => DmaChannel0::isr_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
1 => DmaChannel1::isr_in(),
|
||||
#[cfg(not(esp32c2))]
|
||||
2 => DmaChannel2::isr_in(),
|
||||
#[cfg(esp32s3)]
|
||||
3 => DmaChannel3::isr_in(),
|
||||
#[cfg(esp32s3)]
|
||||
4 => DmaChannel4::isr_in(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
|
||||
impl InterruptAccess<DmaRxInterrupt> for AnyGdmaRxChannel {
|
||||
fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
|
||||
self.int().ena().modify(|_, w| {
|
||||
for interrupt in interrupts {
|
||||
@ -547,13 +534,13 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
|
||||
}
|
||||
|
||||
fn waker(&self) -> &'static AtomicWaker {
|
||||
&RX_WAKERS[self.0.number() as usize]
|
||||
&RX_WAKERS[self.0 as usize]
|
||||
}
|
||||
|
||||
fn is_async(&self) -> bool {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(esp32c2, esp32c3))] {
|
||||
RX_IS_ASYNC[self.0.number() as usize].load(portable_atomic::Ordering::Acquire)
|
||||
RX_IS_ASYNC[self.0 as usize].load(portable_atomic::Ordering::Acquire)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -563,7 +550,7 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
|
||||
fn set_async(&self, _is_async: bool) {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(esp32c2, esp32c3))] {
|
||||
RX_IS_ASYNC[self.0.number() as usize].store(_is_async, portable_atomic::Ordering::Release);
|
||||
RX_IS_ASYNC[self.0 as usize].store(_is_async, portable_atomic::Ordering::Release);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -583,7 +570,26 @@ macro_rules! impl_channel {
|
||||
#[non_exhaustive]
|
||||
pub struct [<DmaChannel $num>] {}
|
||||
|
||||
impl crate::private::Sealed for [<DmaChannel $num>] {}
|
||||
impl $crate::private::Sealed for [<DmaChannel $num>] {}
|
||||
|
||||
impl Peripheral for [<DmaChannel $num>] {
|
||||
type P = Self;
|
||||
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self::steal()
|
||||
}
|
||||
}
|
||||
|
||||
impl [<DmaChannel $num>] {
|
||||
/// Unsafely constructs a new DMA channel.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that only a single instance is used.
|
||||
pub unsafe fn steal() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl [<DmaChannel $num>] {
|
||||
fn handler_in() -> Option<InterruptHandler> {
|
||||
@ -604,44 +610,43 @@ macro_rules! impl_channel {
|
||||
}
|
||||
|
||||
impl DmaChannel for [<DmaChannel $num>] {
|
||||
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>;
|
||||
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>;
|
||||
type Rx = AnyGdmaRxChannel;
|
||||
type Tx = AnyGdmaTxChannel;
|
||||
|
||||
fn set_priority(&self, priority: DmaPriority) {
|
||||
AnyGdmaChannel($num).set_priority(priority);
|
||||
}
|
||||
|
||||
unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
|
||||
(AnyGdmaRxChannel($num), AnyGdmaTxChannel($num))
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
|
||||
fn degrade_rx(rx: Self::Rx) -> ChannelRxImpl<AnyGdmaChannel> {
|
||||
rx.degrade()
|
||||
fn degrade(self) -> AnyGdmaChannel {
|
||||
AnyGdmaChannel($num)
|
||||
}
|
||||
fn degrade_tx(tx: Self::Tx) -> ChannelTxImpl<AnyGdmaChannel> {
|
||||
tx.degrade()
|
||||
}
|
||||
|
||||
impl DmaChannelConvert<AnyGdmaRxChannel> for [<DmaChannel $num>] {
|
||||
fn degrade(self) -> AnyGdmaRxChannel {
|
||||
AnyGdmaRxChannel($num)
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannelConvert<AnyGdmaTxChannel> for [<DmaChannel $num>] {
|
||||
fn degrade(self) -> AnyGdmaTxChannel {
|
||||
AnyGdmaTxChannel($num)
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannelExt for [<DmaChannel $num>] {
|
||||
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
|
||||
ChannelRxImpl(SpecificGdmaChannel::<$num> {})
|
||||
AnyGdmaRxChannel($num)
|
||||
}
|
||||
|
||||
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
||||
ChannelTxImpl(SpecificGdmaChannel::<$num> {})
|
||||
}
|
||||
}
|
||||
|
||||
impl [<DmaChannel $num>] {
|
||||
/// Unsafely constructs a new DMA channel.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that only a single instance is used.
|
||||
pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> {
|
||||
let mut this = Channel {
|
||||
tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})),
|
||||
rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})),
|
||||
};
|
||||
|
||||
this.set_priority(DmaPriority::Priority0);
|
||||
|
||||
this
|
||||
AnyGdmaTxChannel($num)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -737,30 +742,28 @@ crate::impl_dma_eligible! {
|
||||
pub struct Dma<'d> {
|
||||
_inner: PeripheralRef<'d, crate::peripherals::DMA>,
|
||||
/// Channel 0
|
||||
pub channel0: Channel<'d, Blocking, DmaChannel0>,
|
||||
pub channel0: DmaChannel0,
|
||||
/// Channel 1
|
||||
#[cfg(not(esp32c2))]
|
||||
pub channel1: Channel<'d, Blocking, DmaChannel1>,
|
||||
pub channel1: DmaChannel1,
|
||||
/// Channel 2
|
||||
#[cfg(not(esp32c2))]
|
||||
pub channel2: Channel<'d, Blocking, DmaChannel2>,
|
||||
pub channel2: DmaChannel2,
|
||||
/// Channel 3
|
||||
#[cfg(esp32s3)]
|
||||
pub channel3: Channel<'d, Blocking, DmaChannel3>,
|
||||
pub channel3: DmaChannel3,
|
||||
/// Channel 4
|
||||
#[cfg(esp32s3)]
|
||||
pub channel4: Channel<'d, Blocking, DmaChannel4>,
|
||||
pub channel4: DmaChannel4,
|
||||
}
|
||||
|
||||
impl<'d> Dma<'d> {
|
||||
/// Create a DMA instance.
|
||||
pub fn new(
|
||||
dma: impl crate::peripheral::Peripheral<P = crate::peripherals::DMA> + 'd,
|
||||
) -> Dma<'d> {
|
||||
pub fn new(dma: impl Peripheral<P = crate::peripherals::DMA> + 'd) -> Dma<'d> {
|
||||
crate::into_ref!(dma);
|
||||
|
||||
if PeripheralClockControl::enable(Peripheral::Gdma) {
|
||||
PeripheralClockControl::reset(Peripheral::Gdma);
|
||||
if PeripheralClockControl::enable(system::Peripheral::Gdma) {
|
||||
PeripheralClockControl::reset(system::Peripheral::Gdma);
|
||||
}
|
||||
dma.misc_conf().modify(|_, w| w.ahbm_rst_inter().set_bit());
|
||||
dma.misc_conf()
|
||||
|
@ -4,6 +4,7 @@ use crate::{
|
||||
dma::{
|
||||
dma_private::{DmaSupport, DmaSupportRx},
|
||||
AnyGdmaChannel,
|
||||
AnyGdmaRxChannel,
|
||||
Channel,
|
||||
ChannelRx,
|
||||
DescriptorChain,
|
||||
@ -18,6 +19,7 @@ use crate::{
|
||||
Tx,
|
||||
WriteBuffer,
|
||||
},
|
||||
peripheral::Peripheral,
|
||||
Async,
|
||||
Blocking,
|
||||
Mode,
|
||||
@ -40,16 +42,14 @@ where
|
||||
|
||||
impl<'d> Mem2Mem<'d, Blocking> {
|
||||
/// Create a new Mem2Mem instance.
|
||||
pub fn new<CH, DM>(
|
||||
channel: Channel<'d, DM, CH>,
|
||||
pub fn new<CH>(
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
peripheral: impl DmaEligible,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Result<Self, DmaError>
|
||||
where
|
||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||
DM: Mode,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
unsafe {
|
||||
Self::new_unsafe(
|
||||
@ -63,8 +63,8 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
}
|
||||
|
||||
/// Create a new Mem2Mem instance with specific chunk size.
|
||||
pub fn new_with_chunk_size<CH, DM>(
|
||||
channel: Channel<'d, DM, CH>,
|
||||
pub fn new_with_chunk_size<CH>(
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
peripheral: impl DmaEligible,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
@ -72,8 +72,6 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
) -> Result<Self, DmaError>
|
||||
where
|
||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||
DM: Mode,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
unsafe {
|
||||
Self::new_unsafe(
|
||||
@ -92,8 +90,8 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
///
|
||||
/// You must ensure that your not using DMA for the same peripheral and
|
||||
/// that your the only one using the DmaPeripheral.
|
||||
pub unsafe fn new_unsafe<CH, DM>(
|
||||
channel: Channel<'d, DM, CH>,
|
||||
pub unsafe fn new_unsafe<CH>(
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
peripheral: DmaPeripheral,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
@ -101,8 +99,6 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
) -> Result<Self, DmaError>
|
||||
where
|
||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||
DM: Mode,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
if !(1..=4092).contains(&chunk_size) {
|
||||
return Err(DmaError::InvalidChunkSize);
|
||||
@ -111,7 +107,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
return Err(DmaError::OutOfDescriptors);
|
||||
}
|
||||
Ok(Mem2Mem {
|
||||
channel: Channel::<Blocking, _>::from(channel).degrade(),
|
||||
channel: Channel::new(channel.map(|ch| ch.degrade())),
|
||||
peripheral,
|
||||
rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size),
|
||||
tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size),
|
||||
@ -194,7 +190,7 @@ impl<'d, M> DmaSupportRx for Mem2Mem<'d, M>
|
||||
where
|
||||
M: Mode,
|
||||
{
|
||||
type RX = ChannelRx<'d, M, AnyGdmaChannel>;
|
||||
type RX = ChannelRx<'d, M, AnyGdmaRxChannel>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.channel.rx
|
||||
|
@ -67,6 +67,7 @@ pub use self::m2m::*;
|
||||
pub use self::pdma::*;
|
||||
use crate::{
|
||||
interrupt::InterruptHandler,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::Interrupt,
|
||||
soc::is_slice_in_dram,
|
||||
Async,
|
||||
@ -943,6 +944,13 @@ pub trait DmaEligible {
|
||||
fn dma_peripheral(&self) -> DmaPeripheral;
|
||||
}
|
||||
|
||||
/// Helper type to get the DMA (Rx and Tx) channel for a peripheral.
|
||||
pub type DmaChannelFor<T> = <T as DmaEligible>::Dma;
|
||||
/// Helper type to get the DMA Rx channel for a peripheral.
|
||||
pub type RxChannelFor<T> = <DmaChannelFor<T> as DmaChannel>::Rx;
|
||||
/// Helper type to get the DMA Tx channel for a peripheral.
|
||||
pub type TxChannelFor<T> = <DmaChannelFor<T> as DmaChannel>::Tx;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! impl_dma_eligible {
|
||||
@ -1585,13 +1593,46 @@ impl RxCircularState {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait DmaRxChannel:
|
||||
RxRegisterAccess + InterruptAccess<DmaRxInterrupt> + Peripheral<P = Self>
|
||||
{
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait DmaTxChannel:
|
||||
TxRegisterAccess + InterruptAccess<DmaTxInterrupt> + Peripheral<P = Self>
|
||||
{
|
||||
}
|
||||
|
||||
/// A description of a DMA Channel.
|
||||
pub trait DmaChannel: crate::private::Sealed + Sized {
|
||||
pub trait DmaChannel: Peripheral<P = Self> {
|
||||
/// A description of the RX half of a DMA Channel.
|
||||
type Rx: RxRegisterAccess + InterruptAccess<DmaRxInterrupt>;
|
||||
type Rx: DmaRxChannel;
|
||||
|
||||
/// A description of the TX half of a DMA Channel.
|
||||
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>;
|
||||
type Tx: DmaTxChannel;
|
||||
|
||||
/// Sets the priority of the DMA channel.
|
||||
#[cfg(gdma)]
|
||||
fn set_priority(&self, priority: DmaPriority);
|
||||
|
||||
/// Splits the DMA channel into its RX and TX halves.
|
||||
#[cfg(any(esp32c6, esp32h2, esp32s3))] // TODO relax this to allow splitting on all chips
|
||||
fn split(self) -> (Self::Rx, Self::Tx) {
|
||||
// This function is exposed safely on chips that have separate IN and OUT
|
||||
// interrupt handlers.
|
||||
// TODO: this includes the P4 as well.
|
||||
unsafe { self.split_internal(crate::private::Internal) }
|
||||
}
|
||||
|
||||
/// Splits the DMA channel into its RX and TX halves.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function must only be used if the separate halves are used by the
|
||||
/// same peripheral.
|
||||
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -1606,18 +1647,13 @@ pub trait DmaChannelExt: DmaChannel {
|
||||
note = "Not all channels are useable with all peripherals"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub trait DmaChannelConvert<DEG: DmaChannel>: DmaChannel {
|
||||
fn degrade_rx(rx: Self::Rx) -> DEG::Rx;
|
||||
fn degrade_tx(tx: Self::Tx) -> DEG::Tx;
|
||||
pub trait DmaChannelConvert<DEG>: DmaChannel {
|
||||
fn degrade(self) -> DEG;
|
||||
}
|
||||
|
||||
impl<DEG: DmaChannel> DmaChannelConvert<DEG> for DEG {
|
||||
fn degrade_rx(rx: Self::Rx) -> DEG::Rx {
|
||||
rx
|
||||
}
|
||||
|
||||
fn degrade_tx(tx: Self::Tx) -> DEG::Tx {
|
||||
tx
|
||||
fn degrade(self) -> DEG {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@ -1683,17 +1719,20 @@ pub trait Rx: crate::private::Sealed {
|
||||
#[doc(hidden)]
|
||||
pub struct ChannelRx<'a, M, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
M: Mode,
|
||||
CH: DmaRxChannel,
|
||||
{
|
||||
pub(crate) rx_impl: CH::Rx,
|
||||
pub(crate) _phantom: PhantomData<(&'a (), CH, M)>,
|
||||
pub(crate) rx_impl: PeripheralRef<'a, CH>,
|
||||
pub(crate) _phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'a, CH> ChannelRx<'a, Blocking, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
CH: DmaRxChannel,
|
||||
{
|
||||
fn new(rx_impl: CH::Rx) -> Self {
|
||||
/// Creates a new RX channel half.
|
||||
pub fn new(rx_impl: impl Peripheral<P = CH> + 'a) -> Self {
|
||||
crate::into_ref!(rx_impl);
|
||||
#[cfg(gdma)]
|
||||
// clear the mem2mem mode to avoid failed DMA if this
|
||||
// channel was previously used for a mem2mem transfer.
|
||||
@ -1724,10 +1763,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler)
|
||||
where
|
||||
CH: DmaChannel,
|
||||
{
|
||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
self.unlisten_in(EnumSet::all());
|
||||
self.clear_in(EnumSet::all());
|
||||
|
||||
@ -1743,7 +1779,7 @@ where
|
||||
|
||||
impl<'a, CH> ChannelRx<'a, Async, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
CH: DmaRxChannel,
|
||||
{
|
||||
/// Converts an async channel into a blocking channel.
|
||||
pub(crate) fn into_blocking(self) -> ChannelRx<'a, Blocking, CH> {
|
||||
@ -1761,20 +1797,8 @@ where
|
||||
impl<'a, M, CH> ChannelRx<'a, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
CH: DmaRxChannel,
|
||||
{
|
||||
/// Return a less specific (degraded) version of this channel.
|
||||
#[doc(hidden)]
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> ChannelRx<'a, M, DEG>
|
||||
where
|
||||
CH: DmaChannelConvert<DEG>,
|
||||
{
|
||||
ChannelRx {
|
||||
rx_impl: CH::degrade_rx(self.rx_impl),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure the channel.
|
||||
#[cfg(gdma)]
|
||||
pub fn set_priority(&mut self, priority: DmaPriority) {
|
||||
@ -1806,14 +1830,14 @@ where
|
||||
impl<M, CH> crate::private::Sealed for ChannelRx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
CH: DmaRxChannel,
|
||||
{
|
||||
}
|
||||
|
||||
impl<M, CH> Rx for ChannelRx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
CH: DmaRxChannel,
|
||||
{
|
||||
// TODO: used by I2S, which should be rewritten to use the Preparation-based
|
||||
// API.
|
||||
@ -1978,24 +2002,26 @@ pub trait Tx: crate::private::Sealed {
|
||||
#[doc(hidden)]
|
||||
pub struct ChannelTx<'a, M, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
M: Mode,
|
||||
CH: DmaTxChannel,
|
||||
{
|
||||
pub(crate) tx_impl: CH::Tx,
|
||||
pub(crate) _phantom: PhantomData<(&'a (), CH, M)>,
|
||||
pub(crate) tx_impl: PeripheralRef<'a, CH>,
|
||||
pub(crate) _phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'a, CH> ChannelTx<'a, Blocking, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
CH: DmaTxChannel,
|
||||
{
|
||||
fn new(tx_impl: CH::Tx) -> Self {
|
||||
/// Creates a new TX channel half.
|
||||
pub fn new(tx_impl: impl Peripheral<P = CH> + 'a) -> Self {
|
||||
crate::into_ref!(tx_impl);
|
||||
if let Some(interrupt) = tx_impl.peripheral_interrupt() {
|
||||
for cpu in Cpu::all() {
|
||||
crate::interrupt::disable(cpu, interrupt);
|
||||
}
|
||||
}
|
||||
tx_impl.set_async(false);
|
||||
|
||||
Self {
|
||||
tx_impl,
|
||||
_phantom: PhantomData,
|
||||
@ -2014,10 +2040,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler)
|
||||
where
|
||||
CH: DmaChannel,
|
||||
{
|
||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
self.unlisten_out(EnumSet::all());
|
||||
self.clear_out(EnumSet::all());
|
||||
|
||||
@ -2033,7 +2056,7 @@ where
|
||||
|
||||
impl<'a, CH> ChannelTx<'a, Async, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
CH: DmaTxChannel,
|
||||
{
|
||||
/// Converts an async channel into a blocking channel.
|
||||
pub(crate) fn into_blocking(self) -> ChannelTx<'a, Blocking, CH> {
|
||||
@ -2051,20 +2074,8 @@ where
|
||||
impl<'a, M, CH> ChannelTx<'a, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
CH: DmaTxChannel,
|
||||
{
|
||||
/// Return a less specific (degraded) version of this channel.
|
||||
#[doc(hidden)]
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> ChannelTx<'a, M, DEG>
|
||||
where
|
||||
CH: DmaChannelConvert<DEG>,
|
||||
{
|
||||
ChannelTx {
|
||||
tx_impl: CH::degrade_tx(self.tx_impl),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure the channel priority.
|
||||
#[cfg(gdma)]
|
||||
pub fn set_priority(&mut self, priority: DmaPriority) {
|
||||
@ -2101,14 +2112,14 @@ where
|
||||
impl<M, CH> crate::private::Sealed for ChannelTx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
CH: DmaTxChannel,
|
||||
{
|
||||
}
|
||||
|
||||
impl<M, CH> Tx for ChannelTx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
CH: DmaTxChannel,
|
||||
{
|
||||
// TODO: used by I2S, which should be rewritten to use the Preparation-based
|
||||
// API.
|
||||
@ -2309,28 +2320,38 @@ pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
|
||||
}
|
||||
|
||||
/// DMA Channel
|
||||
#[non_exhaustive]
|
||||
pub struct Channel<'d, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
/// RX half of the channel
|
||||
pub rx: ChannelRx<'d, M, CH>,
|
||||
pub rx: ChannelRx<'d, M, CH::Rx>,
|
||||
/// TX half of the channel
|
||||
pub tx: ChannelTx<'d, M, CH>,
|
||||
pub tx: ChannelTx<'d, M, CH::Tx>,
|
||||
}
|
||||
|
||||
impl<'d, CH> Channel<'d, Blocking, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
{
|
||||
pub(crate) fn new(channel: impl Peripheral<P = CH>) -> Self {
|
||||
let (rx, tx) = unsafe {
|
||||
channel
|
||||
.clone_unchecked()
|
||||
.split_internal(crate::private::Internal)
|
||||
};
|
||||
Self {
|
||||
rx: ChannelRx::new(rx),
|
||||
tx: ChannelTx::new(tx),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the interrupt handler for RX and TX interrupts.
|
||||
///
|
||||
/// Interrupts are not enabled at the peripheral level here.
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler)
|
||||
where
|
||||
CH: DmaChannel,
|
||||
{
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
self.rx.set_interrupt_handler(handler);
|
||||
self.tx.set_interrupt_handler(handler);
|
||||
}
|
||||
@ -2418,25 +2439,6 @@ impl<'d, CH: DmaChannel> From<Channel<'d, Async, CH>> for Channel<'d, Blocking,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M, CH> Channel<'d, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
/// Return a less specific (degraded) version of this channel (both rx and
|
||||
/// tx).
|
||||
#[doc(hidden)]
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> Channel<'d, M, DEG>
|
||||
where
|
||||
CH: DmaChannelConvert<DEG>,
|
||||
{
|
||||
Channel {
|
||||
rx: self.rx.degrade(),
|
||||
tx: self.tx.degrade(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod dma_private {
|
||||
use super::*;
|
||||
|
||||
|
@ -16,10 +16,9 @@ use portable_atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::{
|
||||
dma::*,
|
||||
peripheral::PeripheralRef,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::Interrupt,
|
||||
system::{Peripheral, PeripheralClockControl},
|
||||
Blocking,
|
||||
system::{self, PeripheralClockControl},
|
||||
};
|
||||
|
||||
type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock;
|
||||
@ -40,17 +39,33 @@ pub trait PdmaChannel: crate::private::Sealed {
|
||||
fn tx_async_flag(&self) -> &'static AtomicBool;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct SpiDmaRxChannelImpl<C>(C);
|
||||
/// The RX half of an arbitrary SPI DMA channel.
|
||||
pub struct AnySpiDmaRxChannel(AnySpiDmaChannel);
|
||||
|
||||
impl<C> crate::private::Sealed for SpiDmaRxChannelImpl<C> {}
|
||||
impl crate::private::Sealed for AnySpiDmaRxChannel {}
|
||||
impl DmaRxChannel for AnySpiDmaRxChannel {}
|
||||
impl Peripheral for AnySpiDmaRxChannel {
|
||||
type P = Self;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct SpiDmaTxChannelImpl<C>(C);
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self(self.0.clone_unchecked())
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> crate::private::Sealed for SpiDmaTxChannelImpl<C> {}
|
||||
/// The TX half of an arbitrary SPI DMA channel.
|
||||
pub struct AnySpiDmaTxChannel(AnySpiDmaChannel);
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDmaTxChannelImpl<C> {
|
||||
impl crate::private::Sealed for AnySpiDmaTxChannel {}
|
||||
impl DmaTxChannel for AnySpiDmaTxChannel {}
|
||||
impl Peripheral for AnySpiDmaTxChannel {
|
||||
type P = Self;
|
||||
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self(self.0.clone_unchecked())
|
||||
}
|
||||
}
|
||||
|
||||
impl RegisterAccess for AnySpiDmaTxChannel {
|
||||
fn reset(&self) {
|
||||
let spi = self.0.register_block();
|
||||
spi.dma_conf().modify(|_, w| w.out_rst().set_bit());
|
||||
@ -107,7 +122,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDma
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> TxRegisterAccess for SpiDmaTxChannelImpl<C> {
|
||||
impl TxRegisterAccess for AnySpiDmaTxChannel {
|
||||
fn set_auto_write_back(&self, enable: bool) {
|
||||
// there is no `auto_wrback` for SPI
|
||||
assert!(!enable);
|
||||
@ -127,9 +142,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> TxRegisterAccess for SpiD
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaTxInterrupt>
|
||||
for SpiDmaTxChannelImpl<C>
|
||||
{
|
||||
impl InterruptAccess<DmaTxInterrupt> for AnySpiDmaTxChannel {
|
||||
fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
|
||||
let reg_block = self.0.register_block();
|
||||
reg_block.dma_int_ena().modify(|_, w| {
|
||||
@ -215,7 +228,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaTxInte
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDmaRxChannelImpl<C> {
|
||||
impl RegisterAccess for AnySpiDmaRxChannel {
|
||||
fn reset(&self) {
|
||||
let spi = self.0.register_block();
|
||||
spi.dma_conf().modify(|_, w| w.in_rst().set_bit());
|
||||
@ -267,7 +280,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDma
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RxRegisterAccess for SpiDmaRxChannelImpl<C> {
|
||||
impl RxRegisterAccess for AnySpiDmaRxChannel {
|
||||
fn peripheral_interrupt(&self) -> Option<Interrupt> {
|
||||
Some(self.0.peripheral_interrupt())
|
||||
}
|
||||
@ -277,9 +290,7 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RxRegisterAccess for SpiD
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaRxInterrupt>
|
||||
for SpiDmaRxChannelImpl<C>
|
||||
{
|
||||
impl InterruptAccess<DmaRxInterrupt> for AnySpiDmaRxChannel {
|
||||
fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
|
||||
let reg_block = self.0.register_block();
|
||||
reg_block.dma_int_ena().modify(|_, w| {
|
||||
@ -385,17 +396,42 @@ macro_rules! ImplSpiChannel {
|
||||
#[non_exhaustive]
|
||||
pub struct [<Spi $num DmaChannel>] {}
|
||||
|
||||
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
|
||||
|
||||
impl Peripheral for [<Spi $num DmaChannel>] {
|
||||
type P = Self;
|
||||
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self::steal()
|
||||
}
|
||||
}
|
||||
|
||||
impl [<Spi $num DmaChannel>] {
|
||||
/// Unsafely constructs a new DMA channel.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that only a single instance is used.
|
||||
pub unsafe fn steal() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannel for [<Spi $num DmaChannel>] {
|
||||
type Rx = SpiDmaRxChannelImpl<Self>;
|
||||
type Tx = SpiDmaTxChannelImpl<Self>;
|
||||
type Rx = AnySpiDmaRxChannel;
|
||||
type Tx = AnySpiDmaTxChannel;
|
||||
|
||||
unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
|
||||
(AnySpiDmaRxChannel(Self {}.into()), AnySpiDmaTxChannel(Self {}.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannelExt for [<Spi $num DmaChannel>] {
|
||||
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
|
||||
SpiDmaRxChannelImpl(Self {})
|
||||
AnySpiDmaRxChannel(Self {}.into())
|
||||
}
|
||||
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
||||
SpiDmaTxChannelImpl(Self {})
|
||||
AnySpiDmaTxChannel(Self {}.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,7 +439,7 @@ macro_rules! ImplSpiChannel {
|
||||
type RegisterBlock = SpiRegisterBlock;
|
||||
|
||||
fn register_block(&self) -> &SpiRegisterBlock {
|
||||
unsafe { &*crate::peripherals::[<SPI $num>]::PTR }
|
||||
unsafe { &*$crate::peripherals::[<SPI $num>]::PTR }
|
||||
}
|
||||
fn tx_waker(&self) -> &'static AtomicWaker {
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
@ -436,44 +472,53 @@ macro_rules! ImplSpiChannel {
|
||||
}
|
||||
|
||||
impl DmaChannelConvert<AnySpiDmaChannel> for [<Spi $num DmaChannel>] {
|
||||
fn degrade_rx(rx: SpiDmaRxChannelImpl<Self>) -> SpiDmaRxChannelImpl<AnySpiDmaChannelInner> {
|
||||
SpiDmaRxChannelImpl(rx.0.into())
|
||||
}
|
||||
fn degrade_tx(tx: SpiDmaTxChannelImpl<Self>) -> SpiDmaTxChannelImpl<AnySpiDmaChannelInner> {
|
||||
SpiDmaTxChannelImpl(tx.0.into())
|
||||
fn degrade(self) -> AnySpiDmaChannel {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
|
||||
|
||||
impl [<Spi $num DmaChannel>] {
|
||||
/// Unsafely constructs a new DMA channel.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that only a single instance is used.
|
||||
pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> {
|
||||
Channel {
|
||||
tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})),
|
||||
rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})),
|
||||
impl DmaChannelConvert<AnySpiDmaRxChannel> for [<Spi $num DmaChannel>] {
|
||||
fn degrade(self) -> AnySpiDmaRxChannel {
|
||||
AnySpiDmaRxChannel(Self {}.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannelConvert<AnySpiDmaTxChannel> for [<Spi $num DmaChannel>] {
|
||||
fn degrade(self) -> AnySpiDmaTxChannel {
|
||||
AnySpiDmaTxChannel(Self {}.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct I2sDmaRxChannelImpl<C>(C);
|
||||
/// The RX half of an arbitrary I2S DMA channel.
|
||||
pub struct AnyI2sDmaRxChannel(AnyI2sDmaChannel);
|
||||
|
||||
impl<C> crate::private::Sealed for I2sDmaRxChannelImpl<C> {}
|
||||
impl crate::private::Sealed for AnyI2sDmaRxChannel {}
|
||||
impl DmaRxChannel for AnyI2sDmaRxChannel {}
|
||||
impl Peripheral for AnyI2sDmaRxChannel {
|
||||
type P = Self;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct I2sDmaTxChannelImpl<C>(C);
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self(self.0.clone_unchecked())
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> crate::private::Sealed for I2sDmaTxChannelImpl<C> {}
|
||||
/// The TX half of an arbitrary I2S DMA channel.
|
||||
pub struct AnyI2sDmaTxChannel(AnyI2sDmaChannel);
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDmaTxChannelImpl<C> {
|
||||
impl crate::private::Sealed for AnyI2sDmaTxChannel {}
|
||||
impl DmaTxChannel for AnyI2sDmaTxChannel {}
|
||||
impl Peripheral for AnyI2sDmaTxChannel {
|
||||
type P = Self;
|
||||
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self(self.0.clone_unchecked())
|
||||
}
|
||||
}
|
||||
|
||||
impl RegisterAccess for AnyI2sDmaTxChannel {
|
||||
fn reset(&self) {
|
||||
let reg_block = self.0.register_block();
|
||||
reg_block.lc_conf().modify(|_, w| w.out_rst().set_bit());
|
||||
@ -538,7 +583,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDma
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> TxRegisterAccess for I2sDmaTxChannelImpl<C> {
|
||||
impl TxRegisterAccess for AnyI2sDmaTxChannel {
|
||||
fn set_auto_write_back(&self, enable: bool) {
|
||||
let reg_block = self.0.register_block();
|
||||
reg_block
|
||||
@ -564,9 +609,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> TxRegisterAccess for I2sD
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaTxInterrupt>
|
||||
for I2sDmaTxChannelImpl<C>
|
||||
{
|
||||
impl InterruptAccess<DmaTxInterrupt> for AnyI2sDmaTxChannel {
|
||||
fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
|
||||
let reg_block = self.0.register_block();
|
||||
reg_block.int_ena().modify(|_, w| {
|
||||
@ -652,7 +695,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaTxInte
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDmaRxChannelImpl<C> {
|
||||
impl RegisterAccess for AnyI2sDmaRxChannel {
|
||||
fn reset(&self) {
|
||||
let reg_block = self.0.register_block();
|
||||
reg_block.lc_conf().modify(|_, w| w.in_rst().set_bit());
|
||||
@ -710,7 +753,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDma
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RxRegisterAccess for I2sDmaRxChannelImpl<C> {
|
||||
impl RxRegisterAccess for AnyI2sDmaRxChannel {
|
||||
fn peripheral_interrupt(&self) -> Option<Interrupt> {
|
||||
Some(self.0.peripheral_interrupt())
|
||||
}
|
||||
@ -720,9 +763,7 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RxRegisterAccess for I2sD
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaRxInterrupt>
|
||||
for I2sDmaRxChannelImpl<C>
|
||||
{
|
||||
impl InterruptAccess<DmaRxInterrupt> for AnyI2sDmaRxChannel {
|
||||
fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
|
||||
let reg_block = self.0.register_block();
|
||||
reg_block.int_ena().modify(|_, w| {
|
||||
@ -824,17 +865,40 @@ macro_rules! ImplI2sChannel {
|
||||
|
||||
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
|
||||
|
||||
impl Peripheral for [<I2s $num DmaChannel>] {
|
||||
type P = Self;
|
||||
|
||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
||||
Self::steal()
|
||||
}
|
||||
}
|
||||
|
||||
impl [<I2s $num DmaChannel>] {
|
||||
/// Unsafely constructs a new DMA channel.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that only a single instance is used.
|
||||
pub unsafe fn steal() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannel for [<I2s $num DmaChannel>] {
|
||||
type Rx = I2sDmaRxChannelImpl<Self>;
|
||||
type Tx = I2sDmaTxChannelImpl<Self>;
|
||||
type Rx = AnyI2sDmaRxChannel;
|
||||
type Tx = AnyI2sDmaTxChannel;
|
||||
|
||||
unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
|
||||
(AnyI2sDmaRxChannel(Self {}.into()), AnyI2sDmaTxChannel(Self {}.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannelExt for [<I2s $num DmaChannel>] {
|
||||
fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
|
||||
I2sDmaRxChannelImpl(Self {})
|
||||
AnyI2sDmaRxChannel(Self {}.into())
|
||||
}
|
||||
fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
||||
I2sDmaTxChannelImpl(Self {})
|
||||
AnyI2sDmaTxChannel(Self {}.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -874,26 +938,21 @@ macro_rules! ImplI2sChannel {
|
||||
}
|
||||
|
||||
impl DmaChannelConvert<AnyI2sDmaChannel> for [<I2s $num DmaChannel>] {
|
||||
fn degrade_rx(rx: I2sDmaRxChannelImpl<Self>) -> I2sDmaRxChannelImpl<AnyI2sDmaChannelInner> {
|
||||
I2sDmaRxChannelImpl(rx.0.into())
|
||||
}
|
||||
fn degrade_tx(tx: I2sDmaTxChannelImpl<Self>) -> I2sDmaTxChannelImpl<AnyI2sDmaChannelInner> {
|
||||
I2sDmaTxChannelImpl(tx.0.into())
|
||||
fn degrade(self) -> AnyI2sDmaChannel {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl [<I2s $num DmaChannel>] {
|
||||
/// Unsafely constructs a new DMA channel.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that only a single instance is used.
|
||||
pub unsafe fn steal<'a>() -> Channel<'a, Blocking, Self> {
|
||||
Channel {
|
||||
tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})),
|
||||
rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})),
|
||||
impl DmaChannelConvert<AnyI2sDmaRxChannel> for [<I2s $num DmaChannel>] {
|
||||
fn degrade(self) -> AnyI2sDmaRxChannel {
|
||||
AnyI2sDmaRxChannel(Self {}.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl DmaChannelConvert<AnyI2sDmaTxChannel> for [<I2s $num DmaChannel>] {
|
||||
fn degrade(self) -> AnyI2sDmaTxChannel {
|
||||
AnyI2sDmaTxChannel(Self {}.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -921,23 +980,21 @@ crate::impl_dma_eligible!([I2s1DmaChannel] I2S1 => I2s1);
|
||||
pub struct Dma<'d> {
|
||||
_inner: PeripheralRef<'d, crate::peripherals::DMA>,
|
||||
/// DMA channel for SPI2
|
||||
pub spi2channel: Channel<'d, Blocking, Spi2DmaChannel>,
|
||||
pub spi2channel: Spi2DmaChannel,
|
||||
/// DMA channel for SPI3
|
||||
pub spi3channel: Channel<'d, Blocking, Spi3DmaChannel>,
|
||||
pub spi3channel: Spi3DmaChannel,
|
||||
/// DMA channel for I2S0
|
||||
pub i2s0channel: Channel<'d, Blocking, I2s0DmaChannel>,
|
||||
pub i2s0channel: I2s0DmaChannel,
|
||||
/// DMA channel for I2S1
|
||||
#[cfg(i2s1)]
|
||||
pub i2s1channel: Channel<'d, Blocking, I2s1DmaChannel>,
|
||||
pub i2s1channel: I2s1DmaChannel,
|
||||
}
|
||||
|
||||
impl<'d> Dma<'d> {
|
||||
/// Create a DMA instance.
|
||||
pub fn new(
|
||||
dma: impl crate::peripheral::Peripheral<P = crate::peripherals::DMA> + 'd,
|
||||
) -> Dma<'d> {
|
||||
if PeripheralClockControl::enable(Peripheral::Dma) {
|
||||
PeripheralClockControl::reset(Peripheral::Dma);
|
||||
pub fn new(dma: impl Peripheral<P = crate::peripherals::DMA> + 'd) -> Dma<'d> {
|
||||
if PeripheralClockControl::enable(system::Peripheral::Dma) {
|
||||
PeripheralClockControl::reset(system::Peripheral::Dma);
|
||||
}
|
||||
|
||||
#[cfg(esp32)]
|
||||
@ -983,31 +1040,31 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker for SPI-compatible type-erased DMA channels.
|
||||
pub struct AnySpiDmaChannel;
|
||||
|
||||
impl crate::private::Sealed for AnySpiDmaChannel {}
|
||||
|
||||
impl DmaChannel for AnySpiDmaChannel {
|
||||
type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>;
|
||||
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
|
||||
}
|
||||
|
||||
crate::any_enum! {
|
||||
#[doc(hidden)]
|
||||
pub enum AnySpiDmaChannelInner {
|
||||
crate::any_peripheral! {
|
||||
/// An SPI-compatible type-erased DMA channel.
|
||||
pub peripheral AnySpiDmaChannel {
|
||||
Spi2(Spi2DmaChannel),
|
||||
Spi3(Spi3DmaChannel),
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::private::Sealed for AnySpiDmaChannelInner {}
|
||||
impl DmaChannel for AnySpiDmaChannel {
|
||||
type Rx = AnySpiDmaRxChannel;
|
||||
type Tx = AnySpiDmaTxChannel;
|
||||
|
||||
impl PdmaChannel for AnySpiDmaChannelInner {
|
||||
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
|
||||
(
|
||||
AnySpiDmaRxChannel(unsafe { self.clone_unchecked() }),
|
||||
AnySpiDmaTxChannel(unsafe { self.clone_unchecked() }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PdmaChannel for AnySpiDmaChannel {
|
||||
type RegisterBlock = SpiRegisterBlock;
|
||||
|
||||
delegate::delegate! {
|
||||
to match self {
|
||||
to match &self.0 {
|
||||
AnySpiDmaChannelInner::Spi2(channel) => channel,
|
||||
AnySpiDmaChannelInner::Spi3(channel) => channel,
|
||||
} {
|
||||
@ -1023,32 +1080,32 @@ impl PdmaChannel for AnySpiDmaChannelInner {
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker for I2S-compatible type-erased DMA channels.
|
||||
pub struct AnyI2sDmaChannel;
|
||||
|
||||
impl crate::private::Sealed for AnyI2sDmaChannel {}
|
||||
|
||||
impl DmaChannel for AnyI2sDmaChannel {
|
||||
type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>;
|
||||
type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>;
|
||||
}
|
||||
|
||||
crate::any_enum! {
|
||||
#[doc(hidden)]
|
||||
pub enum AnyI2sDmaChannelInner {
|
||||
crate::any_peripheral! {
|
||||
/// An I2S-compatible type-erased DMA channel.
|
||||
pub peripheral AnyI2sDmaChannel {
|
||||
I2s0(I2s0DmaChannel),
|
||||
#[cfg(i2s1)]
|
||||
I2s1(I2s1DmaChannel),
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::private::Sealed for AnyI2sDmaChannelInner {}
|
||||
impl DmaChannel for AnyI2sDmaChannel {
|
||||
type Rx = AnyI2sDmaRxChannel;
|
||||
type Tx = AnyI2sDmaTxChannel;
|
||||
|
||||
impl PdmaChannel for AnyI2sDmaChannelInner {
|
||||
unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
|
||||
(
|
||||
AnyI2sDmaRxChannel(unsafe { self.clone_unchecked() }),
|
||||
AnyI2sDmaTxChannel(unsafe { self.clone_unchecked() }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PdmaChannel for AnyI2sDmaChannel {
|
||||
type RegisterBlock = I2sRegisterBlock;
|
||||
|
||||
delegate::delegate! {
|
||||
to match self {
|
||||
to match &self.0 {
|
||||
AnyI2sDmaChannelInner::I2s0(channel) => channel,
|
||||
#[cfg(i2s1)]
|
||||
AnyI2sDmaChannelInner::I2s1(channel) => channel,
|
||||
|
@ -82,6 +82,7 @@ use crate::{
|
||||
ChannelTx,
|
||||
DescriptorChain,
|
||||
DmaChannelConvert,
|
||||
DmaChannelFor,
|
||||
DmaDescriptor,
|
||||
DmaEligible,
|
||||
DmaError,
|
||||
@ -91,7 +92,9 @@ use crate::{
|
||||
DmaTransferTxCircular,
|
||||
ReadBuffer,
|
||||
Rx,
|
||||
RxChannelFor,
|
||||
Tx,
|
||||
TxChannelFor,
|
||||
WriteBuffer,
|
||||
},
|
||||
gpio::interconnect::PeripheralOutput,
|
||||
@ -258,24 +261,21 @@ where
|
||||
pub i2s_tx: TxCreator<'d, M, T>,
|
||||
}
|
||||
|
||||
impl<'d, DmaMode, T> I2s<'d, DmaMode, T>
|
||||
impl<'d, T> I2s<'d, Blocking, T>
|
||||
where
|
||||
T: RegisterAccess,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new_internal<CH>(
|
||||
fn new_internal(
|
||||
i2s: PeripheralRef<'d, T>,
|
||||
standard: Standard,
|
||||
data_format: DataFormat,
|
||||
sample_rate: impl Into<fugit::HertzU32>,
|
||||
channel: Channel<'d, DmaMode, CH>,
|
||||
channel: PeripheralRef<'d, DmaChannelFor<T>>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
{
|
||||
) -> Self {
|
||||
let channel = Channel::new(channel);
|
||||
channel.runtime_ensure_compatible(&i2s);
|
||||
// on ESP32-C3 / ESP32-S3 and later RX and TX are independent and
|
||||
// could be configured totally independently but for now handle all
|
||||
@ -291,7 +291,6 @@ where
|
||||
i2s.set_master();
|
||||
i2s.update();
|
||||
|
||||
let channel = channel.degrade();
|
||||
Self {
|
||||
i2s_rx: RxCreator {
|
||||
i2s: unsafe { i2s.clone_unchecked() },
|
||||
@ -368,19 +367,17 @@ impl<'d> I2s<'d, Blocking> {
|
||||
/// Construct a new I2S peripheral driver instance for the first I2S
|
||||
/// peripheral
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new<CH, DM>(
|
||||
pub fn new<CH>(
|
||||
i2s: impl Peripheral<P = impl RegisterAccess> + 'd,
|
||||
standard: Standard,
|
||||
data_format: DataFormat,
|
||||
sample_rate: impl Into<fugit::HertzU32>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
|
||||
DM: Mode,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
CH: DmaChannelConvert<DmaChannelFor<AnyI2s>>,
|
||||
{
|
||||
Self::new_typed(
|
||||
i2s.map_into(),
|
||||
@ -401,19 +398,17 @@ where
|
||||
/// Construct a new I2S peripheral driver instance for the first I2S
|
||||
/// peripheral
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new_typed<CH, DM>(
|
||||
pub fn new_typed<CH>(
|
||||
i2s: impl Peripheral<P = T> + 'd,
|
||||
standard: Standard,
|
||||
data_format: DataFormat,
|
||||
sample_rate: impl Into<fugit::HertzU32>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
DM: Mode,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
CH: DmaChannelConvert<DmaChannelFor<T>>,
|
||||
{
|
||||
crate::into_ref!(i2s);
|
||||
Self::new_internal(
|
||||
@ -421,7 +416,7 @@ where
|
||||
standard,
|
||||
data_format,
|
||||
sample_rate,
|
||||
channel.into(),
|
||||
channel.map(|ch| ch.degrade()).into_ref(),
|
||||
rx_descriptors,
|
||||
tx_descriptors,
|
||||
)
|
||||
@ -465,9 +460,10 @@ where
|
||||
pub struct I2sTx<'d, DmaMode, T = AnyI2s>
|
||||
where
|
||||
T: RegisterAccess,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
i2s: PeripheralRef<'d, T>,
|
||||
tx_channel: ChannelTx<'d, DmaMode, T::Dma>,
|
||||
tx_channel: ChannelTx<'d, DmaMode, TxChannelFor<T>>,
|
||||
tx_chain: DescriptorChain,
|
||||
_guard: PeripheralGuard,
|
||||
}
|
||||
@ -501,7 +497,7 @@ where
|
||||
T: RegisterAccess,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type TX = ChannelTx<'d, DmaMode, T::Dma>;
|
||||
type TX = ChannelTx<'d, DmaMode, TxChannelFor<T>>;
|
||||
|
||||
fn tx(&mut self) -> &mut Self::TX {
|
||||
&mut self.tx_channel
|
||||
@ -600,7 +596,7 @@ where
|
||||
DmaMode: Mode,
|
||||
{
|
||||
i2s: PeripheralRef<'d, T>,
|
||||
rx_channel: ChannelRx<'d, DmaMode, T::Dma>,
|
||||
rx_channel: ChannelRx<'d, DmaMode, RxChannelFor<T>>,
|
||||
rx_chain: DescriptorChain,
|
||||
_guard: PeripheralGuard,
|
||||
}
|
||||
@ -634,7 +630,7 @@ where
|
||||
T: RegisterAccess,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type RX = ChannelRx<'d, DmaMode, T::Dma>;
|
||||
type RX = ChannelRx<'d, DmaMode, RxChannelFor<T>>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.rx_channel
|
||||
@ -743,16 +739,7 @@ mod private {
|
||||
use enumset::EnumSet;
|
||||
use fugit::HertzU32;
|
||||
|
||||
use super::{
|
||||
DataFormat,
|
||||
I2sInterrupt,
|
||||
I2sRx,
|
||||
I2sTx,
|
||||
PeripheralGuard,
|
||||
RegisterAccess,
|
||||
Standard,
|
||||
I2S_LL_MCLK_DIVIDER_MAX,
|
||||
};
|
||||
use super::*;
|
||||
#[cfg(not(i2s1))]
|
||||
use crate::peripherals::i2s0::RegisterBlock;
|
||||
// on ESP32-S3 I2S1 doesn't support all features - use that to avoid using those features
|
||||
@ -779,7 +766,7 @@ mod private {
|
||||
M: Mode,
|
||||
{
|
||||
pub i2s: PeripheralRef<'d, T>,
|
||||
pub tx_channel: ChannelTx<'d, M, T::Dma>,
|
||||
pub tx_channel: ChannelTx<'d, M, TxChannelFor<T>>,
|
||||
pub descriptors: &'static mut [DmaDescriptor],
|
||||
pub(crate) guard: PeripheralGuard,
|
||||
}
|
||||
@ -839,7 +826,7 @@ mod private {
|
||||
M: Mode,
|
||||
{
|
||||
pub i2s: PeripheralRef<'d, T>,
|
||||
pub rx_channel: ChannelRx<'d, M, T::Dma>,
|
||||
pub rx_channel: ChannelRx<'d, M, RxChannelFor<T>>,
|
||||
pub descriptors: &'static mut [DmaDescriptor],
|
||||
pub(crate) guard: PeripheralGuard,
|
||||
}
|
||||
|
@ -47,11 +47,13 @@ use crate::{
|
||||
Channel,
|
||||
ChannelTx,
|
||||
DmaChannelConvert,
|
||||
DmaChannelFor,
|
||||
DmaEligible,
|
||||
DmaError,
|
||||
DmaPeripheral,
|
||||
DmaTxBuffer,
|
||||
Tx,
|
||||
TxChannelFor,
|
||||
},
|
||||
gpio::{
|
||||
interconnect::{OutputConnection, PeripheralOutput},
|
||||
@ -177,7 +179,7 @@ where
|
||||
I: Instance,
|
||||
{
|
||||
instance: PeripheralRef<'d, I>,
|
||||
tx_channel: ChannelTx<'d, DM, I::Dma>,
|
||||
tx_channel: ChannelTx<'d, DM, TxChannelFor<I>>,
|
||||
_guard: PeripheralGuard,
|
||||
}
|
||||
|
||||
@ -185,13 +187,13 @@ impl<'d> I2sParallel<'d, Blocking> {
|
||||
/// Create a new I2S Parallel Interface
|
||||
pub fn new<CH>(
|
||||
i2s: impl Peripheral<P = impl Instance> + 'd,
|
||||
channel: Channel<'d, Blocking, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
frequency: impl Into<fugit::HertzU32>,
|
||||
pins: impl TxPins<'d>,
|
||||
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<DmaChannelFor<AnyI2s>>,
|
||||
{
|
||||
Self::new_typed(i2s.map_into(), channel, frequency, pins, clock_pin)
|
||||
}
|
||||
@ -204,19 +206,19 @@ where
|
||||
/// Create a new I2S Parallel Interface
|
||||
pub fn new_typed<CH>(
|
||||
i2s: impl Peripheral<P = I> + 'd,
|
||||
channel: Channel<'d, Blocking, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
frequency: impl Into<fugit::HertzU32>,
|
||||
mut pins: impl TxPins<'d>,
|
||||
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<I::Dma>,
|
||||
CH: DmaChannelConvert<DmaChannelFor<I>>,
|
||||
{
|
||||
crate::into_ref!(i2s);
|
||||
crate::into_mapped_ref!(clock_pin);
|
||||
|
||||
let channel = Channel::new(channel.map(|ch| ch.degrade()));
|
||||
channel.runtime_ensure_compatible(&i2s);
|
||||
let channel = channel.degrade();
|
||||
|
||||
let guard = PeripheralGuard::new(i2s.peripheral());
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
||||
//! let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
|
||||
//! let mut camera = Camera::new(
|
||||
//! lcd_cam.cam,
|
||||
//! channel.rx,
|
||||
//! channel,
|
||||
//! data_pins,
|
||||
//! 20u32.MHz(),
|
||||
//! )
|
||||
@ -67,7 +67,7 @@ use fugit::HertzU32;
|
||||
|
||||
use crate::{
|
||||
clock::Clocks,
|
||||
dma::{ChannelRx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaRxBuffer, Rx},
|
||||
dma::{ChannelRx, DmaChannelConvert, DmaError, DmaPeripheral, DmaRxBuffer, Rx, RxChannelFor},
|
||||
gpio::{
|
||||
interconnect::{PeripheralInput, PeripheralOutput},
|
||||
InputSignal,
|
||||
@ -123,7 +123,7 @@ pub struct Cam<'d> {
|
||||
/// Represents the camera interface with DMA support.
|
||||
pub struct Camera<'d> {
|
||||
lcd_cam: PeripheralRef<'d, LCD_CAM>,
|
||||
rx_channel: ChannelRx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>,
|
||||
rx_channel: ChannelRx<'d, Blocking, RxChannelFor<LCD_CAM>>,
|
||||
_guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>,
|
||||
}
|
||||
|
||||
@ -131,14 +131,15 @@ impl<'d> Camera<'d> {
|
||||
/// Creates a new `Camera` instance with DMA support.
|
||||
pub fn new<P, CH>(
|
||||
cam: Cam<'d>,
|
||||
channel: ChannelRx<'d, Blocking, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
_pins: P,
|
||||
frequency: HertzU32,
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<<LCD_CAM as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<RxChannelFor<LCD_CAM>>,
|
||||
P: RxPins,
|
||||
{
|
||||
let rx_channel = ChannelRx::new(channel.map(|ch| ch.degrade()));
|
||||
let lcd_cam = cam.lcd_cam;
|
||||
|
||||
let clocks = Clocks::get();
|
||||
@ -184,7 +185,7 @@ impl<'d> Camera<'d> {
|
||||
|
||||
Self {
|
||||
lcd_cam,
|
||||
rx_channel: channel.degrade(),
|
||||
rx_channel,
|
||||
_guard: cam._guard,
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@
|
||||
//! config.de_idle_level = Level::Low;
|
||||
//! config.disable_black_region = false;
|
||||
//!
|
||||
//! let mut dpi = Dpi::new(lcd_cam.lcd, channel.tx, 1.MHz(), config)
|
||||
//! let mut dpi = Dpi::new(lcd_cam.lcd, channel, 1.MHz(), config)
|
||||
//! .with_vsync(peripherals.GPIO3)
|
||||
//! .with_hsync(peripherals.GPIO46)
|
||||
//! .with_de(peripherals.GPIO17)
|
||||
@ -97,6 +97,7 @@
|
||||
//! ```
|
||||
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
mem::ManuallyDrop,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
@ -105,7 +106,7 @@ use fugit::HertzU32;
|
||||
|
||||
use crate::{
|
||||
clock::Clocks,
|
||||
dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx},
|
||||
dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor},
|
||||
gpio::{interconnect::PeripheralOutput, Level, OutputSignal},
|
||||
lcd_cam::{
|
||||
calculate_clkm,
|
||||
@ -120,22 +121,27 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Represents the RGB LCD interface.
|
||||
pub struct Dpi<'d> {
|
||||
pub struct Dpi<'d, DM: Mode> {
|
||||
lcd_cam: PeripheralRef<'d, LCD_CAM>,
|
||||
tx_channel: ChannelTx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>,
|
||||
tx_channel: ChannelTx<'d, Blocking, TxChannelFor<LCD_CAM>>,
|
||||
_mode: PhantomData<DM>,
|
||||
}
|
||||
|
||||
impl<'d> Dpi<'d> {
|
||||
impl<'d, DM> Dpi<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Create a new instance of the RGB/DPI driver.
|
||||
pub fn new<DM: Mode, CH>(
|
||||
pub fn new<CH>(
|
||||
lcd: Lcd<'d, DM>,
|
||||
channel: ChannelTx<'d, Blocking, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
frequency: HertzU32,
|
||||
config: Config,
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<<LCD_CAM as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<TxChannelFor<LCD_CAM>>,
|
||||
{
|
||||
let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade()));
|
||||
let lcd_cam = lcd.lcd_cam;
|
||||
|
||||
let clocks = Clocks::get();
|
||||
@ -270,7 +276,8 @@ impl<'d> Dpi<'d> {
|
||||
|
||||
Self {
|
||||
lcd_cam,
|
||||
tx_channel: channel.degrade(),
|
||||
tx_channel,
|
||||
_mode: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,7 +529,7 @@ impl<'d> Dpi<'d> {
|
||||
mut self,
|
||||
next_frame_en: bool,
|
||||
mut buf: TX,
|
||||
) -> Result<DpiTransfer<'d, TX>, (DmaError, Self, TX)> {
|
||||
) -> Result<DpiTransfer<'d, TX, DM>, (DmaError, Self, TX)> {
|
||||
let result = unsafe {
|
||||
self.tx_channel
|
||||
.prepare_transfer(DmaPeripheral::LcdCam, &mut buf)
|
||||
@ -561,12 +568,12 @@ impl<'d> Dpi<'d> {
|
||||
|
||||
/// Represents an ongoing (or potentially finished) transfer using the RGB LCD
|
||||
/// interface
|
||||
pub struct DpiTransfer<'d, BUF: DmaTxBuffer> {
|
||||
dpi: ManuallyDrop<Dpi<'d>>,
|
||||
pub struct DpiTransfer<'d, BUF: DmaTxBuffer, DM: Mode> {
|
||||
dpi: ManuallyDrop<Dpi<'d, DM>>,
|
||||
buffer_view: ManuallyDrop<BUF::View>,
|
||||
}
|
||||
|
||||
impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
|
||||
impl<'d, BUF: DmaTxBuffer, DM: Mode> DpiTransfer<'d, BUF, DM> {
|
||||
/// Returns true when [Self::wait] will not block.
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.dpi
|
||||
@ -578,7 +585,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
|
||||
}
|
||||
|
||||
/// Stops this transfer on the spot and returns the peripheral and buffer.
|
||||
pub fn stop(mut self) -> (Dpi<'d>, BUF) {
|
||||
pub fn stop(mut self) -> (Dpi<'d, DM>, BUF) {
|
||||
self.stop_peripherals();
|
||||
let (dpi, view) = self.release();
|
||||
(dpi, BUF::from_view(view))
|
||||
@ -588,7 +595,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
|
||||
///
|
||||
/// Note: If you specified `next_frame_en` as true in [Dpi::send], you're
|
||||
/// just waiting for a DMA error when you call this.
|
||||
pub fn wait(mut self) -> (Result<(), DmaError>, Dpi<'d>, BUF) {
|
||||
pub fn wait(mut self) -> (Result<(), DmaError>, Dpi<'d, DM>, BUF) {
|
||||
while !self.is_done() {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
@ -611,7 +618,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
|
||||
(result, dpi, BUF::from_view(view))
|
||||
}
|
||||
|
||||
fn release(mut self) -> (Dpi<'d>, BUF::View) {
|
||||
fn release(mut self) -> (Dpi<'d, DM>, BUF::View) {
|
||||
// SAFETY: Since forget is called on self, we know that self.dpi and
|
||||
// self.buffer_view won't be touched again.
|
||||
let result = unsafe {
|
||||
@ -635,7 +642,7 @@ impl<'d, BUF: DmaTxBuffer> DpiTransfer<'d, BUF> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, BUF: DmaTxBuffer> Deref for DpiTransfer<'d, BUF> {
|
||||
impl<'d, BUF: DmaTxBuffer, DM: Mode> Deref for DpiTransfer<'d, BUF, DM> {
|
||||
type Target = BUF::View;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@ -643,13 +650,13 @@ impl<'d, BUF: DmaTxBuffer> Deref for DpiTransfer<'d, BUF> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, BUF: DmaTxBuffer> DerefMut for DpiTransfer<'d, BUF> {
|
||||
impl<'d, BUF: DmaTxBuffer, DM: Mode> DerefMut for DpiTransfer<'d, BUF, DM> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.buffer_view
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, BUF: DmaTxBuffer> Drop for DpiTransfer<'d, BUF> {
|
||||
impl<'d, BUF: DmaTxBuffer, DM: Mode> Drop for DpiTransfer<'d, BUF, DM> {
|
||||
fn drop(&mut self) {
|
||||
self.stop_peripherals();
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
//!
|
||||
//! let mut i8080 = I8080::new(
|
||||
//! lcd_cam.lcd,
|
||||
//! channel.tx,
|
||||
//! channel,
|
||||
//! tx_pins,
|
||||
//! 20.MHz(),
|
||||
//! Config::default(),
|
||||
@ -62,7 +62,7 @@ use fugit::HertzU32;
|
||||
|
||||
use crate::{
|
||||
clock::Clocks,
|
||||
dma::{ChannelTx, DmaChannelConvert, DmaEligible, DmaError, DmaPeripheral, DmaTxBuffer, Tx},
|
||||
dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor},
|
||||
gpio::{
|
||||
interconnect::{OutputConnection, PeripheralOutput},
|
||||
OutputSignal,
|
||||
@ -85,7 +85,7 @@ use crate::{
|
||||
/// Represents the I8080 LCD interface.
|
||||
pub struct I8080<'d, DM: Mode> {
|
||||
lcd_cam: PeripheralRef<'d, LCD_CAM>,
|
||||
tx_channel: ChannelTx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>,
|
||||
tx_channel: ChannelTx<'d, Blocking, TxChannelFor<LCD_CAM>>,
|
||||
_mode: PhantomData<DM>,
|
||||
}
|
||||
|
||||
@ -96,15 +96,16 @@ where
|
||||
/// Creates a new instance of the I8080 LCD interface.
|
||||
pub fn new<P, CH>(
|
||||
lcd: Lcd<'d, DM>,
|
||||
channel: ChannelTx<'d, Blocking, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
mut pins: P,
|
||||
frequency: HertzU32,
|
||||
config: Config,
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<<LCD_CAM as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<TxChannelFor<LCD_CAM>>,
|
||||
P: TxPins,
|
||||
{
|
||||
let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade()));
|
||||
let lcd_cam = lcd.lcd_cam;
|
||||
|
||||
let clocks = Clocks::get();
|
||||
@ -207,7 +208,7 @@ where
|
||||
|
||||
Self {
|
||||
lcd_cam,
|
||||
tx_channel: channel.degrade(),
|
||||
tx_channel,
|
||||
_mode: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -36,15 +36,17 @@ use crate::{
|
||||
ChannelTx,
|
||||
DescriptorChain,
|
||||
DmaChannelConvert,
|
||||
DmaChannelFor,
|
||||
DmaDescriptor,
|
||||
DmaEligible,
|
||||
DmaError,
|
||||
DmaPeripheral,
|
||||
DmaTransferRx,
|
||||
DmaTransferTx,
|
||||
ReadBuffer,
|
||||
Rx,
|
||||
RxChannelFor,
|
||||
Tx,
|
||||
TxChannelFor,
|
||||
WriteBuffer,
|
||||
},
|
||||
gpio::{
|
||||
@ -53,7 +55,7 @@ use crate::{
|
||||
},
|
||||
interrupt::InterruptHandler,
|
||||
peripheral::{self, Peripheral},
|
||||
peripherals::{self, Interrupt, PARL_IO},
|
||||
peripherals::{Interrupt, PARL_IO},
|
||||
system::{self, GenericPeripheralGuard},
|
||||
Async,
|
||||
Blocking,
|
||||
@ -809,7 +811,7 @@ pub struct ParlIoTx<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
tx_channel: ChannelTx<'d, DM, TxChannelFor<PARL_IO>>,
|
||||
tx_chain: DescriptorChain,
|
||||
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>,
|
||||
}
|
||||
@ -890,7 +892,7 @@ pub struct ParlIoRx<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
rx_channel: ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
|
||||
rx_chain: DescriptorChain,
|
||||
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>,
|
||||
}
|
||||
@ -1003,31 +1005,29 @@ where
|
||||
|
||||
impl<'d> ParlIoFullDuplex<'d, Blocking> {
|
||||
/// Create a new instance of [ParlIoFullDuplex]
|
||||
pub fn new<CH, DM>(
|
||||
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
||||
dma_channel: Channel<'d, DM, CH>,
|
||||
pub fn new<CH>(
|
||||
_parl_io: impl Peripheral<P = PARL_IO> + 'd,
|
||||
dma_channel: impl Peripheral<P = CH> + 'd,
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
frequency: HertzU32,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
DM: Mode,
|
||||
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
CH: DmaChannelConvert<DmaChannelFor<PARL_IO>>,
|
||||
{
|
||||
let tx_guard = GenericPeripheralGuard::new();
|
||||
let rx_guard = GenericPeripheralGuard::new();
|
||||
let dma_channel = Channel::<Blocking, CH>::from(dma_channel);
|
||||
let dma_channel = Channel::new(dma_channel.map(|ch| ch.degrade()));
|
||||
internal_init(frequency)?;
|
||||
|
||||
Ok(Self {
|
||||
tx: TxCreatorFullDuplex {
|
||||
tx_channel: dma_channel.tx.degrade(),
|
||||
tx_channel: dma_channel.tx,
|
||||
descriptors: tx_descriptors,
|
||||
_guard: tx_guard,
|
||||
},
|
||||
rx: RxCreatorFullDuplex {
|
||||
rx_channel: dma_channel.rx.degrade(),
|
||||
rx_channel: dma_channel.rx,
|
||||
descriptors: rx_descriptors,
|
||||
_guard: rx_guard,
|
||||
},
|
||||
@ -1036,6 +1036,17 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
|
||||
|
||||
/// Convert to an async version.
|
||||
pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> {
|
||||
for core in crate::Cpu::other() {
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||
}
|
||||
#[cfg(esp32h2)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
|
||||
}
|
||||
}
|
||||
ParlIoFullDuplex {
|
||||
tx: TxCreatorFullDuplex {
|
||||
tx_channel: self.tx.tx_channel.into_async(),
|
||||
@ -1115,35 +1126,52 @@ where
|
||||
pub tx: TxCreator<'d, DM>,
|
||||
}
|
||||
|
||||
impl<'d, DM> ParlIoTxOnly<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Create a new [ParlIoTxOnly]
|
||||
// TODO: only take a TX DMA channel?
|
||||
impl<'d> ParlIoTxOnly<'d, Blocking> {
|
||||
/// Creates a new [ParlIoTxOnly]
|
||||
pub fn new<CH>(
|
||||
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
||||
dma_channel: Channel<'d, DM, CH>,
|
||||
_parl_io: impl Peripheral<P = PARL_IO> + 'd,
|
||||
dma_channel: impl Peripheral<P = CH> + 'd,
|
||||
descriptors: &'static mut [DmaDescriptor],
|
||||
frequency: HertzU32,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<TxChannelFor<PARL_IO>>,
|
||||
{
|
||||
let guard = GenericPeripheralGuard::new();
|
||||
let tx_channel = ChannelTx::new(dma_channel.map(|ch| ch.degrade()));
|
||||
internal_init(frequency)?;
|
||||
|
||||
Ok(Self {
|
||||
tx: TxCreator {
|
||||
tx_channel: dma_channel.tx.degrade(),
|
||||
tx_channel,
|
||||
descriptors,
|
||||
_guard: guard,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ParlIoTxOnly<'_, Blocking> {
|
||||
/// Converts to Async mode.
|
||||
pub fn into_async(self) -> ParlIoTxOnly<'d, Async> {
|
||||
for core in crate::Cpu::other() {
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||
}
|
||||
#[cfg(esp32h2)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
|
||||
}
|
||||
}
|
||||
ParlIoTxOnly {
|
||||
tx: TxCreator {
|
||||
tx_channel: self.tx.tx_channel.into_async(),
|
||||
descriptors: self.tx.descriptors,
|
||||
_guard: self.tx._guard,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the interrupt handler, enables it with
|
||||
/// [crate::interrupt::Priority::min()]
|
||||
///
|
||||
@ -1173,6 +1201,19 @@ impl ParlIoTxOnly<'_, Blocking> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> ParlIoTxOnly<'d, Async> {
|
||||
/// Convert to a blocking version.
|
||||
pub fn into_blocking(self) -> ParlIoTxOnly<'d, Blocking> {
|
||||
ParlIoTxOnly {
|
||||
tx: TxCreator {
|
||||
tx_channel: self.tx.tx_channel.into_blocking(),
|
||||
descriptors: self.tx.descriptors,
|
||||
_guard: self.tx._guard,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::private::Sealed for ParlIoTxOnly<'_, Blocking> {}
|
||||
|
||||
impl InterruptConfigurable for ParlIoTxOnly<'_, Blocking> {
|
||||
@ -1191,35 +1232,53 @@ where
|
||||
pub rx: RxCreator<'d, DM>,
|
||||
}
|
||||
|
||||
impl<'d, DM> ParlIoRxOnly<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
impl<'d> ParlIoRxOnly<'d, Blocking> {
|
||||
/// Create a new [ParlIoRxOnly] instance
|
||||
// TODO: only take a RX DMA channel?
|
||||
pub fn new<CH>(
|
||||
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
|
||||
dma_channel: Channel<'d, DM, CH>,
|
||||
_parl_io: impl Peripheral<P = PARL_IO> + 'd,
|
||||
dma_channel: impl Peripheral<P = CH> + 'd,
|
||||
descriptors: &'static mut [DmaDescriptor],
|
||||
frequency: HertzU32,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<RxChannelFor<PARL_IO>>,
|
||||
{
|
||||
let guard = GenericPeripheralGuard::new();
|
||||
let rx_channel = ChannelRx::new(dma_channel.map(|ch| ch.degrade()));
|
||||
internal_init(frequency)?;
|
||||
|
||||
Ok(Self {
|
||||
rx: RxCreator {
|
||||
rx_channel: dma_channel.rx.degrade(),
|
||||
rx_channel,
|
||||
descriptors,
|
||||
_guard: guard,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ParlIoRxOnly<'_, Blocking> {
|
||||
/// Converts to Async mode.
|
||||
pub fn into_async(self) -> ParlIoRxOnly<'d, Async> {
|
||||
for core in crate::Cpu::other() {
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||
}
|
||||
#[cfg(esp32h2)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
|
||||
}
|
||||
}
|
||||
|
||||
ParlIoRxOnly {
|
||||
rx: RxCreator {
|
||||
rx_channel: self.rx.rx_channel.into_async(),
|
||||
descriptors: self.rx.descriptors,
|
||||
_guard: self.rx._guard,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the interrupt handler, enables it with
|
||||
/// [crate::interrupt::Priority::min()]
|
||||
///
|
||||
@ -1249,6 +1308,19 @@ impl ParlIoRxOnly<'_, Blocking> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> ParlIoRxOnly<'d, Async> {
|
||||
/// Convert to a blocking version.
|
||||
pub fn into_blocking(self) -> ParlIoRxOnly<'d, Blocking> {
|
||||
ParlIoRxOnly {
|
||||
rx: RxCreator {
|
||||
rx_channel: self.rx.rx_channel.into_blocking(),
|
||||
descriptors: self.rx.descriptors,
|
||||
_guard: self.rx._guard,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::private::Sealed for ParlIoRxOnly<'_, Blocking> {}
|
||||
|
||||
impl InterruptConfigurable for ParlIoRxOnly<'_, Blocking> {
|
||||
@ -1361,7 +1433,7 @@ impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
type TX = ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>;
|
||||
type TX = ChannelTx<'d, DM, TxChannelFor<PARL_IO>>;
|
||||
|
||||
fn tx(&mut self) -> &mut Self::TX {
|
||||
&mut self.tx_channel
|
||||
@ -1403,7 +1475,7 @@ where
|
||||
}
|
||||
|
||||
fn start_receive_bytes_dma(
|
||||
rx_channel: &mut ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
rx_channel: &mut ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
|
||||
rx_chain: &mut DescriptorChain,
|
||||
ptr: *mut u8,
|
||||
len: usize,
|
||||
@ -1457,7 +1529,7 @@ impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
type RX = ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>;
|
||||
type RX = ChannelRx<'d, DM, RxChannelFor<PARL_IO>>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.rx_channel
|
||||
@ -1473,7 +1545,7 @@ pub struct TxCreator<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
tx_channel: ChannelTx<'d, DM, TxChannelFor<PARL_IO>>,
|
||||
descriptors: &'static mut [DmaDescriptor],
|
||||
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
|
||||
}
|
||||
@ -1483,7 +1555,7 @@ pub struct RxCreator<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
rx_channel: ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
|
||||
descriptors: &'static mut [DmaDescriptor],
|
||||
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
|
||||
}
|
||||
@ -1493,7 +1565,7 @@ pub struct TxCreatorFullDuplex<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
tx_channel: ChannelTx<'d, DM, TxChannelFor<PARL_IO>>,
|
||||
descriptors: &'static mut [DmaDescriptor],
|
||||
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
|
||||
}
|
||||
@ -1503,7 +1575,7 @@ pub struct RxCreatorFullDuplex<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
rx_channel: ChannelRx<'d, DM, RxChannelFor<PARL_IO>>,
|
||||
descriptors: &'static mut [DmaDescriptor],
|
||||
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
|
||||
}
|
||||
@ -1529,6 +1601,25 @@ pub mod asynch {
|
||||
impl TxDoneFuture {
|
||||
pub fn new() -> Self {
|
||||
Instance::listen_tx_done();
|
||||
let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
|
||||
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
parl_io.bind_parl_io_interrupt(interrupt_handler.handler());
|
||||
unwrap!(crate::interrupt::enable(
|
||||
Interrupt::PARL_IO,
|
||||
interrupt_handler.priority()
|
||||
));
|
||||
}
|
||||
#[cfg(esp32h2)]
|
||||
{
|
||||
parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler());
|
||||
unwrap!(crate::interrupt::enable(
|
||||
Interrupt::PARL_IO_TX,
|
||||
interrupt_handler.priority()
|
||||
));
|
||||
}
|
||||
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
@ -1540,20 +1631,6 @@ pub mod asynch {
|
||||
self: core::pin::Pin<&mut Self>,
|
||||
cx: &mut core::task::Context<'_>,
|
||||
) -> Poll<Self::Output> {
|
||||
let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
|
||||
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
parl_io.bind_parl_io_interrupt(interrupt_handler.handler());
|
||||
crate::interrupt::enable(Interrupt::PARL_IO, interrupt_handler.priority()).unwrap();
|
||||
}
|
||||
#[cfg(esp32h2)]
|
||||
{
|
||||
parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler());
|
||||
crate::interrupt::enable(Interrupt::PARL_IO_TX, interrupt_handler.priority())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
TX_WAKER.register(cx.waker());
|
||||
if Instance::is_listening_tx_done() {
|
||||
Poll::Pending
|
||||
|
@ -63,6 +63,18 @@ impl<'a, T> PeripheralRef<'a, T> {
|
||||
PeripheralRef::new(unsafe { self.inner.clone_unchecked() })
|
||||
}
|
||||
|
||||
/// Transform the inner peripheral.
|
||||
///
|
||||
/// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`,
|
||||
/// using a user-provided impl to convert from `T` to `U`.
|
||||
#[inline]
|
||||
pub fn map<U>(self, transform: impl FnOnce(T) -> U) -> PeripheralRef<'a, U> {
|
||||
PeripheralRef {
|
||||
inner: transform(self.inner),
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the inner peripheral using `Into`.
|
||||
///
|
||||
/// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`,
|
||||
@ -75,10 +87,7 @@ impl<'a, T> PeripheralRef<'a, T> {
|
||||
where
|
||||
T: Into<U>,
|
||||
{
|
||||
PeripheralRef {
|
||||
inner: self.inner.into(),
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
self.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +188,19 @@ pub trait Peripheral: Sized + crate::private::Sealed {
|
||||
Self::P: Into<U>,
|
||||
U: Peripheral<P = U>,
|
||||
{
|
||||
unsafe { self.clone_unchecked().into() }
|
||||
self.map(Into::into)
|
||||
}
|
||||
|
||||
/// Map the peripheral using `Into`.
|
||||
///
|
||||
/// This converts from `Peripheral<P = T>` to `Peripheral<P = U>`,
|
||||
/// using an `Into` impl to convert from `T` to `U`.
|
||||
#[inline]
|
||||
fn map<U>(self, transform: impl FnOnce(Self::P) -> U) -> U
|
||||
where
|
||||
U: Peripheral<P = U>,
|
||||
{
|
||||
transform(unsafe { self.clone_unchecked() })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ use procmacros::ram;
|
||||
use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode};
|
||||
use crate::{
|
||||
clock::Clocks,
|
||||
dma::{Channel, DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
|
||||
dma::{DmaChannelConvert, DmaChannelFor, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
|
||||
gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal},
|
||||
interrupt::InterruptHandler,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
@ -465,26 +465,6 @@ pub struct Spi<'d, M, T = AnySpi> {
|
||||
guard: PeripheralGuard,
|
||||
}
|
||||
|
||||
impl<'d, M, T> Spi<'d, M, T>
|
||||
where
|
||||
M: Mode,
|
||||
T: Instance,
|
||||
{
|
||||
/// Configures the SPI instance to use DMA with the specified channel.
|
||||
///
|
||||
/// This method prepares the SPI instance for DMA transfers using SPI
|
||||
/// and returns an instance of `SpiDma` that supports DMA
|
||||
/// operations.
|
||||
pub fn with_dma<CH, DM>(self, channel: Channel<'d, DM, CH>) -> SpiDma<'d, M, T>
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
DM: Mode,
|
||||
Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
SpiDma::new(self.spi, channel.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, T> Spi<'_, M, T>
|
||||
where
|
||||
T: Instance,
|
||||
@ -549,6 +529,23 @@ impl<'d> Spi<'d, Blocking> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> Spi<'d, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Configures the SPI instance to use DMA with the specified channel.
|
||||
///
|
||||
/// This method prepares the SPI instance for DMA transfers using SPI
|
||||
/// and returns an instance of `SpiDma` that supports DMA
|
||||
/// operations.
|
||||
pub fn with_dma<CH>(self, channel: impl Peripheral<P = CH> + 'd) -> SpiDma<'d, Blocking, T>
|
||||
where
|
||||
CH: DmaChannelConvert<DmaChannelFor<T>>,
|
||||
{
|
||||
SpiDma::new(self.spi, channel.map(|ch| ch.degrade()).into_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Spi<'d, Async> {
|
||||
/// Converts the SPI instance into blocking mode.
|
||||
pub fn into_blocking(self) -> Spi<'d, Blocking> {
|
||||
@ -859,6 +856,7 @@ mod dma {
|
||||
dma::{
|
||||
asynch::{DmaRxFuture, DmaTxFuture},
|
||||
Channel,
|
||||
DmaChannelFor,
|
||||
DmaRxBuf,
|
||||
DmaRxBuffer,
|
||||
DmaTxBuf,
|
||||
@ -885,7 +883,7 @@ mod dma {
|
||||
M: Mode,
|
||||
{
|
||||
pub(crate) spi: PeripheralRef<'d, T>,
|
||||
pub(crate) channel: Channel<'d, M, T::Dma>,
|
||||
pub(crate) channel: Channel<'d, M, DmaChannelFor<T>>,
|
||||
tx_transfer_in_progress: bool,
|
||||
rx_transfer_in_progress: bool,
|
||||
#[cfg(all(esp32, spi_address_workaround))]
|
||||
@ -993,15 +991,15 @@ mod dma {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M, T> SpiDma<'d, M, T>
|
||||
impl<'d, T> SpiDma<'d, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
M: Mode,
|
||||
{
|
||||
pub(super) fn new<CH>(spi: PeripheralRef<'d, T>, channel: Channel<'d, M, CH>) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
{
|
||||
pub(super) fn new(
|
||||
spi: PeripheralRef<'d, T>,
|
||||
channel: PeripheralRef<'d, DmaChannelFor<T>>,
|
||||
) -> Self {
|
||||
let channel = Channel::new(channel);
|
||||
channel.runtime_ensure_compatible(&spi);
|
||||
#[cfg(all(esp32, spi_address_workaround))]
|
||||
let address_buffer = {
|
||||
@ -1027,7 +1025,7 @@ mod dma {
|
||||
|
||||
Self {
|
||||
spi,
|
||||
channel: channel.degrade(),
|
||||
channel,
|
||||
#[cfg(all(esp32, spi_address_workaround))]
|
||||
address_buffer,
|
||||
tx_transfer_in_progress: false,
|
||||
@ -1035,7 +1033,13 @@ mod dma {
|
||||
guard,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M, T> SpiDma<'d, M, T>
|
||||
where
|
||||
M: Mode,
|
||||
T: Instance,
|
||||
{
|
||||
fn driver(&self) -> &'static Info {
|
||||
self.spi.info()
|
||||
}
|
||||
|
@ -177,39 +177,44 @@ pub mod dma {
|
||||
ChannelRx,
|
||||
ChannelTx,
|
||||
DescriptorChain,
|
||||
DmaChannelFor,
|
||||
DmaDescriptor,
|
||||
DmaTransferRx,
|
||||
DmaTransferRxTx,
|
||||
DmaTransferTx,
|
||||
ReadBuffer,
|
||||
Rx,
|
||||
RxChannelFor,
|
||||
Tx,
|
||||
TxChannelFor,
|
||||
WriteBuffer,
|
||||
},
|
||||
Mode,
|
||||
};
|
||||
|
||||
impl<'d, M, T> Spi<'d, M, T>
|
||||
impl<'d, T> Spi<'d, Blocking, T>
|
||||
where
|
||||
T: InstanceDma,
|
||||
M: Mode,
|
||||
{
|
||||
/// Configures the SPI3 peripheral with the provided DMA channel and
|
||||
/// Configures the SPI peripheral with the provided DMA channel and
|
||||
/// descriptors.
|
||||
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
|
||||
pub fn with_dma<CH, DM>(
|
||||
pub fn with_dma<CH>(
|
||||
self,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
channel: impl Peripheral<P = CH> + 'd,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> SpiDma<'d, M, T>
|
||||
) -> SpiDma<'d, Blocking, T>
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
DM: Mode,
|
||||
Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
|
||||
CH: DmaChannelConvert<DmaChannelFor<T>>,
|
||||
{
|
||||
self.spi.info().set_data_mode(self.data_mode, true);
|
||||
SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors)
|
||||
SpiDma::new(
|
||||
self.spi,
|
||||
channel.map(|ch| ch.degrade()).into_ref(),
|
||||
rx_descriptors,
|
||||
tx_descriptors,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +225,7 @@ pub mod dma {
|
||||
M: Mode,
|
||||
{
|
||||
pub(crate) spi: PeripheralRef<'d, T>,
|
||||
pub(crate) channel: Channel<'d, M, T::Dma>,
|
||||
pub(crate) channel: Channel<'d, M, DmaChannelFor<T>>,
|
||||
rx_chain: DescriptorChain,
|
||||
tx_chain: DescriptorChain,
|
||||
_guard: PeripheralGuard,
|
||||
@ -260,7 +265,7 @@ pub mod dma {
|
||||
T: InstanceDma,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type TX = ChannelTx<'d, DmaMode, T::Dma>;
|
||||
type TX = ChannelTx<'d, DmaMode, TxChannelFor<T>>;
|
||||
|
||||
fn tx(&mut self) -> &mut Self::TX {
|
||||
&mut self.channel.tx
|
||||
@ -276,7 +281,7 @@ pub mod dma {
|
||||
T: InstanceDma,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type RX = ChannelRx<'d, DmaMode, T::Dma>;
|
||||
type RX = ChannelRx<'d, DmaMode, RxChannelFor<T>>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.channel.rx
|
||||
@ -287,32 +292,35 @@ pub mod dma {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, DmaMode, T> SpiDma<'d, DmaMode, T>
|
||||
impl<'d, T> SpiDma<'d, Blocking, T>
|
||||
where
|
||||
T: InstanceDma,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
fn new<CH>(
|
||||
fn new(
|
||||
spi: PeripheralRef<'d, T>,
|
||||
channel: Channel<'d, DmaMode, CH>,
|
||||
channel: PeripheralRef<'d, DmaChannelFor<T>>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
{
|
||||
) -> Self {
|
||||
let channel = Channel::new(channel);
|
||||
channel.runtime_ensure_compatible(&spi);
|
||||
let guard = PeripheralGuard::new(spi.info().peripheral);
|
||||
|
||||
Self {
|
||||
spi,
|
||||
channel: channel.degrade(),
|
||||
channel,
|
||||
rx_chain: DescriptorChain::new(rx_descriptors),
|
||||
tx_chain: DescriptorChain::new(tx_descriptors),
|
||||
_guard: guard,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M, T> SpiDma<'d, M, T>
|
||||
where
|
||||
M: Mode,
|
||||
T: InstanceDma,
|
||||
{
|
||||
fn driver(&self) -> DmaDriver {
|
||||
DmaDriver {
|
||||
info: self.spi.info(),
|
||||
|
@ -43,13 +43,9 @@ async fn main(_spawner: Spawner) {
|
||||
);
|
||||
let mut rx_clk_pin = NoPin;
|
||||
|
||||
let parl_io = ParlIoRxOnly::new(
|
||||
peripherals.PARL_IO,
|
||||
dma.channel0.into_async(),
|
||||
rx_descriptors,
|
||||
1.MHz(),
|
||||
)
|
||||
.unwrap();
|
||||
let parl_io = ParlIoRxOnly::new(peripherals.PARL_IO, dma.channel0, rx_descriptors, 1.MHz())
|
||||
.unwrap()
|
||||
.into_async();
|
||||
|
||||
let mut parl_io_rx = parl_io
|
||||
.rx
|
||||
|
@ -54,13 +54,9 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, peripherals.GPIO5);
|
||||
|
||||
let parl_io = ParlIoTxOnly::new(
|
||||
peripherals.PARL_IO,
|
||||
dma.channel0.into_async(),
|
||||
tx_descriptors,
|
||||
1.MHz(),
|
||||
)
|
||||
.unwrap();
|
||||
let parl_io = ParlIoTxOnly::new(peripherals.PARL_IO, dma.channel0, tx_descriptors, 1.MHz())
|
||||
.unwrap()
|
||||
.into_async();
|
||||
|
||||
let mut clock_pin = ClkOutPin::new(peripherals.GPIO8);
|
||||
|
||||
|
@ -71,7 +71,7 @@ fn main() -> ! {
|
||||
.with_scl(peripherals.GPIO48);
|
||||
|
||||
let dma = Dma::new(peripherals.DMA);
|
||||
let channel = dma.channel2;
|
||||
let tx_channel = dma.channel2;
|
||||
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
|
||||
|
||||
let mut expander = Tca9554::new(i2c);
|
||||
@ -166,7 +166,7 @@ fn main() -> ! {
|
||||
config.de_idle_level = Level::Low;
|
||||
config.disable_black_region = false;
|
||||
|
||||
let mut dpi = Dpi::new(lcd_cam.lcd, channel.tx, 16.MHz(), config)
|
||||
let mut dpi = Dpi::new(lcd_cam.lcd, tx_channel, 16.MHz(), config)
|
||||
.with_vsync(vsync_pin)
|
||||
.with_hsync(peripherals.GPIO46)
|
||||
.with_de(peripherals.GPIO17)
|
||||
|
@ -6,11 +6,10 @@
|
||||
#![no_main]
|
||||
|
||||
use esp_hal::{
|
||||
dma::{AnyGdmaChannel, Channel, Dma, DmaError, Mem2Mem},
|
||||
dma::{AnyGdmaChannel, Dma, DmaChannelConvert, DmaError, Mem2Mem},
|
||||
dma_buffers,
|
||||
dma_buffers_chunk_size,
|
||||
dma_descriptors,
|
||||
Blocking,
|
||||
};
|
||||
use hil_test as _;
|
||||
|
||||
@ -25,7 +24,7 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
|
||||
struct Context {
|
||||
channel: Channel<'static, Blocking, AnyGdmaChannel>,
|
||||
channel: AnyGdmaChannel,
|
||||
dma_peripheral: DmaPeripheralType,
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ mod test {
|
||||
let mut spi = Spi::new_with_config(
|
||||
peripherals.SPI2,
|
||||
Config {
|
||||
frequency: 100.kHz(),
|
||||
frequency: 10000.kHz(),
|
||||
mode: SpiMode::Mode0,
|
||||
..Config::default()
|
||||
},
|
||||
@ -137,7 +137,7 @@ mod test {
|
||||
let other_peripheral = Spi::new_with_config(
|
||||
peripherals.SPI3,
|
||||
Config {
|
||||
frequency: 100.kHz(),
|
||||
frequency: 10000.kHz(),
|
||||
mode: SpiMode::Mode0,
|
||||
..Config::default()
|
||||
},
|
||||
@ -205,7 +205,7 @@ mod test {
|
||||
#[timeout(3)]
|
||||
async fn dma_does_not_lock_up_on_core_1() {
|
||||
use embassy_time::Timer;
|
||||
use esp_hal::{dma::Channel, peripherals::SPI2, Blocking};
|
||||
use esp_hal::peripherals::SPI2;
|
||||
use portable_atomic::{AtomicU32, Ordering};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
@ -221,7 +221,7 @@ mod test {
|
||||
|
||||
pub struct SpiPeripherals {
|
||||
pub spi: SPI2,
|
||||
pub dma_channel: Channel<'static, Blocking, DmaChannel>,
|
||||
pub dma_channel: DmaChannel,
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
|
@ -12,14 +12,13 @@
|
||||
|
||||
use esp_hal::{
|
||||
delay::Delay,
|
||||
dma::{Channel, Dma},
|
||||
dma::Dma,
|
||||
dma_buffers,
|
||||
gpio::{AnyPin, NoPin, Pin},
|
||||
i2s::master::{DataFormat, I2s, I2sTx, Standard},
|
||||
peripherals::I2S0,
|
||||
prelude::*,
|
||||
Async,
|
||||
Blocking,
|
||||
};
|
||||
use hil_test as _;
|
||||
|
||||
@ -105,7 +104,7 @@ mod tests {
|
||||
|
||||
struct Context {
|
||||
dout: AnyPin,
|
||||
dma_channel: Channel<'static, Blocking, DmaChannel0>,
|
||||
dma_channel: DmaChannel0,
|
||||
i2s: I2S0,
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#![no_main]
|
||||
|
||||
use esp_hal::{
|
||||
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
|
||||
dma::{Dma, DmaRxBuf, DmaTxBuf},
|
||||
dma_buffers,
|
||||
gpio::Level,
|
||||
lcd_cam::{
|
||||
@ -58,7 +58,9 @@ mod tests {
|
||||
let dma = Dma::new(peripherals.DMA);
|
||||
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
|
||||
|
||||
let channel = dma.channel2;
|
||||
// TODO: use split channels once supported
|
||||
let tx_channel = dma.channel2;
|
||||
let rx_channel = dma.channel3;
|
||||
|
||||
let (vsync_in, vsync_out) = peripherals.GPIO6.split();
|
||||
let (hsync_in, hsync_out) = peripherals.GPIO7.split();
|
||||
@ -101,7 +103,7 @@ mod tests {
|
||||
config.de_idle_level = Level::Low;
|
||||
config.disable_black_region = false;
|
||||
|
||||
let dpi = Dpi::new(lcd_cam.lcd, channel.tx, 500u32.kHz(), config)
|
||||
let dpi = Dpi::new(lcd_cam.lcd, tx_channel, 500u32.kHz(), config)
|
||||
.with_vsync(vsync_out)
|
||||
.with_hsync(hsync_out)
|
||||
.with_de(de_out)
|
||||
@ -117,7 +119,7 @@ mod tests {
|
||||
|
||||
let camera = Camera::new(
|
||||
lcd_cam.cam,
|
||||
channel.rx,
|
||||
rx_channel,
|
||||
RxEightBits::new(d0_in, d1_in, d2_in, d3_in, d4_in, d5_in, d6_in, d7_in),
|
||||
1u32.MHz(),
|
||||
)
|
||||
|
@ -78,7 +78,7 @@ mod tests {
|
||||
|
||||
let i8080 = I8080::new(
|
||||
ctx.lcd_cam.lcd,
|
||||
ctx.dma.channel0.tx,
|
||||
ctx.dma.channel0,
|
||||
pins,
|
||||
20.MHz(),
|
||||
Config::default(),
|
||||
@ -141,7 +141,7 @@ mod tests {
|
||||
|
||||
let mut i8080 = I8080::new(
|
||||
ctx.lcd_cam.lcd,
|
||||
ctx.dma.channel0.tx,
|
||||
ctx.dma.channel0,
|
||||
pins,
|
||||
20.MHz(),
|
||||
Config::default(),
|
||||
@ -258,13 +258,7 @@ mod tests {
|
||||
unit3_signal,
|
||||
);
|
||||
|
||||
let mut i8080 = I8080::new(
|
||||
ctx.lcd_cam.lcd,
|
||||
channel.tx,
|
||||
pins,
|
||||
20.MHz(),
|
||||
Config::default(),
|
||||
)
|
||||
let mut i8080 = I8080::new(ctx.lcd_cam.lcd, channel, pins, 20.MHz(), Config::default())
|
||||
.with_cs(cs_signal)
|
||||
.with_ctrl_pins(NoPin, NoPin);
|
||||
|
||||
|
@ -54,7 +54,7 @@ mod tests {
|
||||
|
||||
let i8080 = I8080::new(
|
||||
ctx.lcd_cam.lcd,
|
||||
ctx.dma.channel0.tx,
|
||||
ctx.dma.channel0,
|
||||
pins,
|
||||
20.MHz(),
|
||||
Config::default(),
|
||||
|
@ -7,7 +7,7 @@
|
||||
#[cfg(esp32c6)]
|
||||
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
|
||||
use esp_hal::{
|
||||
dma::{Channel, Dma, DmaChannel0},
|
||||
dma::{Dma, DmaChannel0},
|
||||
gpio::{
|
||||
interconnect::{InputSignal, OutputSignal},
|
||||
NoPin,
|
||||
@ -27,13 +27,12 @@ use esp_hal::{
|
||||
},
|
||||
peripherals::PARL_IO,
|
||||
prelude::*,
|
||||
Blocking,
|
||||
};
|
||||
use hil_test as _;
|
||||
|
||||
struct Context {
|
||||
parl_io: PARL_IO,
|
||||
dma_channel: Channel<'static, Blocking, DmaChannel0>,
|
||||
dma_channel: DmaChannel0,
|
||||
clock: OutputSignal,
|
||||
valid: OutputSignal,
|
||||
clock_loopback: InputSignal,
|
||||
|
@ -9,7 +9,7 @@
|
||||
#[cfg(esp32c6)]
|
||||
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
|
||||
use esp_hal::{
|
||||
dma::{Channel, Dma, DmaChannel0},
|
||||
dma::{Dma, DmaChannel0},
|
||||
gpio::{
|
||||
interconnect::{InputSignal, OutputSignal},
|
||||
NoPin,
|
||||
@ -29,13 +29,12 @@ use esp_hal::{
|
||||
},
|
||||
peripherals::PARL_IO,
|
||||
prelude::*,
|
||||
Async,
|
||||
};
|
||||
use hil_test as _;
|
||||
|
||||
struct Context {
|
||||
parl_io: PARL_IO,
|
||||
dma_channel: Channel<'static, Async, DmaChannel0>,
|
||||
dma_channel: DmaChannel0,
|
||||
clock: OutputSignal,
|
||||
valid: OutputSignal,
|
||||
clock_loopback: InputSignal,
|
||||
@ -61,7 +60,7 @@ mod tests {
|
||||
let pcnt = Pcnt::new(peripherals.PCNT);
|
||||
let pcnt_unit = pcnt.unit0;
|
||||
let dma = Dma::new(peripherals.DMA);
|
||||
let dma_channel = dma.channel0.into_async();
|
||||
let dma_channel = dma.channel0;
|
||||
|
||||
let parl_io = peripherals.PARL_IO;
|
||||
|
||||
@ -91,8 +90,9 @@ mod tests {
|
||||
let mut pins = TxPinConfigIncludingValidPin::new(pins);
|
||||
let mut clock_pin = ClkOutPin::new(ctx.clock);
|
||||
|
||||
let pio =
|
||||
ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap();
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
|
||||
.unwrap()
|
||||
.into_async();
|
||||
|
||||
let mut pio = pio
|
||||
.tx
|
||||
@ -152,8 +152,9 @@ mod tests {
|
||||
|
||||
let mut clock_pin = ClkOutPin::new(ctx.clock);
|
||||
|
||||
let pio =
|
||||
ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap();
|
||||
let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
|
||||
.unwrap()
|
||||
.into_async();
|
||||
|
||||
let mut pio = pio
|
||||
.tx
|
||||
@ -166,7 +167,8 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// use a PCNT unit to count the negitive clock edges only when valid is high
|
||||
// use a PCNT unit to count the negitive clock edges only when
|
||||
// valid is high
|
||||
let clock_unit = ctx.pcnt_unit;
|
||||
clock_unit.channel0.set_edge_signal(ctx.clock_loopback);
|
||||
clock_unit.channel0.set_ctrl_signal(ctx.valid_loopback);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#[cfg(pcnt)]
|
||||
use esp_hal::pcnt::{channel::EdgeMode, unit::Unit, Pcnt};
|
||||
use esp_hal::{
|
||||
dma::{Channel, Dma, DmaRxBuf, DmaTxBuf},
|
||||
dma::{Dma, DmaRxBuf, DmaTxBuf},
|
||||
dma_buffers,
|
||||
gpio::{AnyPin, Input, Level, Output, Pull},
|
||||
prelude::*,
|
||||
@ -43,7 +43,7 @@ struct Context {
|
||||
spi: Spi<'static, Blocking>,
|
||||
#[cfg(pcnt)]
|
||||
pcnt: esp_hal::peripherals::PCNT,
|
||||
dma_channel: Channel<'static, Blocking, DmaChannel0>,
|
||||
dma_channel: DmaChannel0,
|
||||
gpios: [AnyPin; 3],
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ use embedded_hal::spi::SpiBus;
|
||||
#[cfg(pcnt)]
|
||||
use embedded_hal_async::spi::SpiBus as SpiBusAsync;
|
||||
use esp_hal::{
|
||||
dma::{Channel, Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf},
|
||||
dma::{Dma, DmaDescriptor, DmaRxBuf, DmaTxBuf},
|
||||
dma_buffers,
|
||||
gpio::{Level, NoPin},
|
||||
peripheral::Peripheral,
|
||||
@ -37,7 +37,7 @@ cfg_if::cfg_if! {
|
||||
|
||||
struct Context {
|
||||
spi: Spi<'static, Blocking>,
|
||||
dma_channel: Channel<'static, Blocking, DmaChannel>,
|
||||
dma_channel: DmaChannel,
|
||||
// Reuse the really large buffer so we don't run out of DRAM with many tests
|
||||
rx_buffer: &'static mut [u8],
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
@ -424,9 +424,9 @@ mod tests {
|
||||
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
||||
let mut spi = ctx
|
||||
.spi
|
||||
.into_async()
|
||||
.with_dma(ctx.dma_channel)
|
||||
.with_buffers(dma_rx_buf, dma_tx_buf);
|
||||
.with_buffers(dma_rx_buf, dma_tx_buf)
|
||||
.into_async();
|
||||
|
||||
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
|
||||
ctx.pcnt_unit
|
||||
|
@ -9,7 +9,7 @@
|
||||
#![no_main]
|
||||
|
||||
use esp_hal::{
|
||||
dma::{Channel, Dma},
|
||||
dma::Dma,
|
||||
dma_buffers,
|
||||
gpio::{Input, Level, Output, Pull},
|
||||
peripheral::Peripheral,
|
||||
@ -28,7 +28,7 @@ cfg_if::cfg_if! {
|
||||
|
||||
struct Context {
|
||||
spi: Spi<'static, Blocking>,
|
||||
dma_channel: Channel<'static, Blocking, DmaChannel>,
|
||||
dma_channel: DmaChannel,
|
||||
bitbang_spi: BitbangSpi,
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ fn main() -> ! {
|
||||
);
|
||||
|
||||
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
|
||||
let camera = Camera::new(lcd_cam.cam, dma.channel0.rx, cam_data_pins, 20u32.MHz())
|
||||
let camera = Camera::new(lcd_cam.cam, dma.channel0, cam_data_pins, 20u32.MHz())
|
||||
.with_master_clock(cam_xclk)
|
||||
.with_pixel_clock(cam_pclk)
|
||||
.with_ctrl_pins(cam_vsync, cam_href);
|
||||
|
@ -71,7 +71,7 @@ fn main() -> ! {
|
||||
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
|
||||
let i8080 = I8080::new(
|
||||
lcd_cam.lcd,
|
||||
dma.channel0.tx,
|
||||
dma.channel0,
|
||||
tx_pins,
|
||||
20.MHz(),
|
||||
Config::default(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user