[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)
- 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

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.
@ -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.

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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,
}
}
}

View File

@ -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;
}
}
}

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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

View File

@ -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.

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
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)]

View File

@ -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)] {

View File

@ -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

View File

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

View File

@ -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

View File

@ -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();
}
}

View File

@ -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],
}