[DMA 1/N] Add mode to DMA channel drivers (#2519)

* Add mode to DMA channel drivers

* Swap dma Channel CH and DM

* Fix copy-paste mistake
This commit is contained in:
Dániel Buga 2024-11-14 09:03:05 +01:00 committed by GitHub
parent 959631ee55
commit 38dde2ebbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 470 additions and 392 deletions

View File

@ -65,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `I2c` SCL timeout is now defined in bus clock cycles. (#2477) - `I2c` SCL timeout is now defined in bus clock cycles. (#2477)
- Trying to send a single-shot RMT transmission will result in an error now, `RMT` deals with `u32` now, `PulseCode` is a convenience trait now (#2463) - Trying to send a single-shot RMT transmission will result in an error now, `RMT` deals with `u32` now, `PulseCode` is a convenience trait now (#2463)
- Removed `get_` prefixes from functions (#2528) - Removed `get_` prefixes from functions (#2528)
- The `Camera` and `I8080` drivers' constructors now only accepts blocking-mode DMA channels. (#2519)
### Fixed ### Fixed
@ -180,6 +181,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The DMA channel types have been removed from peripherals (#2261) - The DMA channel types have been removed from peripherals (#2261)
- `I2C` driver renamed to `I2c` (#2320) - `I2C` driver renamed to `I2c` (#2320)
- The GPIO pins are now accessible via `Peripherals` and are no longer part of the `Io` struct (#2508) - The GPIO pins are now accessible via `Peripherals` and are no longer part of the `Io` struct (#2508)
- `dma::{ChannelRx, ChannelTx}` now have a `Mode` type parameter (#2519)
### Fixed ### Fixed

View File

@ -276,7 +276,9 @@ For example:
} }
``` ```
## Circular DMA transfer's `available` returns `Result<usize, DmaError>` now ## DMA related changes
### Circular DMA transfer's `available` returns `Result<usize, DmaError>` now
In case of any error you should drop the transfer and restart it. In case of any error you should drop the transfer and restart it.
@ -293,6 +295,22 @@ In case of any error you should drop the transfer and restart it.
+ }; + };
``` ```
### Channel, ChannelRx and ChannelTx types have changed
- `Channel`'s `Async`/`Blocking` mode has been moved before the channel instance parameter.
- `ChannelRx` and `ChannelTx` have gained a new `Async`/`Blocking` mode parameter.
```diff
-Channel<'d, DmaChannel0, Async>
+Channel<'d, Async, DmaChannel0>
-ChannelRx<'d, DmaChannel0>
+ChannelRx<'d, Async, DmaChannel0>
-ChannelTx<'d, DmaChannel0>
+ChannelTx<'d, Async, DmaChannel0>
```
## Removed `peripheral_input` and `into_peripheral_output` from GPIO pin types ## Removed `peripheral_input` and `into_peripheral_output` from GPIO pin types
Creating peripheral interconnect signals now consume the GPIO pin used for the connection. Creating peripheral interconnect signals now consume the GPIO pin used for the connection.
@ -357,7 +375,9 @@ refer to the `Config` struct as `uart::Config`.
+) +)
``` ```
## I8080 driver split `set_byte_order()` into `set_8bits_order()` and `set_byte_order()`. ## LCD_CAM changes
### I8080 driver split `set_byte_order()` into `set_8bits_order()` and `set_byte_order()`.
If you were using an 8-bit bus. If you were using an 8-bit bus.
@ -371,6 +391,29 @@ If you were using an 16-bit bus, you don't need to change anything, `set_byte_or
If you were sharing the bus between an 8-bit and 16-bit device, you will have to call the corresponding method when If you were sharing the bus between an 8-bit and 16-bit device, you will have to call the corresponding method when
you switch between devices. Be sure to read the documentation of the new methods. you switch between devices. Be sure to read the documentation of the new methods.
### Mixed mode constructors
It is no longer possible to construct `I8080` or `Camera` with an async-mode DMA channel.
Convert the DMA channel into blocking before passing it to these constructors.
```diff
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
let channel = ctx
.dma
.channel0
- .configure(false, DmaPriority::Priority0)
- .into_async();
+ .configure(false, DmaPriority::Priority0);
let i8080 = I8080::new(
lcd_cam.lcd,
channel.tx,
pins,
20.MHz(),
Config::default(),
);
```
## `rmt::Channel::transmit` now returns `Result`, `PulseCode` is now `u32` ## `rmt::Channel::transmit` now returns `Result`, `PulseCode` is now `u32`
When trying to send a one-shot transmission will fail if it doesn't end with an end-marker. When trying to send a one-shot transmission will fail if it doesn't end with an end-marker.

View File

@ -276,21 +276,21 @@ pub mod dma {
/// The underlying [`Aes`](super::Aes) driver /// The underlying [`Aes`](super::Aes) driver
pub aes: super::Aes<'d>, pub aes: super::Aes<'d>,
channel: Channel<'d, <AES as DmaEligible>::Dma, Blocking>, channel: Channel<'d, Blocking, <AES as DmaEligible>::Dma>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
} }
impl<'d> crate::aes::Aes<'d> { impl<'d> crate::aes::Aes<'d> {
/// Enable DMA for the current instance of the AES driver /// Enable DMA for the current instance of the AES driver
pub fn with_dma<C>( pub fn with_dma<CH>(
self, self,
channel: Channel<'d, C, Blocking>, channel: Channel<'d, Blocking, CH>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> AesDma<'d> ) -> AesDma<'d>
where where
C: DmaChannelConvert<<AES as DmaEligible>::Dma>, CH: DmaChannelConvert<<AES as DmaEligible>::Dma>,
{ {
AesDma { AesDma {
aes: self, aes: self,
@ -324,7 +324,7 @@ pub mod dma {
} }
impl<'d> DmaSupportTx for AesDma<'d> { impl<'d> DmaSupportTx for AesDma<'d> {
type TX = ChannelTx<'d, <AES as DmaEligible>::Dma>; type TX = ChannelTx<'d, Blocking, <AES as DmaEligible>::Dma>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx &mut self.channel.tx
@ -336,7 +336,7 @@ pub mod dma {
} }
impl<'d> DmaSupportRx for AesDma<'d> { impl<'d> DmaSupportRx for AesDma<'d> {
type RX = ChannelRx<'d, <AES as DmaEligible>::Dma>; type RX = ChannelRx<'d, Blocking, <AES as DmaEligible>::Dma>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx &mut self.channel.rx

View File

@ -25,6 +25,66 @@ use crate::{
#[doc(hidden)] #[doc(hidden)]
pub trait GdmaChannel { pub trait GdmaChannel {
fn number(&self) -> u8; fn number(&self) -> 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!(),
}
}
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!(),
}
}
} }
/// An arbitrary GDMA channel /// An arbitrary GDMA channel
@ -35,36 +95,6 @@ impl crate::private::Sealed for AnyGdmaChannel {}
impl DmaChannel for AnyGdmaChannel { impl DmaChannel for AnyGdmaChannel {
type Rx = ChannelRxImpl<Self>; type Rx = ChannelRxImpl<Self>;
type Tx = ChannelTxImpl<Self>; type Tx = ChannelTxImpl<Self>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match ch.tx.tx_impl.0.number() {
0 => DmaChannel0::handler(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::handler(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::handler(),
#[cfg(esp32s3)]
3 => DmaChannel3::handler(),
#[cfg(esp32s3)]
4 => DmaChannel4::handler(),
_ => unreachable!(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match ch.tx.tx_impl.0.number() {
0 => DmaChannel0::isrs(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::isrs(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::isrs(),
#[cfg(esp32s3)]
3 => DmaChannel3::isrs(),
#[cfg(esp32s3)]
4 => DmaChannel4::isrs(),
_ => unreachable!(),
}
}
} }
#[non_exhaustive] #[non_exhaustive]
@ -202,6 +232,14 @@ impl<C: GdmaChannel> TxRegisterAccess for ChannelTxImpl<C> {
.out_eof_des_addr() .out_eof_des_addr()
.bits() as _ .bits() as _
} }
fn async_handler(&self) -> Option<InterruptHandler> {
self.0.async_handler_out()
}
fn peripheral_interrupt(&self) -> Option<Interrupt> {
self.0.peripheral_interrupt_out()
}
} }
impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> { impl<C: GdmaChannel> InterruptAccess<DmaTxInterrupt> for ChannelTxImpl<C> {
@ -385,6 +423,14 @@ impl<C: GdmaChannel> RxRegisterAccess for ChannelRxImpl<C> {
.in_conf0() .in_conf0()
.modify(|_, w| w.mem_trans_en().bit(value)); .modify(|_, w| w.mem_trans_en().bit(value));
} }
fn async_handler(&self) -> Option<InterruptHandler> {
self.0.async_handler_in()
}
fn peripheral_interrupt(&self) -> Option<Interrupt> {
self.0.peripheral_interrupt_in()
}
} }
impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> { impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
@ -473,7 +519,7 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
#[non_exhaustive] #[non_exhaustive]
pub struct ChannelCreator<const N: u8> {} pub struct ChannelCreator<const N: u8> {}
impl<CH: DmaChannel, M: Mode> Channel<'_, CH, M> { impl<CH: DmaChannel, M: Mode> Channel<'_, M, CH> {
/// Asserts that the channel is compatible with the given peripheral. /// Asserts that the channel is compatible with the given peripheral.
pub fn runtime_ensure_compatible<P: DmaEligible>(&self, _peripheral: &PeripheralRef<'_, P>) { pub fn runtime_ensure_compatible<P: DmaEligible>(&self, _peripheral: &PeripheralRef<'_, P>) {
// No runtime checks; GDMA channels are compatible with any peripheral // No runtime checks; GDMA channels are compatible with any peripheral
@ -481,7 +527,7 @@ impl<CH: DmaChannel, M: Mode> Channel<'_, CH, M> {
} }
macro_rules! impl_channel { macro_rules! impl_channel {
($num: literal, $async_handler: path, $($interrupt: ident),* ) => { ($num:literal, $interrupt_in:ident, $async_handler:path $(, $interrupt_out:ident , $async_handler_out:path)? ) => {
paste::paste! { paste::paste! {
/// A description of a specific GDMA channel /// A description of a specific GDMA channel
#[non_exhaustive] #[non_exhaustive]
@ -490,26 +536,26 @@ macro_rules! impl_channel {
impl crate::private::Sealed for [<DmaChannel $num>] {} impl crate::private::Sealed for [<DmaChannel $num>] {}
impl [<DmaChannel $num>] { impl [<DmaChannel $num>] {
fn handler() -> InterruptHandler { fn handler_in() -> Option<InterruptHandler> {
$async_handler Some($async_handler)
} }
fn isrs() -> &'static [Interrupt] { fn isr_in() -> Option<Interrupt> {
&[$(Interrupt::$interrupt),*] Some(Interrupt::$interrupt_in)
}
fn handler_out() -> Option<InterruptHandler> {
$crate::if_set! { $(Some($async_handler_out))?, None }
}
fn isr_out() -> Option<Interrupt> {
$crate::if_set! { $(Some(Interrupt::$interrupt_out))?, None }
} }
} }
impl DmaChannel for [<DmaChannel $num>] { impl DmaChannel for [<DmaChannel $num>] {
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>; type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>;
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>; type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>,) -> &'static [Interrupt] {
Self::isrs()
}
} }
impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] { impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
@ -537,11 +583,10 @@ macro_rules! impl_channel {
self, self,
burst_mode: bool, burst_mode: bool,
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<DmaChannel $num>], Blocking> { ) -> Channel<'a, Blocking, [<DmaChannel $num>]> {
let mut this = Channel { let mut this = Channel {
tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})), tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})),
rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})), rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})),
phantom: PhantomData,
}; };
this.configure(burst_mode, priority); this.configure(burst_mode, priority);
@ -553,27 +598,29 @@ macro_rules! impl_channel {
}; };
} }
use super::asynch::interrupt as asynch_handler;
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(esp32c2)] { if #[cfg(esp32c2)] {
const CHANNEL_COUNT: usize = 1; const CHANNEL_COUNT: usize = 1;
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0); impl_channel!(0, DMA_CH0, asynch_handler::interrupt_handler_ch0);
} else if #[cfg(esp32c3)] { } else if #[cfg(esp32c3)] {
const CHANNEL_COUNT: usize = 3; const CHANNEL_COUNT: usize = 3;
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0); impl_channel!(0, DMA_CH0, asynch_handler::interrupt_handler_ch0);
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_CH1); impl_channel!(1, DMA_CH1, asynch_handler::interrupt_handler_ch1);
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_CH2); impl_channel!(2, DMA_CH2, asynch_handler::interrupt_handler_ch2);
} else if #[cfg(any(esp32c6, esp32h2))] { } else if #[cfg(any(esp32c6, esp32h2))] {
const CHANNEL_COUNT: usize = 3; const CHANNEL_COUNT: usize = 3;
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0); impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0);
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1); impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1);
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2); impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2);
} else if #[cfg(esp32s3)] { } else if #[cfg(esp32s3)] {
const CHANNEL_COUNT: usize = 5; const CHANNEL_COUNT: usize = 5;
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0); impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0);
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1); impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1);
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2); impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2);
impl_channel!(3, super::asynch::interrupt::interrupt_handler_ch3, DMA_IN_CH3, DMA_OUT_CH3); impl_channel!(3, DMA_IN_CH3, asynch_handler::interrupt_handler_ch3, DMA_OUT_CH3, asynch_handler::interrupt_handler_ch3);
impl_channel!(4, super::asynch::interrupt::interrupt_handler_ch4, DMA_IN_CH4, DMA_OUT_CH4); impl_channel!(4, DMA_IN_CH4, asynch_handler::interrupt_handler_ch4, DMA_OUT_CH4, asynch_handler::interrupt_handler_ch4);
} }
} }

