Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add helper traits to simplify DMA channel trait bounds
  • Loading branch information
bugadani committed Nov 22, 2024
commit 5e3799488ec13580aa421b4893e31e684f45fce1
4 changes: 2 additions & 2 deletions esp-hal/src/aes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ pub mod dma {
Channel,
ChannelRx,
ChannelTx,
CompatibleWith,
DescriptorChain,
DmaChannelConvert,
DmaChannelFor,
DmaDescriptor,
DmaPeripheral,
Expand Down Expand Up @@ -295,7 +295,7 @@ pub mod dma {
tx_descriptors: &'static mut [DmaDescriptor],
) -> AesDma<'d>
where
CH: DmaChannelConvert<DmaChannelFor<AES>>,
CH: CompatibleWith<AES>,
{
let channel = Channel::new(channel.map(|ch| ch.degrade()));
channel.runtime_ensure_compatible(&self.aes);
Expand Down
12 changes: 12 additions & 0 deletions esp-hal/src/dma/gdma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ impl Peripheral for AnyGdmaRxChannel {
}
}

impl DmaChannelConvert<AnyGdmaRxChannel> for AnyGdmaRxChannel {
fn degrade(self) -> AnyGdmaRxChannel {
self
}
}

/// An arbitrary GDMA TX channel
pub struct AnyGdmaTxChannel(u8);

Expand All @@ -71,6 +77,12 @@ impl Peripheral for AnyGdmaTxChannel {
}
}

impl DmaChannelConvert<AnyGdmaTxChannel> for AnyGdmaTxChannel {
fn degrade(self) -> AnyGdmaTxChannel {
self
}
}

use embassy_sync::waitqueue::AtomicWaker;

static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
Expand Down
65 changes: 64 additions & 1 deletion esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1647,7 +1647,7 @@ pub trait DmaChannelExt: DmaChannel {
note = "Not all channels are useable with all peripherals"
)]
#[doc(hidden)]
pub trait DmaChannelConvert<DEG>: DmaChannel {
pub trait DmaChannelConvert<DEG> {
fn degrade(self) -> DEG;
}

Expand All @@ -1657,6 +1657,69 @@ impl<DEG: DmaChannel> DmaChannelConvert<DEG> for DEG {
}
}

/// Trait implemented for DMA channels that are compatible with a particular
/// peripheral.
#[cfg_attr(pdma, doc = "")]
#[cfg_attr(
pdma,
doc = "Note that using mismatching channels (e.g. trying to use `spi2channel` with SPI3) may compile, but will panic in runtime."
)]
#[cfg_attr(pdma, doc = "")]
/// ## Example
///
/// The following example demonstrates how this trait can be used to only accept
/// types compatible with a specific peripheral.
///
/// ```rust,no_run
#[doc = crate::before_snippet!()]
/// use esp_hal::spi::master::{Spi, Config, Instance as SpiInstance};
/// use esp_hal::dma::CompatibleWith;
/// use esp_hal::Blocking;
/// use esp_hal::dma::Dma;
///
/// fn takes_spi<S: SpiInstance>(spi: Spi<'_, Blocking, S>, channel: impl
/// CompatibleWith<S>) {}
///
/// let dma = Dma::new(peripherals.DMA);
#[cfg_attr(pdma, doc = "let dma_channel = dma.spi2channel;")]
#[cfg_attr(gdma, doc = "let dma_channel = dma.channel0;")]
#[doc = ""]
/// let spi = Spi::new_with_config(
/// peripherals.SPI2,
/// Config::default(),
/// );
///
/// takes_spi(spi, dma_channel);
/// # }
/// ```
pub trait CompatibleWith<P: DmaEligible>: DmaChannel + DmaChannelConvert<DmaChannelFor<P>> {}
impl<P, CH> CompatibleWith<P> for CH
where
P: DmaEligible,
CH: DmaChannel + DmaChannelConvert<DmaChannelFor<P>>,
{
}

/// Trait implemented for the RX half of split DMA channels that are compatible
/// with a particular peripheral.
pub trait RxCompatibleWith<P: DmaEligible>: DmaChannelConvert<RxChannelFor<P>> {}
impl<P, RX> RxCompatibleWith<P> for RX
where
P: DmaEligible,
RX: DmaChannelConvert<RxChannelFor<P>>,
{
}

/// Trait implemented for the TX half of split DMA channels that are compatible
/// with a particular peripheral.
pub trait TxCompatibleWith<PER: DmaEligible>: DmaChannelConvert<TxChannelFor<PER>> {}
impl<P, TX> TxCompatibleWith<P> for TX
where
P: DmaEligible,
TX: DmaChannelConvert<TxChannelFor<P>>,
{
}

