mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 21:00:59 +00:00
[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:
parent
959631ee55
commit
38dde2ebbd
@ -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)
|
||||
- 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)
|
||||
- The `Camera` and `I8080` drivers' constructors now only accepts blocking-mode DMA channels. (#2519)
|
||||
|
||||
### 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)
|
||||
- `I2C` driver renamed to `I2c` (#2320)
|
||||
- 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
|
||||
|
||||
|
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
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.
|
||||
|
||||
@ -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
|
||||
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`
|
||||
|
||||
When trying to send a one-shot transmission will fail if it doesn't end with an end-marker.
|
||||
|
@ -276,21 +276,21 @@ pub mod dma {
|
||||
/// The underlying [`Aes`](super::Aes) driver
|
||||
pub aes: super::Aes<'d>,
|
||||
|
||||
channel: Channel<'d, <AES as DmaEligible>::Dma, Blocking>,
|
||||
channel: Channel<'d, Blocking, <AES as DmaEligible>::Dma>,
|
||||
rx_chain: DescriptorChain,
|
||||
tx_chain: DescriptorChain,
|
||||
}
|
||||
|
||||
impl<'d> crate::aes::Aes<'d> {
|
||||
/// Enable DMA for the current instance of the AES driver
|
||||
pub fn with_dma<C>(
|
||||
pub fn with_dma<CH>(
|
||||
self,
|
||||
channel: Channel<'d, C, Blocking>,
|
||||
channel: Channel<'d, Blocking, CH>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> AesDma<'d>
|
||||
where
|
||||
C: DmaChannelConvert<<AES as DmaEligible>::Dma>,
|
||||
CH: DmaChannelConvert<<AES as DmaEligible>::Dma>,
|
||||
{
|
||||
AesDma {
|
||||
aes: self,
|
||||
@ -324,7 +324,7 @@ pub mod dma {
|
||||
}
|
||||
|
||||
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 {
|
||||
&mut self.channel.tx
|
||||
@ -336,7 +336,7 @@ pub mod dma {
|
||||
}
|
||||
|
||||
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 {
|
||||
&mut self.channel.rx
|
||||
|
@ -25,6 +25,66 @@ use crate::{
|
||||
#[doc(hidden)]
|
||||
pub trait GdmaChannel {
|
||||
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
|
||||
@ -35,36 +95,6 @@ impl crate::private::Sealed for AnyGdmaChannel {}
|
||||
impl DmaChannel for AnyGdmaChannel {
|
||||
type Rx = ChannelRxImpl<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]
|
||||
@ -202,6 +232,14 @@ impl<C: GdmaChannel> TxRegisterAccess for ChannelTxImpl<C> {
|
||||
.out_eof_des_addr()
|
||||
.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> {
|
||||
@ -385,6 +423,14 @@ impl<C: GdmaChannel> RxRegisterAccess for ChannelRxImpl<C> {
|
||||
.in_conf0()
|
||||
.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> {
|
||||
@ -473,7 +519,7 @@ impl<C: GdmaChannel> InterruptAccess<DmaRxInterrupt> for ChannelRxImpl<C> {
|
||||
#[non_exhaustive]
|
||||
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.
|
||||
pub fn runtime_ensure_compatible<P: DmaEligible>(&self, _peripheral: &PeripheralRef<'_, P>) {
|
||||
// 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 {
|
||||
($num: literal, $async_handler: path, $($interrupt: ident),* ) => {
|
||||
($num:literal, $interrupt_in:ident, $async_handler:path $(, $interrupt_out:ident , $async_handler_out:path)? ) => {
|
||||
paste::paste! {
|
||||
/// A description of a specific GDMA channel
|
||||
#[non_exhaustive]
|
||||
@ -490,26 +536,26 @@ macro_rules! impl_channel {
|
||||
impl crate::private::Sealed for [<DmaChannel $num>] {}
|
||||
|
||||
impl [<DmaChannel $num>] {
|
||||
fn handler() -> InterruptHandler {
|
||||
$async_handler
|
||||
fn handler_in() -> Option<InterruptHandler> {
|
||||
Some($async_handler)
|
||||
}
|
||||
|
||||
fn isrs() -> &'static [Interrupt] {
|
||||
&[$(Interrupt::$interrupt),*]
|
||||
fn isr_in() -> Option<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>] {
|
||||
type Rx = ChannelRxImpl<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>] {
|
||||
@ -537,11 +583,10 @@ macro_rules! impl_channel {
|
||||
self,
|
||||
burst_mode: bool,
|
||||
priority: DmaPriority,
|
||||
) -> Channel<'a, [<DmaChannel $num>], Blocking> {
|
||||
) -> Channel<'a, Blocking, [<DmaChannel $num>]> {
|
||||
let mut this = Channel {
|
||||
tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})),
|
||||
rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})),
|
||||
phantom: PhantomData,
|
||||
};
|
||||
|
||||
this.configure(burst_mode, priority);
|
||||
@ -553,27 +598,29 @@ macro_rules! impl_channel {
|
||||
};
|
||||
}
|
||||
|
||||
use super::asynch::interrupt as asynch_handler;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(esp32c2)] {
|
||||
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)] {
|
||||
const CHANNEL_COUNT: usize = 3;
|
||||
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0);
|
||||
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_CH1);
|
||||
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_CH2);
|
||||
impl_channel!(0, DMA_CH0, asynch_handler::interrupt_handler_ch0);
|
||||
impl_channel!(1, DMA_CH1, asynch_handler::interrupt_handler_ch1);
|
||||
impl_channel!(2, DMA_CH2, asynch_handler::interrupt_handler_ch2);
|
||||
} else if #[cfg(any(esp32c6, esp32h2))] {
|
||||
const CHANNEL_COUNT: usize = 3;
|
||||
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0);
|
||||
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1);
|
||||
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2);
|
||||
impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0);
|
||||
impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1);
|
||||
impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2);
|
||||
} else if #[cfg(esp32s3)] {
|
||||
const CHANNEL_COUNT: usize = 5;
|
||||
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0);
|
||||
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1);
|
||||
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2);
|
||||
impl_channel!(3, super::asynch::interrupt::interrupt_handler_ch3, DMA_IN_CH3, DMA_OUT_CH3);
|
||||
impl_channel!(4, super::asynch::interrupt::interrupt_handler_ch4, DMA_IN_CH4, DMA_OUT_CH4);
|
||||
impl_channel!(0, DMA_IN_CH0, asynch_handler::interrupt_handler_ch0, DMA_OUT_CH0, asynch_handler::interrupt_handler_ch0);
|
||||
impl_channel!(1, DMA_IN_CH1, asynch_handler::interrupt_handler_ch1, DMA_OUT_CH1, asynch_handler::interrupt_handler_ch1);
|
||||
impl_channel!(2, DMA_IN_CH2, asynch_handler::interrupt_handler_ch2, DMA_OUT_CH2, asynch_handler::interrupt_handler_ch2);
|
||||
impl_channel!(3, DMA_IN_CH3, asynch_handler::interrupt_handler_ch3, DMA_OUT_CH3, asynch_handler::interrupt_handler_ch3);
|
||||
impl_channel!(4, DMA_IN_CH4, asynch_handler::interrupt_handler_ch4, DMA_OUT_CH4, asynch_handler::interrupt_handler_ch4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ pub struct Mem2Mem<'d, M>
|
||||
where
|
||||
M: Mode,
|
||||
{
|
||||
channel: Channel<'d, AnyGdmaChannel, M>,
|
||||
channel: Channel<'d, M, AnyGdmaChannel>,
|
||||
rx_chain: DescriptorChain,
|
||||
tx_chain: DescriptorChain,
|
||||
peripheral: DmaPeripheral,
|
||||
@ -41,7 +41,7 @@ where
|
||||
impl<'d> Mem2Mem<'d, Blocking> {
|
||||
/// Create a new Mem2Mem instance.
|
||||
pub fn new<CH, DM>(
|
||||
channel: Channel<'d, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
peripheral: impl DmaEligible,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
@ -49,7 +49,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
where
|
||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||
DM: Mode,
|
||||
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
unsafe {
|
||||
Self::new_unsafe(
|
||||
@ -64,7 +64,7 @@ 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, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
peripheral: impl DmaEligible,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
@ -73,7 +73,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
where
|
||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||
DM: Mode,
|
||||
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
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
|
||||
/// that your the only one using the DmaPeripheral.
|
||||
pub unsafe fn new_unsafe<CH, DM>(
|
||||
channel: Channel<'d, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
peripheral: DmaPeripheral,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
@ -102,7 +102,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
where
|
||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||
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) {
|
||||
return Err(DmaError::InvalidChunkSize);
|
||||
@ -111,7 +111,7 @@ impl<'d> Mem2Mem<'d, Blocking> {
|
||||
return Err(DmaError::OutOfDescriptors);
|
||||
}
|
||||
Ok(Mem2Mem {
|
||||
channel: Channel::<_, Blocking>::from(channel).degrade(),
|
||||
channel: Channel::<Blocking, _>::from(channel).degrade(),
|
||||
peripheral,
|
||||
rx_chain: DescriptorChain::new_with_chunk_size(rx_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
|
||||
MODE: Mode,
|
||||
M: Mode,
|
||||
{
|
||||
type RX = ChannelRx<'d, AnyGdmaChannel>;
|
||||
type RX = ChannelRx<'d, M, AnyGdmaChannel>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.channel.rx
|
||||
|
@ -1571,12 +1571,6 @@ pub trait DmaChannel: crate::private::Sealed + Sized {
|
||||
|
||||
/// A description of the TX half of a DMA Channel.
|
||||
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)]
|
||||
@ -1666,16 +1660,16 @@ pub trait Rx: crate::private::Sealed {
|
||||
// DMA receive channel
|
||||
#[non_exhaustive]
|
||||
#[doc(hidden)]
|
||||
pub struct ChannelRx<'a, CH>
|
||||
pub struct ChannelRx<'a, M, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
{
|
||||
pub(crate) burst_mode: bool,
|
||||
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
|
||||
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.
|
||||
#[doc(hidden)]
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> ChannelRx<'a, DEG>
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> ChannelRx<'a, M, DEG>
|
||||
where
|
||||
CH: DmaChannelConvert<DEG>,
|
||||
{
|
||||
@ -1712,10 +1757,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<CH> crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {}
|
||||
|
||||
impl<CH> Rx for ChannelRx<'_, CH>
|
||||
impl<M, CH> crate::private::Sealed for ChannelRx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
}
|
||||
|
||||
impl<M, CH> Rx for ChannelRx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
unsafe fn prepare_transfer_without_start(
|
||||
@ -1894,17 +1945,17 @@ pub trait Tx: crate::private::Sealed {
|
||||
|
||||
/// DMA transmit channel
|
||||
#[doc(hidden)]
|
||||
pub struct ChannelTx<'a, CH>
|
||||
pub struct ChannelTx<'a, M, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
{
|
||||
#[allow(unused)]
|
||||
pub(crate) burst_mode: bool,
|
||||
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
|
||||
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.
|
||||
#[doc(hidden)]
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> ChannelTx<'a, DEG>
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> ChannelTx<'a, M, DEG>
|
||||
where
|
||||
CH: DmaChannelConvert<DEG>,
|
||||
{
|
||||
@ -1936,10 +2038,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<CH> crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {}
|
||||
|
||||
impl<CH> Tx for ChannelTx<'_, CH>
|
||||
impl<M, CH> crate::private::Sealed for ChannelTx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
}
|
||||
|
||||
impl<M, CH> Tx for ChannelTx<'_, M, CH>
|
||||
where
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
unsafe fn prepare_transfer_without_start(
|
||||
@ -2116,6 +2224,9 @@ pub trait RegisterAccess: crate::private::Sealed {
|
||||
pub trait RxRegisterAccess: RegisterAccess {
|
||||
#[cfg(gdma)]
|
||||
fn set_mem2mem_mode(&self, value: bool);
|
||||
|
||||
fn peripheral_interrupt(&self) -> Option<Interrupt>;
|
||||
fn async_handler(&self) -> Option<InterruptHandler>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -2125,6 +2236,9 @@ pub trait TxRegisterAccess: RegisterAccess {
|
||||
|
||||
/// Outlink descriptor address when EOF occurs of Tx channel.
|
||||
fn last_dscr_address(&self) -> usize;
|
||||
|
||||
fn peripheral_interrupt(&self) -> Option<Interrupt>;
|
||||
fn async_handler(&self) -> Option<InterruptHandler>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -2148,38 +2262,30 @@ pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
|
||||
}
|
||||
|
||||
/// DMA Channel
|
||||
pub struct Channel<'d, CH, M>
|
||||
pub struct Channel<'d, M, CH>
|
||||
where
|
||||
CH: DmaChannel,
|
||||
M: Mode,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
/// RX half of the channel
|
||||
pub rx: ChannelRx<'d, CH>,
|
||||
pub rx: ChannelRx<'d, M, CH>,
|
||||
/// TX half of the channel
|
||||
pub tx: ChannelTx<'d, CH>,
|
||||
pub(crate) phantom: PhantomData<M>,
|
||||
pub tx: ChannelTx<'d, M, CH>,
|
||||
}
|
||||
|
||||
impl<'d, C> Channel<'d, C, Blocking>
|
||||
impl<'d, CH> Channel<'d, Blocking, CH>
|
||||
where
|
||||
C: DmaChannel,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
/// 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
|
||||
C: DmaChannel,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
self.unlisten(EnumSet::all());
|
||||
self.clear_interrupts(EnumSet::all());
|
||||
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()));
|
||||
}
|
||||
self.rx.set_interrupt_handler(handler);
|
||||
self.tx.set_interrupt_handler(handler);
|
||||
}
|
||||
|
||||
/// Listen for the given interrupts
|
||||
@ -2226,67 +2332,59 @@ where
|
||||
|
||||
/// Configure the channel.
|
||||
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
|
||||
self.tx.configure(burst_mode, priority);
|
||||
self.rx.configure(burst_mode, priority);
|
||||
self.tx.configure(burst_mode, priority);
|
||||
}
|
||||
|
||||
/// Converts a blocking channel to an async channel.
|
||||
pub fn into_async(mut self) -> Channel<'d, C, Async> {
|
||||
self.set_interrupt_handler(C::async_handler(&self));
|
||||
|
||||
pub fn into_async(self) -> Channel<'d, Async, CH> {
|
||||
Channel {
|
||||
tx: self.tx,
|
||||
rx: self.rx,
|
||||
phantom: PhantomData,
|
||||
rx: self.rx.into_async(),
|
||||
tx: self.tx.into_async(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, C> Channel<'d, C, Async>
|
||||
impl<'d, CH> Channel<'d, Async, CH>
|
||||
where
|
||||
C: DmaChannel,
|
||||
CH: DmaChannel,
|
||||
{
|
||||
/// Converts an async channel to a blocking channel.
|
||||
pub fn into_blocking(self) -> Channel<'d, C, Blocking> {
|
||||
for interrupt in C::interrupts(&self).iter().copied() {
|
||||
crate::interrupt::disable(Cpu::current(), interrupt);
|
||||
}
|
||||
|
||||
pub fn into_blocking(self) -> Channel<'d, Blocking, CH> {
|
||||
Channel {
|
||||
tx: self.tx,
|
||||
rx: self.rx,
|
||||
phantom: PhantomData,
|
||||
rx: self.rx.into_blocking(),
|
||||
tx: self.tx.into_blocking(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, C: DmaChannel> From<Channel<'d, C, Blocking>> for Channel<'d, C, Async> {
|
||||
fn from(channel: Channel<'d, C, Blocking>) -> Self {
|
||||
impl<'d, CH: DmaChannel> From<Channel<'d, Blocking, CH>> for Channel<'d, Async, CH> {
|
||||
fn from(channel: Channel<'d, Blocking, CH>) -> Self {
|
||||
channel.into_async()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, C: DmaChannel> From<Channel<'d, C, Async>> for Channel<'d, C, Blocking> {
|
||||
fn from(channel: Channel<'d, C, Async>) -> Self {
|
||||
impl<'d, CH: DmaChannel> From<Channel<'d, Async, CH>> for Channel<'d, Blocking, CH> {
|
||||
fn from(channel: Channel<'d, Async, CH>) -> Self {
|
||||
channel.into_blocking()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, CH, M: Mode> Channel<'d, CH, M>
|
||||
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, DEG, M>
|
||||
pub fn degrade<DEG: DmaChannel>(self) -> Channel<'d, M, DEG>
|
||||
where
|
||||
CH: DmaChannelConvert<DEG>,
|
||||
{
|
||||
Channel {
|
||||
rx: self.rx.degrade(),
|
||||
tx: self.tx.degrade(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ pub trait PdmaChannel: crate::private::Sealed {
|
||||
fn tx_waker(&self) -> &'static AtomicWaker;
|
||||
fn rx_waker(&self) -> &'static AtomicWaker;
|
||||
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
|
||||
|
||||
fn peripheral_interrupt(&self) -> Interrupt;
|
||||
fn async_handler(&self) -> InterruptHandler;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -107,6 +110,14 @@ impl<C: PdmaChannel<RegisterBlock = SpiRegisterBlock>> TxRegisterAccess for SpiD
|
||||
let spi = self.0.register_block();
|
||||
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>
|
||||
@ -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>
|
||||
for SpiDmaRxChannelImpl<C>
|
||||
@ -343,27 +362,9 @@ macro_rules! ImplSpiChannel {
|
||||
#[non_exhaustive]
|
||||
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>] {
|
||||
type Rx = SpiDmaRxChannelImpl<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>] {
|
||||
@ -393,6 +394,14 @@ macro_rules! ImplSpiChannel {
|
||||
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
|
||||
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>] {
|
||||
@ -416,11 +425,10 @@ macro_rules! ImplSpiChannel {
|
||||
self,
|
||||
burst_mode: bool,
|
||||
priority: DmaPriority,
|
||||
) -> Channel<'a, [<Spi $num DmaChannel>], Blocking> {
|
||||
) -> Channel<'a, Blocking, [<Spi $num DmaChannel>]> {
|
||||
let mut this = Channel {
|
||||
tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})),
|
||||
rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})),
|
||||
phantom: PhantomData,
|
||||
};
|
||||
|
||||
this.configure(burst_mode, priority);
|
||||
@ -518,6 +526,14 @@ impl<C: PdmaChannel<RegisterBlock = I2sRegisterBlock>> TxRegisterAccess for I2sD
|
||||
.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 = 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>
|
||||
for I2sDmaRxChannelImpl<C>
|
||||
@ -756,27 +780,9 @@ macro_rules! ImplI2sChannel {
|
||||
|
||||
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>] {
|
||||
type Rx = I2sDmaRxChannelImpl<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>] {
|
||||
@ -805,6 +811,14 @@ macro_rules! ImplI2sChannel {
|
||||
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
|
||||
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>] {
|
||||
@ -825,11 +839,10 @@ macro_rules! ImplI2sChannel {
|
||||
self,
|
||||
burst_mode: bool,
|
||||
priority: DmaPriority,
|
||||
) -> Channel<'a, [<I2s $num DmaChannel>], Blocking> {
|
||||
) -> Channel<'a, Blocking, [<I2s $num DmaChannel>]> {
|
||||
let mut this = Channel {
|
||||
tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})),
|
||||
rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})),
|
||||
phantom: PhantomData,
|
||||
};
|
||||
|
||||
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
|
||||
C: DmaChannel,
|
||||
CH: DmaChannel,
|
||||
M: Mode,
|
||||
{
|
||||
/// Asserts that the channel is compatible with the given peripheral.
|
||||
pub fn runtime_ensure_compatible(&self, peripheral: &PeripheralRef<'_, impl DmaEligible>) {
|
||||
@ -928,20 +942,6 @@ impl crate::private::Sealed for AnySpiDmaChannel {}
|
||||
impl DmaChannel for AnySpiDmaChannel {
|
||||
type Rx = SpiDmaRxChannelImpl<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! {
|
||||
@ -966,6 +966,8 @@ impl PdmaChannel for AnySpiDmaChannelInner {
|
||||
fn tx_waker(&self) -> &'static AtomicWaker;
|
||||
fn rx_waker(&self) -> &'static AtomicWaker;
|
||||
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 {
|
||||
type Rx = I2sDmaRxChannelImpl<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! {
|
||||
@ -1020,6 +1006,8 @@ impl PdmaChannel for AnyI2sDmaChannelInner {
|
||||
fn tx_waker(&self) -> &'static AtomicWaker;
|
||||
fn rx_waker(&self) -> &'static AtomicWaker;
|
||||
fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool;
|
||||
fn peripheral_interrupt(&self) -> Interrupt;
|
||||
fn async_handler(&self) -> InterruptHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,8 +74,6 @@
|
||||
//!
|
||||
//! - Only TDM Philips standard is supported.
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
use private::*;
|
||||
|
||||
@ -251,6 +249,7 @@ impl DataFormat {
|
||||
}
|
||||
|
||||
/// Instance of the I2S peripheral driver
|
||||
#[non_exhaustive]
|
||||
pub struct I2s<'d, M, T = AnyI2s>
|
||||
where
|
||||
T: RegisterAccess,
|
||||
@ -260,7 +259,6 @@ where
|
||||
pub i2s_rx: RxCreator<'d, M, T>,
|
||||
/// Handles the transmission (TX) side of the I2S peripheral.
|
||||
pub i2s_tx: TxCreator<'d, M, T>,
|
||||
phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'d, DmaMode, T> I2s<'d, DmaMode, T>
|
||||
@ -274,7 +272,7 @@ where
|
||||
standard: Standard,
|
||||
data_format: DataFormat,
|
||||
sample_rate: impl Into<fugit::HertzU32>,
|
||||
channel: Channel<'d, CH, DmaMode>,
|
||||
channel: Channel<'d, DmaMode, CH>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
@ -299,15 +297,12 @@ where
|
||||
i2s: unsafe { i2s.clone_unchecked() },
|
||||
rx_channel: channel.rx,
|
||||
descriptors: rx_descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
i2s_tx: TxCreator {
|
||||
i2s,
|
||||
tx_channel: channel.tx,
|
||||
descriptors: tx_descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -376,14 +371,14 @@ impl<'d> I2s<'d, Blocking> {
|
||||
standard: Standard,
|
||||
data_format: DataFormat,
|
||||
sample_rate: impl Into<fugit::HertzU32>,
|
||||
channel: Channel<'d, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
|
||||
DM: Mode,
|
||||
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
Self::new_typed(
|
||||
i2s.map_into(),
|
||||
@ -409,14 +404,14 @@ where
|
||||
standard: Standard,
|
||||
data_format: DataFormat,
|
||||
sample_rate: impl Into<fugit::HertzU32>,
|
||||
channel: Channel<'d, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
DM: Mode,
|
||||
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
crate::into_ref!(i2s);
|
||||
Self::new_internal(
|
||||
@ -432,26 +427,17 @@ where
|
||||
|
||||
/// Converts the SPI instance into async mode.
|
||||
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_rx: RxCreator {
|
||||
i2s: self.i2s_rx.i2s,
|
||||
rx_channel: channel.rx,
|
||||
rx_channel: self.i2s_rx.rx_channel.into_async(),
|
||||
descriptors: self.i2s_rx.descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
i2s_tx: TxCreator {
|
||||
i2s: self.i2s_tx.i2s,
|
||||
tx_channel: channel.tx,
|
||||
tx_channel: self.i2s_tx.tx_channel.into_async(),
|
||||
descriptors: self.i2s_tx.descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -477,9 +463,8 @@ where
|
||||
T: RegisterAccess,
|
||||
{
|
||||
i2s: PeripheralRef<'d, T>,
|
||||
tx_channel: ChannelTx<'d, T::Dma>,
|
||||
tx_channel: ChannelTx<'d, DmaMode, T::Dma>,
|
||||
tx_chain: DescriptorChain,
|
||||
phantom: PhantomData<DmaMode>,
|
||||
}
|
||||
|
||||
impl<DmaMode, T> core::fmt::Debug for I2sTx<'_, DmaMode, T>
|
||||
@ -511,7 +496,7 @@ where
|
||||
T: RegisterAccess,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type TX = ChannelTx<'d, T::Dma>;
|
||||
type TX = ChannelTx<'d, DmaMode, T::Dma>;
|
||||
|
||||
fn tx(&mut self) -> &mut Self::TX {
|
||||
&mut self.tx_channel
|
||||
@ -610,9 +595,8 @@ where
|
||||
DmaMode: Mode,
|
||||
{
|
||||
i2s: PeripheralRef<'d, T>,
|
||||
rx_channel: ChannelRx<'d, T::Dma>,
|
||||
rx_channel: ChannelRx<'d, DmaMode, T::Dma>,
|
||||
rx_chain: DescriptorChain,
|
||||
phantom: PhantomData<DmaMode>,
|
||||
}
|
||||
|
||||
impl<DmaMode, T> core::fmt::Debug for I2sRx<'_, DmaMode, T>
|
||||
@ -644,7 +628,7 @@ where
|
||||
T: RegisterAccess,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type RX = ChannelRx<'d, T::Dma>;
|
||||
type RX = ChannelRx<'d, DmaMode, T::Dma>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.rx_channel
|
||||
@ -750,8 +734,6 @@ pub trait RegisterAccess: RegisterAccessPrivate {}
|
||||
impl<T> RegisterAccess for T where T: RegisterAccessPrivate {}
|
||||
|
||||
mod private {
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use enumset::EnumSet;
|
||||
use fugit::HertzU32;
|
||||
|
||||
@ -790,22 +772,20 @@ mod private {
|
||||
M: Mode,
|
||||
{
|
||||
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(crate) phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T>
|
||||
impl<'d, M, T> TxCreator<'d, M, T>
|
||||
where
|
||||
M: Mode,
|
||||
T: RegisterAccess,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
pub fn build(self) -> I2sTx<'d, DmaMode, T> {
|
||||
pub fn build(self) -> I2sTx<'d, M, T> {
|
||||
I2sTx {
|
||||
i2s: self.i2s,
|
||||
tx_channel: self.tx_channel,
|
||||
tx_chain: DescriptorChain::new(self.descriptors),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -849,22 +829,20 @@ mod private {
|
||||
M: Mode,
|
||||
{
|
||||
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(crate) phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'d, M, T> RxCreator<'d, M, T>
|
||||
where
|
||||
T: RegisterAccess,
|
||||
M: Mode,
|
||||
T: RegisterAccess,
|
||||
{
|
||||
pub fn build(self) -> I2sRx<'d, M, T> {
|
||||
I2sRx {
|
||||
i2s: self.i2s,
|
||||
rx_channel: self.rx_channel,
|
||||
rx_chain: DescriptorChain::new(self.descriptors),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
||||
//! - `DMA`
|
||||
//! - `system` (to configure and enable the I2S peripheral)
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
mem::ManuallyDrop,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
@ -177,8 +176,7 @@ where
|
||||
I: Instance,
|
||||
{
|
||||
instance: PeripheralRef<'d, I>,
|
||||
tx_channel: ChannelTx<'d, I::Dma>,
|
||||
mode: PhantomData<DM>,
|
||||
tx_channel: ChannelTx<'d, DM, I::Dma>,
|
||||
}
|
||||
|
||||
impl<'d, DM> I2sParallel<'d, DM>
|
||||
@ -188,7 +186,7 @@ where
|
||||
/// Create a new I2S Parallel Interface
|
||||
pub fn new<CH>(
|
||||
i2s: impl Peripheral<P = impl Instance> + 'd,
|
||||
channel: Channel<'d, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
frequency: impl Into<fugit::HertzU32>,
|
||||
pins: impl TxPins<'d>,
|
||||
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
|
||||
@ -208,7 +206,7 @@ where
|
||||
/// Create a new I2S Parallel Interface
|
||||
pub fn new_typed<CH>(
|
||||
i2s: impl Peripheral<P = I> + 'd,
|
||||
channel: Channel<'d, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
frequency: impl Into<fugit::HertzU32>,
|
||||
mut pins: impl TxPins<'d>,
|
||||
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
|
||||
@ -234,7 +232,6 @@ where
|
||||
Self {
|
||||
instance: i2s,
|
||||
tx_channel: channel.tx,
|
||||
mode: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ use crate::{
|
||||
lcd_cam::{calculate_clkm, BitOrder, ByteOrder},
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::LCD_CAM,
|
||||
Blocking,
|
||||
};
|
||||
|
||||
/// Generation of GDMA SUC EOF
|
||||
@ -125,14 +126,14 @@ 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, <LCD_CAM as DmaEligible>::Dma>,
|
||||
rx_channel: ChannelRx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>,
|
||||
}
|
||||
|
||||
impl<'d> Camera<'d> {
|
||||
/// Creates a new `Camera` instance with DMA support.
|
||||
pub fn new<P, CH>(
|
||||
cam: Cam<'d>,
|
||||
channel: ChannelRx<'d, CH>,
|
||||
channel: ChannelRx<'d, Blocking, CH>,
|
||||
_pins: P,
|
||||
frequency: HertzU32,
|
||||
) -> Self
|
||||
|
@ -83,21 +83,25 @@ use crate::{
|
||||
},
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::LCD_CAM,
|
||||
Blocking,
|
||||
Mode,
|
||||
};
|
||||
|
||||
/// Represents the I8080 LCD interface.
|
||||
pub struct I8080<'d, DM: Mode> {
|
||||
lcd_cam: PeripheralRef<'d, LCD_CAM>,
|
||||
tx_channel: ChannelTx<'d, <LCD_CAM as DmaEligible>::Dma>,
|
||||
_phantom: PhantomData<DM>,
|
||||
tx_channel: ChannelTx<'d, Blocking, <LCD_CAM as DmaEligible>::Dma>,
|
||||
_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.
|
||||
pub fn new<P, CH>(
|
||||
lcd: Lcd<'d, DM>,
|
||||
channel: ChannelTx<'d, CH>,
|
||||
channel: ChannelTx<'d, Blocking, CH>,
|
||||
mut pins: P,
|
||||
frequency: HertzU32,
|
||||
config: Config,
|
||||
@ -209,12 +213,10 @@ impl<'d, DM: Mode> I8080<'d, DM> {
|
||||
Self {
|
||||
lcd_cam,
|
||||
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.
|
||||
/// This must be set to [ByteOrder::default()] when transmitting in 8-bit
|
||||
/// mode.
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -23,8 +23,6 @@
|
||||
//!
|
||||
//! [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 fugit::HertzU32;
|
||||
use peripheral::PeripheralRef;
|
||||
@ -769,7 +767,6 @@ where
|
||||
Ok(ParlIoTx {
|
||||
tx_channel: self.tx_channel,
|
||||
tx_chain: DescriptorChain::new(self.descriptors),
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -801,7 +798,6 @@ where
|
||||
Ok(ParlIoTx {
|
||||
tx_channel: self.tx_channel,
|
||||
tx_chain: DescriptorChain::new(self.descriptors),
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -811,9 +807,8 @@ pub struct ParlIoTx<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
tx_channel: ChannelTx<'d, <PARL_IO as DmaEligible>::Dma>,
|
||||
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
tx_chain: DescriptorChain,
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
impl<DM> core::fmt::Debug for ParlIoTx<'_, DM>
|
||||
@ -850,7 +845,6 @@ where
|
||||
Ok(ParlIoRx {
|
||||
rx_channel: self.rx_channel,
|
||||
rx_chain: DescriptorChain::new(self.descriptors),
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -880,7 +874,6 @@ where
|
||||
Ok(ParlIoRx {
|
||||
rx_channel: self.rx_channel,
|
||||
rx_chain: DescriptorChain::new(self.descriptors),
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -890,9 +883,8 @@ pub struct ParlIoRx<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
rx_channel: ChannelRx<'d, <PARL_IO as DmaEligible>::Dma>,
|
||||
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
|
||||
rx_chain: DescriptorChain,
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
impl<DM> core::fmt::Debug for ParlIoRx<'_, DM>
|
||||
@ -1005,7 +997,7 @@ 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, CH, DM>,
|
||||
dma_channel: Channel<'d, DM, CH>,
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
frequency: HertzU32,
|
||||
@ -1013,43 +1005,33 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
|
||||
where
|
||||
DM: Mode,
|
||||
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)?;
|
||||
|
||||
Ok(Self {
|
||||
tx: TxCreatorFullDuplex {
|
||||
tx_channel: dma_channel.tx.degrade(),
|
||||
descriptors: tx_descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
rx: RxCreatorFullDuplex {
|
||||
rx_channel: dma_channel.rx.degrade(),
|
||||
descriptors: rx_descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert to an async version.
|
||||
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 {
|
||||
tx: TxCreatorFullDuplex {
|
||||
tx_channel: channel.tx,
|
||||
tx_channel: self.tx.tx_channel.into_async(),
|
||||
descriptors: self.tx.descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
rx: RxCreatorFullDuplex {
|
||||
rx_channel: channel.rx,
|
||||
rx_channel: self.rx.rx_channel.into_async(),
|
||||
descriptors: self.rx.descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1094,22 +1076,14 @@ impl InterruptConfigurable for ParlIoFullDuplex<'_, Blocking> {
|
||||
impl<'d> ParlIoFullDuplex<'d, Async> {
|
||||
/// Convert to a blocking version.
|
||||
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 {
|
||||
tx: TxCreatorFullDuplex {
|
||||
tx_channel: channel.tx,
|
||||
tx_channel: self.tx.tx_channel.into_blocking(),
|
||||
descriptors: self.tx.descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
rx: RxCreatorFullDuplex {
|
||||
rx_channel: channel.rx,
|
||||
rx_channel: self.rx.rx_channel.into_blocking(),
|
||||
descriptors: self.rx.descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1133,7 +1107,7 @@ where
|
||||
// TODO: only take a TX DMA channel?
|
||||
pub fn new<CH>(
|
||||
_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],
|
||||
frequency: HertzU32,
|
||||
) -> Result<Self, Error>
|
||||
@ -1146,7 +1120,6 @@ where
|
||||
tx: TxCreator {
|
||||
tx_channel: dma_channel.tx.degrade(),
|
||||
descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -1208,7 +1181,7 @@ where
|
||||
// TODO: only take a RX DMA channel?
|
||||
pub fn new<CH>(
|
||||
_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],
|
||||
frequency: HertzU32,
|
||||
) -> Result<Self, Error>
|
||||
@ -1221,7 +1194,6 @@ where
|
||||
rx: RxCreator {
|
||||
rx_channel: dma_channel.rx.degrade(),
|
||||
descriptors,
|
||||
phantom: PhantomData,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -1372,7 +1344,7 @@ impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM>
|
||||
where
|
||||
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 {
|
||||
&mut self.tx_channel
|
||||
@ -1414,7 +1386,7 @@ where
|
||||
}
|
||||
|
||||
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,
|
||||
ptr: *mut u8,
|
||||
len: usize,
|
||||
@ -1468,7 +1440,7 @@ impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM>
|
||||
where
|
||||
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 {
|
||||
&mut self.rx_channel
|
||||
@ -1484,9 +1456,8 @@ pub struct TxCreator<'d, DM>
|
||||
where
|
||||
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],
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
/// Creates a RX channel
|
||||
@ -1494,9 +1465,8 @@ pub struct RxCreator<'d, DM>
|
||||
where
|
||||
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],
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
/// Creates a TX channel
|
||||
@ -1504,9 +1474,8 @@ pub struct TxCreatorFullDuplex<'d, DM>
|
||||
where
|
||||
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],
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
/// Creates a RX channel
|
||||
@ -1514,9 +1483,8 @@ pub struct RxCreatorFullDuplex<'d, DM>
|
||||
where
|
||||
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],
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -474,11 +474,11 @@ where
|
||||
/// 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, CH, DM>) -> SpiDma<'d, M, T>
|
||||
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, CH, M>: From<Channel<'d, CH, DM>>,
|
||||
Channel<'d, M, CH>: From<Channel<'d, DM, CH>>,
|
||||
{
|
||||
SpiDma::new(self.spi, channel.into())
|
||||
}
|
||||
@ -880,7 +880,7 @@ mod dma {
|
||||
M: Mode,
|
||||
{
|
||||
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,
|
||||
rx_transfer_in_progress: bool,
|
||||
#[cfg(all(esp32, spi_address_workaround))]
|
||||
@ -990,7 +990,7 @@ mod dma {
|
||||
T: Instance,
|
||||
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
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
{
|
||||
@ -3003,10 +3003,10 @@ macro_rules! spi_instance {
|
||||
cs: OutputSignal::$cs,
|
||||
sio0_input: InputSignal::$mosi,
|
||||
sio1_output: OutputSignal::$miso,
|
||||
sio2_output: if_set!($(Some(OutputSignal::$sio2))?, None),
|
||||
sio2_input: if_set!($(Some(InputSignal::$sio2))?, None),
|
||||
sio3_output: if_set!($(Some(OutputSignal::$sio3))?, None),
|
||||
sio3_input: if_set!($(Some(InputSignal::$sio3))?, None),
|
||||
sio2_output: $crate::if_set!($(Some(OutputSignal::$sio2))?, None),
|
||||
sio2_input: $crate::if_set!($(Some(InputSignal::$sio2))?, None),
|
||||
sio3_output: $crate::if_set!($(Some(OutputSignal::$sio3))?, None),
|
||||
sio3_input: $crate::if_set!($(Some(InputSignal::$sio3))?, None),
|
||||
};
|
||||
|
||||
&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_if::cfg_if! {
|
||||
if #[cfg(esp32)] {
|
||||
|
@ -202,14 +202,14 @@ pub mod dma {
|
||||
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
|
||||
pub fn with_dma<CH, DM>(
|
||||
self,
|
||||
channel: Channel<'d, CH, DM>,
|
||||
channel: Channel<'d, DM, CH>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> SpiDma<'d, M, T>
|
||||
where
|
||||
CH: DmaChannelConvert<T::Dma>,
|
||||
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);
|
||||
SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors)
|
||||
@ -223,7 +223,7 @@ pub mod dma {
|
||||
M: Mode,
|
||||
{
|
||||
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,
|
||||
tx_chain: DescriptorChain,
|
||||
}
|
||||
@ -262,7 +262,7 @@ pub mod dma {
|
||||
T: InstanceDma,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type TX = ChannelTx<'d, T::Dma>;
|
||||
type TX = ChannelTx<'d, DmaMode, T::Dma>;
|
||||
|
||||
fn tx(&mut self) -> &mut Self::TX {
|
||||
&mut self.channel.tx
|
||||
@ -278,7 +278,7 @@ pub mod dma {
|
||||
T: InstanceDma,
|
||||
DmaMode: Mode,
|
||||
{
|
||||
type RX = ChannelRx<'d, T::Dma>;
|
||||
type RX = ChannelRx<'d, DmaMode, T::Dma>;
|
||||
|
||||
fn rx(&mut self) -> &mut Self::RX {
|
||||
&mut self.channel.rx
|
||||
@ -296,7 +296,7 @@ pub mod dma {
|
||||
{
|
||||
fn new<CH>(
|
||||
spi: PeripheralRef<'d, T>,
|
||||
channel: Channel<'d, CH, DmaMode>,
|
||||
channel: Channel<'d, DmaMode, CH>,
|
||||
rx_descriptors: &'static mut [DmaDescriptor],
|
||||
tx_descriptors: &'static mut [DmaDescriptor],
|
||||
) -> Self
|
||||
|
@ -25,7 +25,7 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
|
||||
struct Context {
|
||||
channel: Channel<'static, AnyGdmaChannel, Blocking>,
|
||||
channel: Channel<'static, Blocking, AnyGdmaChannel>,
|
||||
dma_peripheral: DmaPeripheralType,
|
||||
}
|
||||
|
||||
|
@ -90,27 +90,6 @@ mod tests {
|
||||
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]
|
||||
fn test_i8080_8bit_is_seen_by_pcnt(ctx: Context<'static>) {
|
||||
// FIXME: Update this test to exercise all the I8080 output signals once the
|
||||
|
@ -70,31 +70,4 @@ mod tests {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ struct Context {
|
||||
spi: Spi<'static, Blocking>,
|
||||
#[cfg(pcnt)]
|
||||
pcnt: esp_hal::peripherals::PCNT,
|
||||
dma_channel: Channel<'static, DmaChannel0, Blocking>,
|
||||
dma_channel: Channel<'static, Blocking, DmaChannel0>,
|
||||
gpios: [AnyPin; 3],
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user