View File

@ -32,7 +32,7 @@ pub struct Mem2Mem<'d, M>
where where
M: Mode, M: Mode,
{ {
channel: Channel<'d, AnyGdmaChannel, M>, channel: Channel<'d, M, AnyGdmaChannel>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
peripheral: DmaPeripheral, peripheral: DmaPeripheral,
@ -41,7 +41,7 @@ where
impl<'d> Mem2Mem<'d, Blocking> { impl<'d> Mem2Mem<'d, Blocking> {
/// Create a new Mem2Mem instance. /// Create a new Mem2Mem instance.
pub fn new<CH, DM>( pub fn new<CH, DM>(
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
peripheral: impl DmaEligible, peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
@ -49,7 +49,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode, DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>, Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
unsafe { unsafe {
Self::new_unsafe( Self::new_unsafe(
@ -64,7 +64,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
/// Create a new Mem2Mem instance with specific chunk size. /// Create a new Mem2Mem instance with specific chunk size.
pub fn new_with_chunk_size<CH, DM>( pub fn new_with_chunk_size<CH, DM>(
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
peripheral: impl DmaEligible, peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
@ -73,7 +73,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode, DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>, Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
unsafe { unsafe {
Self::new_unsafe( Self::new_unsafe(
@ -93,7 +93,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
/// You must ensure that your not using DMA for the same peripheral and /// You must ensure that your not using DMA for the same peripheral and
/// that your the only one using the DmaPeripheral. /// that your the only one using the DmaPeripheral.
pub unsafe fn new_unsafe<CH, DM>( pub unsafe fn new_unsafe<CH, DM>(
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
peripheral: DmaPeripheral, peripheral: DmaPeripheral,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
@ -102,7 +102,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode, DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>, Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
if !(1..=4092).contains(&chunk_size) { if !(1..=4092).contains(&chunk_size) {
return Err(DmaError::InvalidChunkSize); return Err(DmaError::InvalidChunkSize);
@ -111,7 +111,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
return Err(DmaError::OutOfDescriptors); return Err(DmaError::OutOfDescriptors);
} }
Ok(Mem2Mem { Ok(Mem2Mem {
channel: Channel::<_, Blocking>::from(channel).degrade(), channel: Channel::<Blocking, _>::from(channel).degrade(),
peripheral, peripheral,
rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size), rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size),
tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size), tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size),
@ -190,11 +190,11 @@ where
} }
} }
impl<'d, MODE> DmaSupportRx for Mem2Mem<'d, MODE> impl<'d, M> DmaSupportRx for Mem2Mem<'d, M>
where where
MODE: Mode, M: Mode,
{ {
type RX = ChannelRx<'d, AnyGdmaChannel>; type RX = ChannelRx<'d, M, AnyGdmaChannel>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx &mut self.channel.rx

View File

@ -1571,12 +1571,6 @@ pub trait DmaChannel: crate::private::Sealed + Sized {
/// A description of the TX half of a DMA Channel. /// A description of the TX half of a DMA Channel.
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>; type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>;
/// Returns the async interrupt handler.
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler;
/// Returns the interrupt.
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt];
} }
#[doc(hidden)] #[doc(hidden)]
@ -1666,16 +1660,16 @@ pub trait Rx: crate::private::Sealed {
// DMA receive channel // DMA receive channel
#[non_exhaustive] #[non_exhaustive]
#[doc(hidden)] #[doc(hidden)]
pub struct ChannelRx<'a, CH> pub struct ChannelRx<'a, M, CH>
where where
CH: DmaChannel, CH: DmaChannel,
{ {
pub(crate) burst_mode: bool, pub(crate) burst_mode: bool,
pub(crate) rx_impl: CH::Rx, pub(crate) rx_impl: CH::Rx,
pub(crate) _phantom: PhantomData<(&'a (), CH)>, pub(crate) _phantom: PhantomData<(&'a (), CH, M)>,
} }
impl<'a, CH> ChannelRx<'a, CH> impl<'a, CH> ChannelRx<'a, Blocking, CH>
where where
CH: DmaChannel, CH: DmaChannel,
{ {
@ -1692,9 +1686,60 @@ where
} }
} }
/// Converts a blocking channel to an async channel.
pub(crate) fn into_async(mut self) -> ChannelRx<'a, Async, CH> {
if let Some(handler) = self.rx_impl.async_handler() {
self.set_interrupt_handler(handler);
}
ChannelRx {
burst_mode: self.burst_mode,
rx_impl: self.rx_impl,
_phantom: PhantomData,
}
}
fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where
CH: DmaChannel,
{
self.unlisten_in(EnumSet::all());
self.clear_in(EnumSet::all());
if let Some(interrupt) = self.rx_impl.peripheral_interrupt() {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, interrupt);
}
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
}
}
}
impl<'a, CH> ChannelRx<'a, Async, CH>
where
CH: DmaChannel,
{
/// Converts an async channel into a blocking channel.
pub(crate) fn into_blocking(self) -> ChannelRx<'a, Blocking, CH> {
if let Some(interrupt) = self.rx_impl.peripheral_interrupt() {
crate::interrupt::disable(Cpu::current(), interrupt);
}
ChannelRx {
burst_mode: self.burst_mode,
rx_impl: self.rx_impl,
_phantom: PhantomData,
}
}
}
impl<'a, M, CH> ChannelRx<'a, M, CH>
where
M: Mode,
CH: DmaChannel,
{
/// Return a less specific (degraded) version of this channel. /// Return a less specific (degraded) version of this channel.
#[doc(hidden)] #[doc(hidden)]
pub fn degrade<DEG: DmaChannel>(self) -> ChannelRx<'a, DEG> pub fn degrade<DEG: DmaChannel>(self) -> ChannelRx<'a, M, DEG>
where where
CH: DmaChannelConvert<DEG>, CH: DmaChannelConvert<DEG>,
{ {
@ -1712,10 +1757,16 @@ where
} }
} }
impl<CH> crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {} impl<M, CH> crate::private::Sealed for ChannelRx<'_, M, CH>
impl<CH> Rx for ChannelRx<'_, CH>
where where
M: Mode,
CH: DmaChannel,
{
}
impl<M, CH> Rx for ChannelRx<'_, M, CH>
where
M: Mode,
CH: DmaChannel, CH: DmaChannel,
{ {
unsafe fn prepare_transfer_without_start( unsafe fn prepare_transfer_without_start(
@ -1894,17 +1945,17 @@ pub trait Tx: crate::private::Sealed {
/// DMA transmit channel /// DMA transmit channel
#[doc(hidden)] #[doc(hidden)]
pub struct ChannelTx<'a, CH> pub struct ChannelTx<'a, M, CH>
where where
CH: DmaChannel, CH: DmaChannel,
{ {
#[allow(unused)] #[allow(unused)]
pub(crate) burst_mode: bool, pub(crate) burst_mode: bool,
pub(crate) tx_impl: CH::Tx, pub(crate) tx_impl: CH::Tx,
pub(crate) _phantom: PhantomData<(&'a (), CH)>, pub(crate) _phantom: PhantomData<(&'a (), CH, M)>,
} }
impl<'a, CH> ChannelTx<'a, CH> impl<'a, CH> ChannelTx<'a, Blocking, CH>
where where
CH: DmaChannel, CH: DmaChannel,
{ {
@ -1916,9 +1967,60 @@ where
} }
} }
/// Converts a blocking channel to an async channel.
pub(crate) fn into_async(mut self) -> ChannelTx<'a, Async, CH> {
if let Some(handler) = self.tx_impl.async_handler() {
self.set_interrupt_handler(handler);
}
ChannelTx {
burst_mode: self.burst_mode,
tx_impl: self.tx_impl,
_phantom: PhantomData,
}
}
fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where
CH: DmaChannel,
{
self.unlisten_out(EnumSet::all());
self.clear_out(EnumSet::all());
if let Some(interrupt) = self.tx_impl.peripheral_interrupt() {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, interrupt);
}
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
}
}
}
impl<'a, CH> ChannelTx<'a, Async, CH>
where
CH: DmaChannel,
{
/// Converts an async channel into a blocking channel.
pub(crate) fn into_blocking(self) -> ChannelTx<'a, Blocking, CH> {
if let Some(interrupt) = self.tx_impl.peripheral_interrupt() {
crate::interrupt::disable(Cpu::current(), interrupt);
}
ChannelTx {
burst_mode: self.burst_mode,
tx_impl: self.tx_impl,
_phantom: PhantomData,
}
}
}
impl<'a, M, CH> ChannelTx<'a, M, CH>
where
M: Mode,
CH: DmaChannel,
{
/// Return a less specific (degraded) version of this channel. /// Return a less specific (degraded) version of this channel.
#[doc(hidden)] #[doc(hidden)]
pub fn degrade<DEG: DmaChannel>(self) -> ChannelTx<'a, DEG> pub fn degrade<DEG: DmaChannel>(self) -> ChannelTx<'a, M, DEG>
where where
CH: DmaChannelConvert<DEG>, CH: DmaChannelConvert<DEG>,
{ {
@ -1936,10 +2038,16 @@ where
} }
} }
impl<CH> crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {} impl<M, CH> crate::private::Sealed for ChannelTx<'_, M, CH>
impl<CH> Tx for ChannelTx<'_, CH>
where where
M: Mode,
CH: DmaChannel,
{
}
impl<M, CH> Tx for ChannelTx<'_, M, CH>
where
M: Mode,
CH: DmaChannel, CH: DmaChannel,
{ {
unsafe fn prepare_transfer_without_start( unsafe fn prepare_transfer_without_start(
@ -2116,6 +2224,9 @@ pub trait RegisterAccess: crate::private::Sealed {
pub trait RxRegisterAccess: RegisterAccess { pub trait RxRegisterAccess: RegisterAccess {
#[cfg(gdma)] #[cfg(gdma)]
fn set_mem2mem_mode(&self, value: bool); fn set_mem2mem_mode(&self, value: bool);
fn peripheral_interrupt(&self) -> Option<Interrupt>;
fn async_handler(&self) -> Option<InterruptHandler>;
} }
#[doc(hidden)] #[doc(hidden)]
@ -2125,6 +2236,9 @@ pub trait TxRegisterAccess: RegisterAccess {
/// Outlink descriptor address when EOF occurs of Tx channel. /// Outlink descriptor address when EOF occurs of Tx channel.
fn last_dscr_address(&self) -> usize; fn last_dscr_address(&self) -> usize;
fn peripheral_interrupt(&self) -> Option<Interrupt>;
fn async_handler(&self) -> Option<InterruptHandler>;
} }
#[doc(hidden)] #[doc(hidden)]
@ -2148,38 +2262,30 @@ pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
} }
/// DMA Channel /// DMA Channel
pub struct Channel<'d, CH, M> pub struct Channel<'d, M, CH>
where where
CH: DmaChannel,
M: Mode, M: Mode,
CH: DmaChannel,
{ {
/// RX half of the channel /// RX half of the channel
pub rx: ChannelRx<'d, CH>, pub rx: ChannelRx<'d, M, CH>,
/// TX half of the channel /// TX half of the channel
pub tx: ChannelTx<'d, CH>, pub tx: ChannelTx<'d, M, CH>,
pub(crate) phantom: PhantomData<M>,
} }
impl<'d, C> Channel<'d, C, Blocking> impl<'d, CH> Channel<'d, Blocking, CH>
where where
C: DmaChannel, CH: DmaChannel,
{ {
/// Sets the interrupt handler for RX and TX interrupts. /// Sets the interrupt handler for RX and TX interrupts.
/// ///
/// Interrupts are not enabled at the peripheral level here. /// Interrupts are not enabled at the peripheral level here.
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) pub fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where where
C: DmaChannel, CH: DmaChannel,
{ {
self.unlisten(EnumSet::all()); self.rx.set_interrupt_handler(handler);
self.clear_interrupts(EnumSet::all()); self.tx.set_interrupt_handler(handler);
for interrupt in C::interrupts(self).iter().copied() {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, interrupt);
}
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
}
} }
/// Listen for the given interrupts /// Listen for the given interrupts
@ -2226,67 +2332,59 @@ where
/// Configure the channel. /// Configure the channel.
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
self.tx.configure(burst_mode, priority);
self.rx.configure(burst_mode, priority); self.rx.configure(burst_mode, priority);
self.tx.configure(burst_mode, priority);
} }
/// Converts a blocking channel to an async channel. /// Converts a blocking channel to an async channel.
pub fn into_async(mut self) -> Channel<'d, C, Async> { pub fn into_async(self) -> Channel<'d, Async, CH> {
self.set_interrupt_handler(C::async_handler(&self));
Channel { Channel {
tx: self.tx, rx: self.rx.into_async(),
rx: self.rx, tx: self.tx.into_async(),
phantom: PhantomData,
} }
} }
} }
impl<'d, C> Channel<'d, C, Async> impl<'d, CH> Channel<'d, Async, CH>
where where
C: DmaChannel, CH: DmaChannel,
{ {
/// Converts an async channel to a blocking channel. /// Converts an async channel to a blocking channel.
pub fn into_blocking(self) -> Channel<'d, C, Blocking> { pub fn into_blocking(self) -> Channel<'d, Blocking, CH> {
for interrupt in C::interrupts(&self).iter().copied() {
crate::interrupt::disable(Cpu::current(), interrupt);
}
Channel { Channel {
tx: self.tx, rx: self.rx.into_blocking(),
rx: self.rx, tx: self.tx.into_blocking(),
phantom: PhantomData,
} }
} }
} }
impl<'d, C: DmaChannel> From<Channel<'d, C, Blocking>> for Channel<'d, C, Async> { impl<'d, CH: DmaChannel> From<Channel<'d, Blocking, CH>> for Channel<'d, Async, CH> {
fn from(channel: Channel<'d, C, Blocking>) -> Self { fn from(channel: Channel<'d, Blocking, CH>) -> Self {
channel.into_async() channel.into_async()
} }
} }
impl<'d, C: DmaChannel> From<Channel<'d, C, Async>> for Channel<'d, C, Blocking> { impl<'d, CH: DmaChannel> From<Channel<'d, Async, CH>> for Channel<'d, Blocking, CH> {
fn from(channel: Channel<'d, C, Async>) -> Self { fn from(channel: Channel<'d, Async, CH>) -> Self {
channel.into_blocking() channel.into_blocking()
} }
} }
impl<'d, CH, M: Mode> Channel<'d, CH, M> impl<'d, M, CH> Channel<'d, M, CH>
where where
M: Mode,
CH: DmaChannel, CH: DmaChannel,
{ {
/// Return a less specific (degraded) version of this channel (both rx and /// Return a less specific (degraded) version of this channel (both rx and
/// tx). /// tx).
#[doc(hidden)] #[doc(hidden)]
pub fn degrade<DEG: DmaChannel>(self) -> Channel<'d, DEG, M> pub fn degrade<DEG: DmaChannel>(self) -> Channel<'d, M, DEG>
where where
CH: DmaChannelConvert<DEG>, CH: DmaChannelConvert<DEG>,
{ {
Channel { Channel {
rx: self.rx.degrade(), rx: self.rx.degrade(),
tx: self.tx.degrade(), tx: self.tx.degrade(),
phantom: PhantomData,
} }
} }
} }