/// The functions here are not meant to be used outside the HAL
#[doc(hidden)]
pub trait Rx: crate::private::Sealed {
Expand Down
6 changes: 3 additions & 3 deletions esp-hal/src/i2s/master.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ use crate::{
Channel,
ChannelRx,
ChannelTx,
CompatibleWith,
DescriptorChain,
DmaChannelConvert,
DmaChannelFor,
DmaDescriptor,
DmaEligible,
Expand Down Expand Up @@ -377,7 +377,7 @@ impl<'d> I2s<'d, Blocking> {
tx_descriptors: &'static mut [DmaDescriptor],
) -> Self
where
CH: DmaChannelConvert<DmaChannelFor<AnyI2s>>,
CH: CompatibleWith<AnyI2s>,
{
Self::new_typed(
i2s.map_into(),
Expand Down Expand Up @@ -408,7 +408,7 @@ where
tx_descriptors: &'static mut [DmaDescriptor],
) -> Self
where
CH: DmaChannelConvert<DmaChannelFor<T>>,
CH: CompatibleWith<T>,
{
crate::into_ref!(i2s);
Self::new_internal(
Expand Down
7 changes: 3 additions & 4 deletions esp-hal/src/i2s/parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ use crate::{
asynch::DmaTxFuture,
Channel,
ChannelTx,
DmaChannelConvert,
DmaChannelFor,
CompatibleWith,
DmaEligible,
DmaError,
DmaPeripheral,
Expand Down Expand Up @@ -193,7 +192,7 @@ impl<'d> I2sParallel<'d, Blocking> {
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
) -> Self
where
CH: DmaChannelConvert<DmaChannelFor<AnyI2s>>,
CH: CompatibleWith<AnyI2s>,
{
Self::new_typed(i2s.map_into(), channel, frequency, pins, clock_pin)
}
Expand All @@ -212,7 +211,7 @@ where
clock_pin: impl Peripheral<P = impl PeripheralOutput> + 'd,
) -> Self
where
CH: DmaChannelConvert<DmaChannelFor<I>>,
CH: CompatibleWith<I>,
{
crate::into_ref!(i2s);
crate::into_mapped_ref!(clock_pin);
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/src/lcd_cam/cam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use fugit::HertzU32;

use crate::{
clock::Clocks,
dma::{ChannelRx, DmaChannelConvert, DmaError, DmaPeripheral, DmaRxBuffer, Rx, RxChannelFor},
dma::{ChannelRx, DmaError, DmaPeripheral, DmaRxBuffer, Rx, RxChannelFor, RxCompatibleWith},
gpio::{
interconnect::{PeripheralInput, PeripheralOutput},
InputSignal,
Expand Down Expand Up @@ -136,7 +136,7 @@ impl<'d> Camera<'d> {
frequency: HertzU32,
) -> Self
where
CH: DmaChannelConvert<RxChannelFor<LCD_CAM>>,
CH: RxCompatibleWith<LCD_CAM>,
P: RxPins,
{
let rx_channel = ChannelRx::new(channel.map(|ch| ch.degrade()));
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/src/lcd_cam/lcd/dpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ use fugit::HertzU32;

use crate::{
clock::Clocks,
dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor},
dma::{ChannelTx, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor, TxCompatibleWith},
gpio::{interconnect::PeripheralOutput, Level, OutputSignal},
lcd_cam::{
calculate_clkm,
Expand Down Expand Up @@ -139,7 +139,7 @@ where
config: Config,
) -> Self
where
CH: DmaChannelConvert<TxChannelFor<LCD_CAM>>,
CH: TxCompatibleWith<LCD_CAM>,
{
let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade()));
let lcd_cam = lcd.lcd_cam;
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/src/lcd_cam/lcd/i8080.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use fugit::HertzU32;

use crate::{
clock::Clocks,
dma::{ChannelTx, DmaChannelConvert, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor},
dma::{ChannelTx, DmaError, DmaPeripheral, DmaTxBuffer, Tx, TxChannelFor, TxCompatibleWith},
gpio::{
interconnect::{OutputConnection, PeripheralOutput},
OutputSignal,
Expand Down Expand Up @@ -102,7 +102,7 @@ where
config: Config,
) -> Self
where
CH: DmaChannelConvert<TxChannelFor<LCD_CAM>>,
CH: TxCompatibleWith<LCD_CAM>,
P: TxPins,
{
let tx_channel = ChannelTx::new(channel.map(|ch| ch.degrade()));
Expand Down
11 changes: 6 additions & 5 deletions esp-hal/src/parl_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ use crate::{
Channel,
ChannelRx,
ChannelTx,
CompatibleWith,
DescriptorChain,
DmaChannelConvert,
DmaChannelFor,
DmaDescriptor,
DmaError,
DmaPeripheral,
Expand All @@ -45,8 +44,10 @@ use crate::{
ReadBuffer,
Rx,
RxChannelFor,
RxCompatibleWith,
Tx,
TxChannelFor,
TxCompatibleWith,
WriteBuffer,
},
gpio::{
Expand Down Expand Up @@ -1013,7 +1014,7 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
frequency: HertzU32,
) -> Result<Self, Error>
where
CH: DmaChannelConvert<DmaChannelFor<PARL_IO>>,
CH: CompatibleWith<PARL_IO>,
{
let tx_guard = GenericPeripheralGuard::new();
let rx_guard = GenericPeripheralGuard::new();
Expand Down Expand Up @@ -1135,7 +1136,7 @@ impl<'d> ParlIoTxOnly<'d, Blocking> {
frequency: HertzU32,
) -> Result<Self, Error>
where
CH: DmaChannelConvert<TxChannelFor<PARL_IO>>,
CH: TxCompatibleWith<PARL_IO>,
{
let guard = GenericPeripheralGuard::new();
let tx_channel = ChannelTx::new(dma_channel.map(|ch| ch.degrade()));
Expand Down Expand Up @@ -1241,7 +1242,7 @@ impl<'d> ParlIoRxOnly<'d, Blocking> {
frequency: HertzU32,
) -> Result<Self, Error>
where
CH: DmaChannelConvert<RxChannelFor<PARL_IO>>,
CH: RxCompatibleWith<PARL_IO>,
{
let guard = GenericPeripheralGuard::new();
let rx_channel = ChannelRx::new(dma_channel.map(|ch| ch.degrade()));
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/src/spi/master.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ use procmacros::ram;
use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode};
use crate::{
clock::Clocks,
dma::{DmaChannelConvert, DmaChannelFor, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
dma::{CompatibleWith, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal},
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
Expand Down Expand Up @@ -540,7 +540,7 @@ where
/// operations.
pub fn with_dma<CH>(self, channel: impl Peripheral<P = CH> + 'd) -> SpiDma<'d, Blocking, T>
where
CH: DmaChannelConvert<DmaChannelFor<T>>,
CH: CompatibleWith<T>,
{
SpiDma::new(self.spi, channel.map(|ch| ch.degrade()).into_ref())
}
Expand Down
5 changes: 3 additions & 2 deletions esp-hal/src/spi/slave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ use core::marker::PhantomData;

use super::{Error, SpiMode};
use crate::{
dma::{DmaChannelConvert, DmaEligible},
dma::DmaEligible,
gpio::{
interconnect::{PeripheralInput, PeripheralOutput},
InputSignal,
Expand Down Expand Up @@ -176,6 +176,7 @@ pub mod dma {
Channel,
ChannelRx,
ChannelTx,
CompatibleWith,
DescriptorChain,
DmaChannelFor,
DmaDescriptor,
Expand Down Expand Up @@ -206,7 +207,7 @@ pub mod dma {
tx_descriptors: &'static mut [DmaDescriptor],
) -> SpiDma<'d, Blocking, T>
where
CH: DmaChannelConvert<DmaChannelFor<T>>,
CH: CompatibleWith<T>,
{
self.spi.info().set_data_mode(self.data_mode, true);
SpiDma::new(
Expand Down
6 changes: 2 additions & 4 deletions hil-test/tests/lcd_cam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#![no_main]

use esp_hal::{
dma::{Dma, DmaRxBuf, DmaTxBuf},
dma::{Dma, DmaChannel, DmaRxBuf, DmaTxBuf},
dma_buffers,
gpio::Level,
lcd_cam::{
Expand Down Expand Up @@ -58,9 +58,7 @@ mod tests {
let dma = Dma::new(peripherals.DMA);
let lcd_cam = LcdCam::new(peripherals.LCD_CAM);

// TODO: use split channels once supported
let tx_channel = dma.channel2;
let rx_channel = dma.channel3;
let (rx_channel, tx_channel) = dma.channel2.split();

let (vsync_in, vsync_out) = peripherals.GPIO6.split();
let (hsync_in, hsync_out) = peripherals.GPIO7.split();
Expand Down