View File

@ -32,6 +32,9 @@ pub trait PdmaChannel: crate::private::Sealed {
fn tx_waker(&self) -> &'static AtomicWaker; fn tx_waker(&self) -> &'static AtomicWaker;
fn rx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker;
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
fn peripheral_interrupt(&self) -> Interrupt;
fn async_handler(&self) -> InterruptHandler;
} }
#[doc(hidden)] #[doc(hidden)]
@ -107,6 +110,14 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> TxRegisterAccess for SpiD
let spi = self.0.register_block(); let spi = self.0.register_block();
spi.out_eof_des_addr().read().dma_out_eof_des_addr().bits() as usize spi.out_eof_des_addr().read().dma_out_eof_des_addr().bits() as usize
} }
fn peripheral_interrupt(&self) -> Option<Interrupt> {
None
}
fn async_handler(&self) -> Option<InterruptHandler> {
None
}
} }
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaTxInterrupt> impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaTxInterrupt>
@ -241,7 +252,15 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RegisterAccess for SpiDma
} }
} }
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RxRegisterAccess for SpiDmaRxChannelImpl<C> {} impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> RxRegisterAccess for SpiDmaRxChannelImpl<C> {
fn peripheral_interrupt(&self) -> Option<Interrupt> {
Some(self.0.peripheral_interrupt())
}
fn async_handler(&self) -> Option<InterruptHandler> {
Some(self.0.async_handler())
}
}
impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaRxInterrupt> impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> InterruptAccess<DmaRxInterrupt>
for SpiDmaRxChannelImpl<C> for SpiDmaRxChannelImpl<C>
@ -343,27 +362,9 @@ macro_rules! ImplSpiChannel {
#[non_exhaustive] #[non_exhaustive]
pub struct [<Spi $num DmaChannel>] {} pub struct [<Spi $num DmaChannel>] {}
impl [<Spi $num DmaChannel>] {
fn handler() -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]
}
fn isrs() -> &'static [Interrupt] {
&[Interrupt::[< SPI $num _DMA >]]
}
}
impl DmaChannel for [<Spi $num DmaChannel>] { impl DmaChannel for [<Spi $num DmaChannel>] {
type Rx = SpiDmaRxChannelImpl<Self>; type Rx = SpiDmaRxChannelImpl<Self>;
type Tx = SpiDmaTxChannelImpl<Self>; type Tx = SpiDmaTxChannelImpl<Self>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
Self::isrs()
}
} }
impl DmaChannelExt for [<Spi $num DmaChannel>] { impl DmaChannelExt for [<Spi $num DmaChannel>] {
@ -393,6 +394,14 @@ macro_rules! ImplSpiChannel {
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
peripheral == DmaPeripheral::[<Spi $num>] peripheral == DmaPeripheral::[<Spi $num>]
} }
fn peripheral_interrupt(&self) -> Interrupt {
Interrupt::[< SPI $num _DMA >]
}
fn async_handler(&self) -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]
}
} }
impl DmaChannelConvert<AnySpiDmaChannel> for [<Spi $num DmaChannel>] { impl DmaChannelConvert<AnySpiDmaChannel> for [<Spi $num DmaChannel>] {
@ -416,11 +425,10 @@ macro_rules! ImplSpiChannel {
self, self,
burst_mode: bool, burst_mode: bool,
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>], Blocking> { ) -> Channel<'a, Blocking, [<Spi $num DmaChannel>]> {
let mut this = Channel { let mut this = Channel {
tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})), tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})),
rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})), rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})),
phantom: PhantomData,
}; };
this.configure(burst_mode, priority); this.configure(burst_mode, priority);
@ -518,6 +526,14 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> TxRegisterAccess for I2sD
.out_eof_des_addr() .out_eof_des_addr()
.bits() as usize .bits() as usize
} }
fn peripheral_interrupt(&self) -> Option<Interrupt> {
None
}
fn async_handler(&self) -> Option<InterruptHandler> {
None
}
} }
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaTxInterrupt> impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaTxInterrupt>
@ -658,7 +674,15 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RegisterAccess for I2sDma
} }
} }
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RxRegisterAccess for I2sDmaRxChannelImpl<C> {} impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> RxRegisterAccess for I2sDmaRxChannelImpl<C> {
fn peripheral_interrupt(&self) -> Option<Interrupt> {
Some(self.0.peripheral_interrupt())
}
fn async_handler(&self) -> Option<InterruptHandler> {
Some(self.0.async_handler())
}
}
impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaRxInterrupt> impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> InterruptAccess<DmaRxInterrupt>
for I2sDmaRxChannelImpl<C> for I2sDmaRxChannelImpl<C>
@ -756,27 +780,9 @@ macro_rules! ImplI2sChannel {
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {} impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
impl [<I2s $num DmaChannel>] {
fn handler() -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >]
}
fn isrs() -> &'static [Interrupt] {
&[Interrupt::[< I2S $num >]]
}
}
impl DmaChannel for [<I2s $num DmaChannel>] { impl DmaChannel for [<I2s $num DmaChannel>] {
type Rx = I2sDmaRxChannelImpl<Self>; type Rx = I2sDmaRxChannelImpl<Self>;
type Tx = I2sDmaTxChannelImpl<Self>; type Tx = I2sDmaTxChannelImpl<Self>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
Self::isrs()
}
} }
impl DmaChannelExt for [<I2s $num DmaChannel>] { impl DmaChannelExt for [<I2s $num DmaChannel>] {
@ -805,6 +811,14 @@ macro_rules! ImplI2sChannel {
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
peripheral == DmaPeripheral::[<I2s $num>] peripheral == DmaPeripheral::[<I2s $num>]
} }
fn peripheral_interrupt(&self) -> Interrupt {
Interrupt::[< I2S $num >]
}
fn async_handler(&self) -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >]
}
} }
impl DmaChannelConvert<AnyI2sDmaChannel> for [<I2s $num DmaChannel>] { impl DmaChannelConvert<AnyI2sDmaChannel> for [<I2s $num DmaChannel>] {
@ -825,11 +839,10 @@ macro_rules! ImplI2sChannel {
self, self,
burst_mode: bool, burst_mode: bool,
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>], Blocking> { ) -> Channel<'a, Blocking, [<I2s $num DmaChannel>]> {
let mut this = Channel { let mut this = Channel {
tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})), tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})),
rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})), rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})),
phantom: PhantomData,
}; };
this.configure(burst_mode, priority); this.configure(burst_mode, priority);
@ -904,9 +917,10 @@ impl<'d> Dma<'d> {
} }
} }
impl<'d, C, M: Mode> Channel<'d, C, M> impl<'d, CH, M> Channel<'d, M, CH>
where where
C: DmaChannel, CH: DmaChannel,
M: Mode,
{ {
/// Asserts that the channel is compatible with the given peripheral. /// Asserts that the channel is compatible with the given peripheral.
pub fn runtime_ensure_compatible(&self, peripheral: &PeripheralRef<'_, impl DmaEligible>) { pub fn runtime_ensure_compatible(&self, peripheral: &PeripheralRef<'_, impl DmaEligible>) {
@ -928,20 +942,6 @@ impl crate::private::Sealed for AnySpiDmaChannel {}
impl DmaChannel for AnySpiDmaChannel { impl DmaChannel for AnySpiDmaChannel {
type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>; type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>;
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>; type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match &ch.tx.tx_impl.0 {
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::handler(),
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::handler(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match &ch.tx.tx_impl.0 {
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::isrs(),
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::isrs(),
}
}
} }
crate::any_enum! { crate::any_enum! {
@ -966,6 +966,8 @@ impl PdmaChannel for AnySpiDmaChannelInner {
fn tx_waker(&self) -> &'static AtomicWaker; fn tx_waker(&self) -> &'static AtomicWaker;
fn rx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker;
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
fn peripheral_interrupt(&self) -> Interrupt;
fn async_handler(&self) -> InterruptHandler;
} }
} }
} }
@ -978,22 +980,6 @@ impl crate::private::Sealed for AnyI2sDmaChannel {}
impl DmaChannel for AnyI2sDmaChannel { impl DmaChannel for AnyI2sDmaChannel {
type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>; type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>;
type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>; type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match &ch.tx.tx_impl.0 {
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::handler(),
#[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::handler(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match &ch.tx.tx_impl.0 {
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::isrs(),
#[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::isrs(),
}
}
} }
crate::any_enum! { crate::any_enum! {
@ -1020,6 +1006,8 @@ impl PdmaChannel for AnyI2sDmaChannelInner {
fn tx_waker(&self) -> &'static AtomicWaker; fn tx_waker(&self) -> &'static AtomicWaker;
fn rx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker;
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
fn peripheral_interrupt(&self) -> Interrupt;
fn async_handler(&self) -> InterruptHandler;
} }
} }
} }

View File

@ -74,8 +74,6 @@
//! //!
//! - Only TDM Philips standard is supported. //! - Only TDM Philips standard is supported.
use core::marker::PhantomData;
use enumset::{EnumSet, EnumSetType}; use enumset::{EnumSet, EnumSetType};
use private::*; use private::*;
@ -251,6 +249,7 @@ impl DataFormat {
} }
/// Instance of the I2S peripheral driver /// Instance of the I2S peripheral driver
#[non_exhaustive]
pub struct I2s<'d, M, T = AnyI2s> pub struct I2s<'d, M, T = AnyI2s>
where where
T: RegisterAccess, T: RegisterAccess,
@ -260,7 +259,6 @@ where
pub i2s_rx: RxCreator<'d, M, T>, pub i2s_rx: RxCreator<'d, M, T>,
/// Handles the transmission (TX) side of the I2S peripheral. /// Handles the transmission (TX) side of the I2S peripheral.
pub i2s_tx: TxCreator<'d, M, T>, pub i2s_tx: TxCreator<'d, M, T>,
phantom: PhantomData<M>,
} }
impl<'d, DmaMode, T> I2s<'d, DmaMode, T> impl<'d, DmaMode, T> I2s<'d, DmaMode, T>
@ -274,7 +272,7 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH, DmaMode>, channel: Channel<'d, DmaMode, CH>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
@ -299,15 +297,12 @@ where
i2s: unsafe { i2s.clone_unchecked() }, i2s: unsafe { i2s.clone_unchecked() },
rx_channel: channel.rx, rx_channel: channel.rx,
descriptors: rx_descriptors, descriptors: rx_descriptors,
phantom: PhantomData,
}, },
i2s_tx: TxCreator { i2s_tx: TxCreator {
i2s, i2s,
tx_channel: channel.tx, tx_channel: channel.tx,
descriptors: tx_descriptors, descriptors: tx_descriptors,
phantom: PhantomData,
}, },
phantom: PhantomData,
} }
} }
} }
@ -376,14 +371,14 @@ impl<'d> I2s<'d, Blocking> {
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
where where
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>, CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
DM: Mode, DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>, Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
Self::new_typed( Self::new_typed(
i2s.map_into(), i2s.map_into(),
@ -409,14 +404,14 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DM: Mode, DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>, Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
crate::into_ref!(i2s); crate::into_ref!(i2s);
Self::new_internal( Self::new_internal(
@ -432,26 +427,17 @@ where
/// Converts the SPI instance into async mode. /// Converts the SPI instance into async mode.
pub fn into_async(self) -> I2s<'d, Async, T> { pub fn into_async(self) -> I2s<'d, Async, T> {
let channel = Channel {
rx: self.i2s_rx.rx_channel,
tx: self.i2s_tx.tx_channel,
phantom: PhantomData::<Blocking>,
};
let channel = channel.into_async();
I2s { I2s {
i2s_rx: RxCreator { i2s_rx: RxCreator {
i2s: self.i2s_rx.i2s, i2s: self.i2s_rx.i2s,
rx_channel: channel.rx, rx_channel: self.i2s_rx.rx_channel.into_async(),
descriptors: self.i2s_rx.descriptors, descriptors: self.i2s_rx.descriptors,
phantom: PhantomData,
}, },
i2s_tx: TxCreator { i2s_tx: TxCreator {
i2s: self.i2s_tx.i2s, i2s: self.i2s_tx.i2s,
tx_channel: channel.tx, tx_channel: self.i2s_tx.tx_channel.into_async(),
descriptors: self.i2s_tx.descriptors, descriptors: self.i2s_tx.descriptors,
phantom: PhantomData,
}, },
phantom: PhantomData,
} }
} }
} }
@ -477,9 +463,8 @@ where
T: RegisterAccess, T: RegisterAccess,
{ {
i2s: PeripheralRef<'d, T>, i2s: PeripheralRef<'d, T>,
tx_channel: ChannelTx<'d, T::Dma>, tx_channel: ChannelTx<'d, DmaMode, T::Dma>,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
phantom: PhantomData<DmaMode>,
} }
impl<DmaMode, T> core::fmt::Debug for I2sTx<'_, DmaMode, T> impl<DmaMode, T> core::fmt::Debug for I2sTx<'_, DmaMode, T>
@ -511,7 +496,7 @@ where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, DmaMode: Mode,
{ {
type TX = ChannelTx<'d, T::Dma>; type TX = ChannelTx<'d, DmaMode, T::Dma>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel &mut self.tx_channel
@ -610,9 +595,8 @@ where
DmaMode: Mode, DmaMode: Mode,
{ {
i2s: PeripheralRef<'d, T>, i2s: PeripheralRef<'d, T>,
rx_channel: ChannelRx<'d, T::Dma>, rx_channel: ChannelRx<'d, DmaMode, T::Dma>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
phantom: PhantomData<DmaMode>,
} }
impl<DmaMode, T> core::fmt::Debug for I2sRx<'_, DmaMode, T> impl<DmaMode, T> core::fmt::Debug for I2sRx<'_, DmaMode, T>
@ -644,7 +628,7 @@ where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, DmaMode: Mode,
{ {
type RX = ChannelRx<'d, T::Dma>; type RX = ChannelRx<'d, DmaMode, T::Dma>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel &mut self.rx_channel
@ -750,8 +734,6 @@ pub trait RegisterAccess: RegisterAccessPrivate {}
impl<T> RegisterAccess for T where T: RegisterAccessPrivate {} impl<T> RegisterAccess for T where T: RegisterAccessPrivate {}
mod private { mod private {
use core::marker::PhantomData;
use enumset::EnumSet; use enumset::EnumSet;
use fugit::HertzU32; use fugit::HertzU32;
@ -790,22 +772,20 @@ mod private {
M: Mode, M: Mode,
{ {
pub i2s: PeripheralRef<'d, T>, pub i2s: PeripheralRef<'d, T>,
pub tx_channel: ChannelTx<'d, T::Dma>, pub tx_channel: ChannelTx<'d, M, T::Dma>,
pub descriptors: &'static mut [DmaDescriptor], pub descriptors: &'static mut [DmaDescriptor],
pub(crate) phantom: PhantomData<M>,
} }
impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T> impl<'d, M, T> TxCreator<'d, M, T>
where where
M: Mode,
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode,
{ {
pub fn build(self) -> I2sTx<'d, DmaMode, T> { pub fn build(self) -> I2sTx<'d, M, T> {
I2sTx { I2sTx {
i2s: self.i2s, i2s: self.i2s,
tx_channel: self.tx_channel, tx_channel: self.tx_channel,
tx_chain: DescriptorChain::new(self.descriptors), tx_chain: DescriptorChain::new(self.descriptors),
phantom: PhantomData,
} }
} }
@ -849,22 +829,20 @@ mod private {
M: Mode, M: Mode,
{ {
pub i2s: PeripheralRef<'d, T>, pub i2s: PeripheralRef<'d, T>,
pub rx_channel: ChannelRx<'d, T::Dma>, pub rx_channel: ChannelRx<'d, M, T::Dma>,
pub descriptors: &'static mut [DmaDescriptor], pub descriptors: &'static mut [DmaDescriptor],
pub(crate) phantom: PhantomData<M>,
} }
impl<'d, M, T> RxCreator<'d, M, T> impl<'d, M, T> RxCreator<'d, M, T>
where where
T: RegisterAccess,
M: Mode, M: Mode,
T: RegisterAccess,
{ {
pub fn build(self) -> I2sRx<'d, M, T> { pub fn build(self) -> I2sRx<'d, M, T> {
I2sRx { I2sRx {
i2s: self.i2s, i2s: self.i2s,
rx_channel: self.rx_channel, rx_channel: self.rx_channel,
rx_chain: DescriptorChain::new(self.descriptors), rx_chain: DescriptorChain::new(self.descriptors),
phantom: PhantomData,
} }
} }

View File

@ -35,7 +35,6 @@
//! - `DMA` //! - `DMA`
//! - `system` (to configure and enable the I2S peripheral) //! - `system` (to configure and enable the I2S peripheral)
use core::{ use core::{
marker::PhantomData,
mem::ManuallyDrop, mem::ManuallyDrop,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
@ -177,8 +176,7 @@ where
I: Instance, I: Instance,
{ {
instance: PeripheralRef<'d, I>, instance: PeripheralRef<'d, I>,
tx_channel: ChannelTx<'d, I::Dma>, tx_channel: ChannelTx<'d, DM, I::Dma>,
mode: PhantomData<DM>,
} }
impl<'d, DM> I2sParallel<'d, DM> impl<'d, DM> I2sParallel<'d, DM>
@ -188,7 +186,7 @@ where
/// Create a new I2S Parallel Interface /// Create a new I2S Parallel Interface
pub fn new<CH>( pub fn new<CH>(
i2s: impl Peripheral<P = impl Instance> + 'd, i2s: impl Peripheral<P = impl Instance> + 'd,
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
frequency: impl Into<fugit::HertzU32>, frequency: impl Into<fugit::HertzU32>,
pins: impl TxPins<'d>, pins: impl TxPins<'d>,
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd, clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
@ -208,7 +206,7 @@ where
/// Create a new I2S Parallel Interface /// Create a new I2S Parallel Interface
pub fn new_typed<CH>( pub fn new_typed<CH>(
i2s: impl Peripheral<P = I> + 'd, i2s: impl Peripheral<P = I> + 'd,
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
frequency: impl Into<fugit::HertzU32>, frequency: impl Into<fugit::HertzU32>,
mut pins: impl TxPins<'d>, mut pins: impl TxPins<'d>,
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd, clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
@ -234,7 +232,6 @@ where
Self { Self {
instance: i2s, instance: i2s,
tx_channel: channel.tx, tx_channel: channel.tx,
mode: PhantomData,
} }
} }

View File

@ -82,6 +82,7 @@ use crate::{
lcd_cam::{calculate_clkm, BitOrder, ByteOrder}, lcd_cam::{calculate_clkm, BitOrder, ByteOrder},
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::LCD_CAM, peripherals::LCD_CAM,
Blocking,
}; };
/// Generation of GDMA SUC EOF /// Generation of GDMA SUC EOF
@ -125,14 +126,14 @@ pub struct Cam<'d> {
/// Represents the camera interface with DMA support. /// Represents the camera interface with DMA support.
pub struct Camera<'d> { pub struct Camera<'d> {
lcd_cam: PeripheralRef<'d, LCD_CAM>, lcd_cam: PeripheralRef<'d, LCD_CAM>,
rx_channel: ChannelRx<'d, <LCD_CAM as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>,
} }
impl<'d> Camera<'d> { impl<'d> Camera<'d> {
/// Creates a new `Camera` instance with DMA support. /// Creates a new `Camera` instance with DMA support.
pub fn new<P, CH>( pub fn new<P, CH>(
cam: Cam<'d>, cam: Cam<'d>,
channel: ChannelRx<'d, CH>, channel: ChannelRx<'d, Blocking, CH>,
_pins: P, _pins: P,
frequency: HertzU32, frequency: HertzU32,
) -> Self ) -> Self

View File

@ -83,21 +83,25 @@ use crate::{
}, },
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::LCD_CAM, peripherals::LCD_CAM,
Blocking,
Mode, Mode,
}; };
/// Represents the I8080 LCD interface. /// Represents the I8080 LCD interface.
pub struct I8080<'d, DM: Mode> { pub struct I8080<'d, DM: Mode> {
lcd_cam: PeripheralRef<'d, LCD_CAM>, lcd_cam: PeripheralRef<'d, LCD_CAM>,
tx_channel: ChannelTx<'d, <LCD_CAM as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>,
_phantom: PhantomData<DM>, _mode: PhantomData<DM>,
} }
impl<'d, DM: Mode> I8080<'d, DM> { impl<'d, DM> I8080<'d, DM>
where
DM: Mode,
{
/// Creates a new instance of the I8080 LCD interface. /// Creates a new instance of the I8080 LCD interface.
pub fn new<P, CH>( pub fn new<P, CH>(
lcd: Lcd<'d, DM>, lcd: Lcd<'d, DM>,
channel: ChannelTx<'d, CH>, channel: ChannelTx<'d, Blocking, CH>,
mut pins: P, mut pins: P,
frequency: HertzU32, frequency: HertzU32,
config: Config, config: Config,
@ -209,12 +213,10 @@ impl<'d, DM: Mode> I8080<'d, DM> {
Self { Self {
lcd_cam, lcd_cam,
tx_channel: channel.degrade(), tx_channel: channel.degrade(),
_phantom: PhantomData, _mode: PhantomData,
} }
} }
}
impl<'d, DM: Mode> I8080<'d, DM> {
/// Configures the byte order for data transmission in 16-bit mode. /// Configures the byte order for data transmission in 16-bit mode.
/// This must be set to [ByteOrder::default()] when transmitting in 8-bit /// This must be set to [ByteOrder::default()] when transmitting in 8-bit
/// mode. /// mode.

View File

@ -118,3 +118,16 @@ macro_rules! any_peripheral {
} }
}; };
} }
/// Macro to choose between two expressions. Useful for implementing "else" for
/// `$()?` macro syntax.
#[macro_export]
#[doc(hidden)]
macro_rules! if_set {
(, $not_set:expr) => {
$not_set
};
($set:expr, $not_set:expr) => {
$set
};
}

View File

@ -23,8 +23,6 @@
//! //!
//! [Parallel IO TX]: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/parl_io_tx.rs //! [Parallel IO TX]: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/parl_io_tx.rs
use core::marker::PhantomData;
use enumset::{EnumSet, EnumSetType}; use enumset::{EnumSet, EnumSetType};
use fugit::HertzU32; use fugit::HertzU32;
use peripheral::PeripheralRef; use peripheral::PeripheralRef;
@ -769,7 +767,6 @@ where
Ok(ParlIoTx { Ok(ParlIoTx {
tx_channel: self.tx_channel, tx_channel: self.tx_channel,
tx_chain: DescriptorChain::new(self.descriptors), tx_chain: DescriptorChain::new(self.descriptors),
phantom: PhantomData,
}) })
} }
} }
@ -801,7 +798,6 @@ where
Ok(ParlIoTx { Ok(ParlIoTx {
tx_channel: self.tx_channel, tx_channel: self.tx_channel,
tx_chain: DescriptorChain::new(self.descriptors), tx_chain: DescriptorChain::new(self.descriptors),
phantom: PhantomData,
}) })
} }
} }
@ -811,9 +807,8 @@ pub struct ParlIoTx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
tx_channel: ChannelTx<'d, <PARL_IO as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
phantom: PhantomData<DM>,
} }
impl<DM> core::fmt::Debug for ParlIoTx<'_, DM> impl<DM> core::fmt::Debug for ParlIoTx<'_, DM>
@ -850,7 +845,6 @@ where
Ok(ParlIoRx { Ok(ParlIoRx {
rx_channel: self.rx_channel, rx_channel: self.rx_channel,
rx_chain: DescriptorChain::new(self.descriptors), rx_chain: DescriptorChain::new(self.descriptors),
phantom: PhantomData,
}) })
} }
} }
@ -880,7 +874,6 @@ where
Ok(ParlIoRx { Ok(ParlIoRx {
rx_channel: self.rx_channel, rx_channel: self.rx_channel,
rx_chain: DescriptorChain::new(self.descriptors), rx_chain: DescriptorChain::new(self.descriptors),
phantom: PhantomData,
}) })
} }
} }
@ -890,9 +883,8 @@ pub struct ParlIoRx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
rx_channel: ChannelRx<'d, <PARL_IO as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
phantom: PhantomData<DM>,
} }
impl<DM> core::fmt::Debug for ParlIoRx<'_, DM> impl<DM> core::fmt::Debug for ParlIoRx<'_, DM>
@ -1005,7 +997,7 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
/// Create a new instance of [ParlIoFullDuplex] /// Create a new instance of [ParlIoFullDuplex]
pub fn new<CH, DM>( pub fn new<CH, DM>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
dma_channel: Channel<'d, CH, DM>, dma_channel: Channel<'d, DM, CH>,
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32, frequency: HertzU32,
@ -1013,43 +1005,33 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
where where
DM: Mode, DM: Mode,
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>, CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>, Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{ {
let dma_channel = Channel::<'d, CH, Blocking>::from(dma_channel); let dma_channel = Channel::<Blocking, CH>::from(dma_channel);
internal_init(frequency)?; internal_init(frequency)?;
Ok(Self { Ok(Self {
tx: TxCreatorFullDuplex { tx: TxCreatorFullDuplex {
tx_channel: dma_channel.tx.degrade(), tx_channel: dma_channel.tx.degrade(),
descriptors: tx_descriptors, descriptors: tx_descriptors,
phantom: PhantomData,
}, },
rx: RxCreatorFullDuplex { rx: RxCreatorFullDuplex {
rx_channel: dma_channel.rx.degrade(), rx_channel: dma_channel.rx.degrade(),
descriptors: rx_descriptors, descriptors: rx_descriptors,
phantom: PhantomData,
}, },
}) })
} }
/// Convert to an async version. /// Convert to an async version.
pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> { pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> {
let channel = Channel {
tx: self.tx.tx_channel,
rx: self.rx.rx_channel,
phantom: PhantomData::<Blocking>,
};
let channel = channel.into_async();
ParlIoFullDuplex { ParlIoFullDuplex {
tx: TxCreatorFullDuplex { tx: TxCreatorFullDuplex {
tx_channel: channel.tx, tx_channel: self.tx.tx_channel.into_async(),
descriptors: self.tx.descriptors, descriptors: self.tx.descriptors,
phantom: PhantomData,
}, },
rx: RxCreatorFullDuplex { rx: RxCreatorFullDuplex {
rx_channel: channel.rx, rx_channel: self.rx.rx_channel.into_async(),
descriptors: self.rx.descriptors, descriptors: self.rx.descriptors,
phantom: PhantomData,
}, },
} }
} }
@ -1094,22 +1076,14 @@ impl InterruptConfigurable for ParlIoFullDuplex<'_, Blocking> {
impl<'d> ParlIoFullDuplex<'d, Async> { impl<'d> ParlIoFullDuplex<'d, Async> {
/// Convert to a blocking version. /// Convert to a blocking version.
pub fn into_blocking(self) -> ParlIoFullDuplex<'d, Blocking> { pub fn into_blocking(self) -> ParlIoFullDuplex<'d, Blocking> {
let channel = Channel {
tx: self.tx.tx_channel,
rx: self.rx.rx_channel,
phantom: PhantomData::<Async>,
};
let channel = channel.into_blocking();
ParlIoFullDuplex { ParlIoFullDuplex {
tx: TxCreatorFullDuplex { tx: TxCreatorFullDuplex {
tx_channel: channel.tx, tx_channel: self.tx.tx_channel.into_blocking(),
descriptors: self.tx.descriptors, descriptors: self.tx.descriptors,
phantom: PhantomData,
}, },
rx: RxCreatorFullDuplex { rx: RxCreatorFullDuplex {
rx_channel: channel.rx, rx_channel: self.rx.rx_channel.into_blocking(),
descriptors: self.rx.descriptors, descriptors: self.rx.descriptors,
phantom: PhantomData,
}, },
} }
} }
@ -1133,7 +1107,7 @@ where
// TODO: only take a TX DMA channel? // TODO: only take a TX DMA channel?
pub fn new<CH>( pub fn new<CH>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
dma_channel: Channel<'d, CH, DM>, dma_channel: Channel<'d, DM, CH>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32, frequency: HertzU32,
) -> Result<Self, Error> ) -> Result<Self, Error>
@ -1146,7 +1120,6 @@ where
tx: TxCreator { tx: TxCreator {
tx_channel: dma_channel.tx.degrade(), tx_channel: dma_channel.tx.degrade(),
descriptors, descriptors,
phantom: PhantomData,
}, },
}) })
} }
@ -1208,7 +1181,7 @@ where
// TODO: only take a RX DMA channel? // TODO: only take a RX DMA channel?
pub fn new<CH>( pub fn new<CH>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd, _parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
dma_channel: Channel<'d, CH, DM>, dma_channel: Channel<'d, DM, CH>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32, frequency: HertzU32,
) -> Result<Self, Error> ) -> Result<Self, Error>
@ -1221,7 +1194,6 @@ where
rx: RxCreator { rx: RxCreator {
rx_channel: dma_channel.rx.degrade(), rx_channel: dma_channel.rx.degrade(),
descriptors, descriptors,
phantom: PhantomData,
}, },
}) })
} }
@ -1372,7 +1344,7 @@ impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
type TX = ChannelTx<'d, <PARL_IO as DmaEligible>::Dma>; type TX = ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel &mut self.tx_channel
@ -1414,7 +1386,7 @@ where
} }
fn start_receive_bytes_dma( fn start_receive_bytes_dma(
rx_channel: &mut ChannelRx<'d, <PARL_IO as DmaEligible>::Dma>, rx_channel: &mut ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
rx_chain: &mut DescriptorChain, rx_chain: &mut DescriptorChain,
ptr: *mut u8, ptr: *mut u8,
len: usize, len: usize,
@ -1468,7 +1440,7 @@ impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
type RX = ChannelRx<'d, <PARL_IO as DmaEligible>::Dma>; type RX = ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel &mut self.rx_channel
@ -1484,9 +1456,8 @@ pub struct TxCreator<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
tx_channel: ChannelTx<'d, <PARL_IO as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
phantom: PhantomData<DM>,
} }
/// Creates a RX channel /// Creates a RX channel
@ -1494,9 +1465,8 @@ pub struct RxCreator<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
rx_channel: ChannelRx<'d, <PARL_IO as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
phantom: PhantomData<DM>,
} }
/// Creates a TX channel /// Creates a TX channel
@ -1504,9 +1474,8 @@ pub struct TxCreatorFullDuplex<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
tx_channel: ChannelTx<'d, <PARL_IO as DmaEligible>::Dma>, tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
phantom: PhantomData<DM>,
} }
/// Creates a RX channel /// Creates a RX channel
@ -1514,9 +1483,8 @@ pub struct RxCreatorFullDuplex<'d, DM>
where where
DM: Mode, DM: Mode,
{ {
rx_channel: ChannelRx<'d, <PARL_IO as DmaEligible>::Dma>, rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor], descriptors: &'static mut [DmaDescriptor],
phantom: PhantomData<DM>,
} }
#[doc(hidden)] #[doc(hidden)]

View File

@ -474,11 +474,11 @@ where
/// This method prepares the SPI instance for DMA transfers using SPI /// This method prepares the SPI instance for DMA transfers using SPI
/// and returns an instance of `SpiDma` that supports DMA /// and returns an instance of `SpiDma` that supports DMA
/// operations. /// operations.
pub fn with_dma<CH, DM>(self, channel: Channel<'d, CH, DM>) -> SpiDma<'d, M, T> pub fn with_dma<CH, DM>(self, channel: Channel<'d, DM, CH>) -> SpiDma<'d, M, T>
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DM: Mode, DM: Mode,
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>, Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
{ {
SpiDma::new(self.spi, channel.into()) SpiDma::new(self.spi, channel.into())
} }
@ -880,7 +880,7 @@ mod dma {
M: Mode, M: Mode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<'d, T::Dma, M>, pub(crate) channel: Channel<'d, M, T::Dma>,
tx_transfer_in_progress: bool, tx_transfer_in_progress: bool,
rx_transfer_in_progress: bool, rx_transfer_in_progress: bool,
#[cfg(all(esp32, spi_address_workaround))] #[cfg(all(esp32, spi_address_workaround))]
@ -990,7 +990,7 @@ mod dma {
T: Instance, T: Instance,
M: Mode, M: Mode,
{ {
pub(super) fn new<CH>(spi: PeripheralRef<'d, T>, channel: Channel<'d, CH, M>) -> Self pub(super) fn new<CH>(spi: PeripheralRef<'d, T>, channel: Channel<'d, M, CH>) -> Self
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
{ {
@ -3003,10 +3003,10 @@ macro_rules! spi_instance {
cs: OutputSignal::$cs, cs: OutputSignal::$cs,
sio0_input: InputSignal::$mosi, sio0_input: InputSignal::$mosi,
sio1_output: OutputSignal::$miso, sio1_output: OutputSignal::$miso,
sio2_output: if_set!($(Some(OutputSignal::$sio2))?, None), sio2_output: $crate::if_set!($(Some(OutputSignal::$sio2))?, None),
sio2_input: if_set!($(Some(InputSignal::$sio2))?, None), sio2_input: $crate::if_set!($(Some(InputSignal::$sio2))?, None),
sio3_output: if_set!($(Some(OutputSignal::$sio3))?, None), sio3_output: $crate::if_set!($(Some(OutputSignal::$sio3))?, None),
sio3_input: if_set!($(Some(InputSignal::$sio3))?, None), sio3_input: $crate::if_set!($(Some(InputSignal::$sio3))?, None),
}; };
&INFO &INFO
@ -3022,17 +3022,6 @@ macro_rules! spi_instance {
} }
} }
/// Macro to choose between two expressions. Useful for implementing "else" for
/// `$()?` macro syntax.
macro_rules! if_set {
(, $not_set:expr) => {
$not_set
};
($set:expr, $not_set:expr) => {
$set
};
}
#[cfg(spi2)] #[cfg(spi2)]
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(esp32)] { if #[cfg(esp32)] {

View File

@ -202,14 +202,14 @@ pub mod dma {
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
pub fn with_dma<CH, DM>( pub fn with_dma<CH, DM>(
self, self,
channel: Channel<'d, CH, DM>, channel: Channel<'d, DM, CH>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> SpiDma<'d, M, T> ) -> SpiDma<'d, M, T>
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DM: Mode, DM: Mode,
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>, Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
{ {
self.spi.info().set_data_mode(self.data_mode, true); self.spi.info().set_data_mode(self.data_mode, true);
SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors) SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors)
@ -223,7 +223,7 @@ pub mod dma {
M: Mode, M: Mode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<'d, T::Dma, M>, pub(crate) channel: Channel<'d, M, T::Dma>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
} }
@ -262,7 +262,7 @@ pub mod dma {
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, DmaMode: Mode,
{ {
type TX = ChannelTx<'d, T::Dma>; type TX = ChannelTx<'d, DmaMode, T::Dma>;
fn tx(&mut self) -> &mut Self::TX { fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx &mut self.channel.tx
@ -278,7 +278,7 @@ pub mod dma {
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, DmaMode: Mode,
{ {
type RX = ChannelRx<'d, T::Dma>; type RX = ChannelRx<'d, DmaMode, T::Dma>;
fn rx(&mut self) -> &mut Self::RX { fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx &mut self.channel.rx
@ -296,7 +296,7 @@ pub mod dma {
{ {
fn new<CH>( fn new<CH>(
spi: PeripheralRef<'d, T>, spi: PeripheralRef<'d, T>,
channel: Channel<'d, CH, DmaMode>, channel: Channel<'d, DmaMode, CH>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self

View File

@ -25,7 +25,7 @@ cfg_if::cfg_if! {
} }
struct Context { struct Context {
channel: Channel<'static, AnyGdmaChannel, Blocking>, channel: Channel<'static, Blocking, AnyGdmaChannel>,
dma_peripheral: DmaPeripheralType, dma_peripheral: DmaPeripheralType,
} }

View File

@ -90,27 +90,6 @@ mod tests {
xfer.wait().0.unwrap(); xfer.wait().0.unwrap();
} }
#[test]
fn test_i8080_8bit_async_channel(ctx: Context<'static>) {
let channel = ctx
.dma
.channel0
.configure(false, DmaPriority::Priority0)
.into_async();
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
let i8080 = I8080::new(
ctx.lcd_cam.lcd,
channel.tx,
pins,
20.MHz(),
Config::default(),
);
let xfer = i8080.send(Command::<u8>::None, 0, ctx.dma_buf).unwrap();
xfer.wait().0.unwrap();
}
#[test] #[test]
fn test_i8080_8bit_is_seen_by_pcnt(ctx: Context<'static>) { fn test_i8080_8bit_is_seen_by_pcnt(ctx: Context<'static>) {
// FIXME: Update this test to exercise all the I8080 output signals once the // FIXME: Update this test to exercise all the I8080 output signals once the

View File

@ -70,31 +70,4 @@ mod tests {
transfer.wait().0.unwrap(); transfer.wait().0.unwrap();
} }
#[test]
async fn test_i8080_8bit_async_channel(ctx: Context<'static>) {
let channel = ctx
.dma
.channel0
.configure(false, DmaPriority::Priority0)
.into_async();
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
let i8080 = I8080::new(
ctx.lcd_cam.lcd,
channel.tx,
pins,
20.MHz(),
Config::default(),
);
let mut transfer = i8080.send(Command::<u8>::None, 0, ctx.dma_buf).unwrap();
transfer.wait_for_done().await;
// This should not block forever and should immediately return.
transfer.wait_for_done().await;
transfer.wait().0.unwrap();
}
} }

View File

@ -43,7 +43,7 @@ struct Context {
spi: Spi<'static, Blocking>, spi: Spi<'static, Blocking>,
#[cfg(pcnt)] #[cfg(pcnt)]
pcnt: esp_hal::peripherals::PCNT, pcnt: esp_hal::peripherals::PCNT,
dma_channel: Channel<'static, DmaChannel0, Blocking>, dma_channel: Channel<'static, Blocking, DmaChannel0>,
gpios: [AnyPin; 3], gpios: [AnyPin; 3],
} }