diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md
index b43cbf688..cd1e634f1 100644
--- a/esp-hal/CHANGELOG.md
+++ b/esp-hal/CHANGELOG.md
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Rng` and `Trng` now implement `Peripheral
` (#2992)
- SPI, UART, I2C: `with_` functions of peripheral drivers now disconnect the previously assigned pins from the peripheral. (#3012)
- SPI, UART, I2C: Dropping a driver now disconnects pins from their peripherals. (#3012)
+- Migrate PARL_IO driver to DMA move API (#3033)
- `Async` drivers are no longer `Send` (#2980)
- GPIO drivers now take configuration structs (#2990, #3029)
- `flip-link` feature is now a config option (`ESP_HAL_CONFIG_FLIP_LINK`) (#3001)
diff --git a/esp-hal/MIGRATING-0.23.md b/esp-hal/MIGRATING-0.23.md
index b1a9ea1ae..c0e94c58f 100644
--- a/esp-hal/MIGRATING-0.23.md
+++ b/esp-hal/MIGRATING-0.23.md
@@ -174,6 +174,35 @@ config/config.toml
+ ESP_HAL_CONFIG_PSRAM_MODE = "octal"
```
+## PARL_IO changes
+Parallel IO now uses the newer DMA Move API.
+
+Changes on the TX side
+```diff
+ let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);
++ let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
+
+- let transfer = parl_io_tx.write_dma(&tx_buffer).unwrap();
+- transfer.wait().unwrap();
++ let transfer = parl_io_tx.write(dma_tx_buf.len(), dma_tx_buf).unwrap();
++ (result, parl_io_tx, dma_tx_buf) = transfer.wait();
++ result.unwrap();
+```
+
+Changes on the RX side
+```diff
+ let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0);
++ let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
+- let transfer = parl_io_rx.read_dma(&mut rx_buffer).unwrap();
+- transfer.wait().unwrap();
++ let transfer = parl_io_rx.read(Some(dma_rx_buf.len()), dma_rx_buf).unwrap();
++ (_, parl_io_rx, dma_rx_buf) = transfer.wait();
+```
+
+On the RX side, the `EofMode` is now decided at transfer time, rather than config time.
+- `EofMode::ByteLen` -> `Some()`
+- `EofMode::EnableSignal` -> `None`
+
## GPIO changes
GPIO drivers now take configuration structs.
diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs
index 2ce44afd2..bc43033be 100644
--- a/esp-hal/src/parl_io.rs
+++ b/esp-hal/src/parl_io.rs
@@ -17,11 +17,13 @@
#![doc = crate::before_snippet!()]
//! # use esp_hal::delay::Delay;
//! # use esp_hal::dma_buffers;
+//! # use esp_hal::dma::DmaRxBuf;
//! # use esp_hal::gpio::NoPin;
//! # use esp_hal::parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits};
//!
//! // Initialize DMA buffer and descriptors for data reception
//! let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0);
+//! let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer)?;
//! let dma_channel = peripherals.DMA_CH0;
//!
//! // Configure the 4-bit input pins and clock pin
@@ -38,7 +40,6 @@
//! let parl_io = ParlIoRxOnly::new(
//! peripherals.PARL_IO,
//! dma_channel,
-//! rx_descriptors,
//! 1.MHz(),
//! )?;
//!
@@ -52,14 +53,13 @@
//! )?;
//!
//! // Initialize the buffer and delay
-//! let mut buffer = rx_buffer;
-//! buffer.fill(0u8);
+//! dma_rx_buf.as_mut_slice().fill(0u8);
//! let delay = Delay::new();
//!
//! loop {
//! // Read data via DMA and print received values
-//! let transfer = parl_io_rx.read_dma(&mut buffer)?;
-//! transfer.wait()?;
+//! let transfer = parl_io_rx.read(Some(dma_rx_buf.len()), dma_rx_buf)?;
+//! (_, parl_io_rx, dma_rx_buf) = transfer.wait();
//!
//! delay.delay_millis(500);
//! }
@@ -70,11 +70,11 @@
//! ```rust, no_run
#![doc = crate::before_snippet!()]
//! # use esp_hal::delay::Delay;
-//! # use esp_hal::dma_buffers;
+//! # use esp_hal::dma_tx_buffer;
//! # use esp_hal::parl_io::{BitPackOrder, ParlIoTxOnly, TxFourBits, SampleEdge, ClkOutPin, TxPinConfigWithValidPin};
//!
//! // Initialize DMA buffer and descriptors for data reception
-//! let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);
+//! let mut dma_tx_buf = dma_tx_buffer!(32000).unwrap();
//! let dma_channel = peripherals.DMA_CH0;
//!
//! // Configure the 4-bit input pins and clock pin
@@ -92,7 +92,6 @@
//! let parl_io = ParlIoTxOnly::new(
//! peripherals.PARL_IO,
//! dma_channel,
-//! tx_descriptors,
//! 1.MHz(),
//! )?;
//!
@@ -107,20 +106,24 @@
//! BitPackOrder::Msb,
//! )?;
//!
-//! let buffer = tx_buffer;
-//! for i in 0..buffer.len() {
-//! buffer[i] = (i % 255) as u8;
+//! for i in 0..dma_tx_buf.len() {
+//! dma_tx_buf.as_mut_slice()[i] = (i % 255) as u8;
//! }
//!
//! let delay = Delay::new();
//! loop {
-//! let transfer = parl_io_tx.write_dma(&buffer)?;
-//! transfer.wait()?;
+//! let transfer = parl_io_tx.write(dma_tx_buf.len(), dma_tx_buf)?;
+//! (_, parl_io_tx, dma_tx_buf) = transfer.wait();
//! delay.delay_millis(500);
//! }
//! # }
//! ```
+use core::{
+ mem::ManuallyDrop,
+ ops::{Deref, DerefMut},
+};
+
use enumset::{EnumSet, EnumSetType};
use fugit::HertzU32;
use peripheral::PeripheralRef;
@@ -128,31 +131,27 @@ use private::*;
use crate::{
dma::{
- dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
Channel,
ChannelRx,
ChannelTx,
- DescriptorChain,
DmaChannelFor,
- DmaDescriptor,
DmaError,
DmaPeripheral,
- DmaTransferRx,
- DmaTransferTx,
+ DmaRxBuffer,
+ DmaTxBuffer,
PeripheralRxChannel,
PeripheralTxChannel,
- ReadBuffer,
Rx,
RxChannelFor,
Tx,
TxChannelFor,
- WriteBuffer,
},
gpio::{
interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput},
NoPin,
},
interrupt::InterruptHandler,
+ parl_io::asynch::interrupt_handler,
peripheral::{self, Peripheral},
peripherals::{Interrupt, PARL_IO, PCR},
system::{self, GenericPeripheralGuard},
@@ -351,16 +350,6 @@ impl EnableMode {
}
}
-/// Generation of GDMA SUC EOF
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum EofMode {
- /// Generate GDMA SUC EOF by data byte length
- ByteLen,
- /// Generate GDMA SUC EOF by the external enable signal
- EnableSignal,
-}
-
/// Used to configure no pin as clock output
impl TxClkPin for NoPin {
fn configure(&mut self) {
@@ -605,6 +594,7 @@ impl FullDuplex for TxOneBit<'_> {}
impl FullDuplex for TxTwoBits<'_> {}
impl FullDuplex for TxFourBits<'_> {}
impl FullDuplex for TxEightBits<'_> {}
+impl FullDuplex for TxPinConfigWithValidPin<'_, TxFourBits<'_>> {}
impl NotContainsValidSignalPin for TxOneBit<'_> {}
impl NotContainsValidSignalPin for TxTwoBits<'_> {}
@@ -627,7 +617,6 @@ where
rx_pins: P,
valid_pin: PeripheralRef<'d, InputConnection>,
enable_mode: EnableMode,
- eof_mode: EofMode,
}
impl<'d, P> RxPinConfigWithValidPin<'d, P>
@@ -639,14 +628,12 @@ where
rx_pins: P,
valid_pin: impl Peripheral + 'd,
enable_mode: EnableMode,
- eof_mode: EofMode,
) -> Self {
crate::into_mapped_ref!(valid_pin);
Self {
rx_pins,
valid_pin,
enable_mode,
- eof_mode,
}
}
}
@@ -674,7 +661,6 @@ where
if let Some(sel) = self.enable_mode.smp_model_sel() {
Instance::set_rx_sample_mode(sel);
}
- Instance::set_eof_gen_sel(self.eof_mode);
Ok(())
}
@@ -687,7 +673,6 @@ where
{
rx_pins: P,
enable_mode: EnableMode,
- eof_mode: EofMode,
}
impl
RxPinConfigIncludingValidPin
@@ -695,11 +680,10 @@ where
P: ContainsValidSignalPin + RxPins + ConfigurePins,
{
/// Create a new [RxPinConfigIncludingValidPin]
- pub fn new(rx_pins: P, enable_mode: EnableMode, eof_mode: EofMode) -> Self {
+ pub fn new(rx_pins: P, enable_mode: EnableMode) -> Self {
Self {
rx_pins,
enable_mode,
- eof_mode,
}
}
}
@@ -725,7 +709,6 @@ where
if let Some(sel) = self.enable_mode.smp_model_sel() {
Instance::set_rx_sample_mode(sel);
}
- Instance::set_eof_gen_sel(self.eof_mode);
Ok(())
}
@@ -823,6 +806,7 @@ impl FullDuplex for RxOneBit<'_> {}
impl FullDuplex for RxTwoBits<'_> {}
impl FullDuplex for RxFourBits<'_> {}
impl FullDuplex for RxEightBits<'_> {}
+impl FullDuplex for RxPinConfigWithValidPin<'_, RxFourBits<'_>> {}
impl NotContainsValidSignalPin for RxOneBit<'_> {}
impl NotContainsValidSignalPin for RxTwoBits<'_> {}
@@ -863,7 +847,6 @@ where
Ok(ParlIoTx {
tx_channel: self.tx_channel,
- tx_chain: DescriptorChain::new(self.descriptors),
_guard: self._guard,
})
}
@@ -895,7 +878,6 @@ where
Ok(ParlIoTx {
tx_channel: self.tx_channel,
- tx_chain: DescriptorChain::new(self.descriptors),
_guard: self._guard,
})
}
@@ -908,7 +890,6 @@ where
Dm: DriverMode,
{
tx_channel: ChannelTx<'d, Dm, PeripheralTxChannel>,
- tx_chain: DescriptorChain,
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>,
}
@@ -947,7 +928,6 @@ where
Ok(ParlIoRx {
rx_channel: self.rx_channel,
- rx_chain: DescriptorChain::new(self.descriptors),
_guard: guard,
})
}
@@ -977,7 +957,6 @@ where
Ok(ParlIoRx {
rx_channel: self.rx_channel,
- rx_chain: DescriptorChain::new(self.descriptors),
_guard: self._guard,
})
}
@@ -990,7 +969,6 @@ where
Dm: DriverMode,
{
rx_channel: ChannelRx<'d, Dm, PeripheralRxChannel>,
- rx_chain: DescriptorChain,
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::ParlIo as u8 }>,
}
@@ -1105,8 +1083,6 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
pub fn new(
_parl_io: impl Peripheral + 'd,
dma_channel: impl Peripheral
+ 'd,
- tx_descriptors: &'static mut [DmaDescriptor],
- rx_descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32,
) -> Result
where
@@ -1120,12 +1096,10 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
Ok(Self {
tx: TxCreatorFullDuplex {
tx_channel: dma_channel.tx,
- descriptors: tx_descriptors,
_guard: tx_guard,
},
rx: RxCreatorFullDuplex {
rx_channel: dma_channel.rx,
- descriptors: rx_descriptors,
_guard: rx_guard,
},
})
@@ -1144,15 +1118,38 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
}
+
+ #[cfg(esp32c6)]
+ {
+ unsafe {
+ crate::interrupt::bind_interrupt(Interrupt::PARL_IO, interrupt_handler.handler());
+ }
+ unwrap!(crate::interrupt::enable(
+ Interrupt::PARL_IO,
+ interrupt_handler.priority()
+ ));
+ }
+ #[cfg(esp32h2)]
+ {
+ unsafe {
+ crate::interrupt::bind_interrupt(
+ Interrupt::PARL_IO_TX,
+ interrupt_handler.handler(),
+ );
+ }
+ unwrap!(crate::interrupt::enable(
+ Interrupt::PARL_IO_TX,
+ interrupt_handler.priority()
+ ));
+ }
+
ParlIoFullDuplex {
tx: TxCreatorFullDuplex {
tx_channel: self.tx.tx_channel.into_async(),
- descriptors: self.tx.descriptors,
_guard: self.tx._guard,
},
rx: RxCreatorFullDuplex {
rx_channel: self.rx.rx_channel.into_async(),
- descriptors: self.rx.descriptors,
_guard: self.rx._guard,
},
}
@@ -1203,12 +1200,10 @@ impl<'d> ParlIoFullDuplex<'d, Async> {
ParlIoFullDuplex {
tx: TxCreatorFullDuplex {
tx_channel: self.tx.tx_channel.into_blocking(),
- descriptors: self.tx.descriptors,
_guard: self.tx._guard,
},
rx: RxCreatorFullDuplex {
rx_channel: self.rx.rx_channel.into_blocking(),
- descriptors: self.rx.descriptors,
_guard: self.rx._guard,
},
}
@@ -1230,7 +1225,6 @@ impl<'d> ParlIoTxOnly<'d, Blocking> {
pub fn new(
_parl_io: impl Peripheral + 'd,
dma_channel: impl Peripheral
+ 'd,
- descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32,
) -> Result
where
@@ -1243,7 +1237,6 @@ impl<'d> ParlIoTxOnly<'d, Blocking> {
Ok(Self {
tx: TxCreator {
tx_channel,
- descriptors,
_guard: guard,
},
})
@@ -1262,10 +1255,33 @@ impl<'d> ParlIoTxOnly<'d, Blocking> {
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
}
+ #[cfg(esp32c6)]
+ {
+ unsafe {
+ crate::interrupt::bind_interrupt(Interrupt::PARL_IO, interrupt_handler.handler());
+ }
+ unwrap!(crate::interrupt::enable(
+ Interrupt::PARL_IO,
+ interrupt_handler.priority()
+ ));
+ }
+ #[cfg(esp32h2)]
+ {
+ unsafe {
+ crate::interrupt::bind_interrupt(
+ Interrupt::PARL_IO_TX,
+ interrupt_handler.handler(),
+ );
+ }
+ unwrap!(crate::interrupt::enable(
+ Interrupt::PARL_IO_TX,
+ interrupt_handler.priority()
+ ));
+ }
+
ParlIoTxOnly {
tx: TxCreator {
tx_channel: self.tx.tx_channel.into_async(),
- descriptors: self.tx.descriptors,
_guard: self.tx._guard,
},
}
@@ -1307,7 +1323,6 @@ impl<'d> ParlIoTxOnly<'d, Async> {
ParlIoTxOnly {
tx: TxCreator {
tx_channel: self.tx.tx_channel.into_blocking(),
- descriptors: self.tx.descriptors,
_guard: self.tx._guard,
},
}
@@ -1338,7 +1353,6 @@ impl<'d> ParlIoRxOnly<'d, Blocking> {
pub fn new(
_parl_io: impl Peripheral + 'd,
dma_channel: impl Peripheral
+ 'd,
- descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32,
) -> Result
where
@@ -1351,7 +1365,6 @@ impl<'d> ParlIoRxOnly<'d, Blocking> {
Ok(Self {
rx: RxCreator {
rx_channel,
- descriptors,
_guard: guard,
},
})
@@ -1370,11 +1383,33 @@ impl<'d> ParlIoRxOnly<'d, Blocking> {
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
}
+ #[cfg(esp32c6)]
+ {
+ unsafe {
+ crate::interrupt::bind_interrupt(Interrupt::PARL_IO, interrupt_handler.handler());
+ }
+ unwrap!(crate::interrupt::enable(
+ Interrupt::PARL_IO,
+ interrupt_handler.priority()
+ ));
+ }
+ #[cfg(esp32h2)]
+ {
+ unsafe {
+ crate::interrupt::bind_interrupt(
+ Interrupt::PARL_IO_TX,
+ interrupt_handler.handler(),
+ );
+ }
+ unwrap!(crate::interrupt::enable(
+ Interrupt::PARL_IO_TX,
+ interrupt_handler.priority()
+ ));
+ }
ParlIoRxOnly {
rx: RxCreator {
rx_channel: self.rx.rx_channel.into_async(),
- descriptors: self.rx.descriptors,
_guard: self.rx._guard,
},
}
@@ -1416,7 +1451,6 @@ impl<'d> ParlIoRxOnly<'d, Async> {
ParlIoRxOnly {
rx: RxCreator {
rx_channel: self.rx.rx_channel.into_blocking(),
- descriptors: self.rx.descriptors,
_guard: self.rx._guard,
},
}
@@ -1460,48 +1494,41 @@ fn internal_init(frequency: HertzU32) -> Result<(), Error> {
Ok(())
}
-impl ParlIoTx<'_, Dm>
+impl<'d, Dm> ParlIoTx<'d, Dm>
where
Dm: DriverMode,
{
/// Perform a DMA write.
///
- /// This will return a [DmaTransferTx]
+ /// This will return a [ParlIoTxTransfer]
///
/// The maximum amount of data to be sent is 32736 bytes.
- pub fn write_dma<'t, TXBUF>(
- &'t mut self,
- words: &'t TXBUF,
- ) -> Result, Error>
+ pub fn write(
+ mut self,
+ number_of_bytes: usize,
+ mut buffer: BUF,
+ ) -> Result, (Error, Self, BUF)>
where
- TXBUF: ReadBuffer,
+ BUF: DmaTxBuffer,
{
- let (ptr, len) = unsafe { words.read_buffer() };
-
- if len > MAX_DMA_SIZE {
- return Err(Error::MaxDmaTransferSizeExceeded);
+ if number_of_bytes > MAX_DMA_SIZE {
+ return Err((Error::MaxDmaTransferSizeExceeded, self, buffer));
}
- self.start_write_bytes_dma(ptr, len)?;
-
- Ok(DmaTransferTx::new(self))
- }
-
- fn start_write_bytes_dma(&mut self, ptr: *const u8, len: usize) -> Result<(), Error> {
PCR::regs()
.parl_clk_tx_conf()
.modify(|_, w| w.parl_tx_rst_en().set_bit());
Instance::clear_tx_interrupts();
- Instance::set_tx_bytes(len as u16);
+ Instance::set_tx_bytes(number_of_bytes as u16);
- self.tx_channel.is_done();
-
- unsafe {
- self.tx_chain.fill_for_tx(false, ptr, len)?;
+ let result = unsafe {
self.tx_channel
- .prepare_transfer_without_start(DmaPeripheral::ParlIo, &self.tx_chain)
- .and_then(|_| self.tx_channel.start_transfer())?;
+ .prepare_transfer(DmaPeripheral::ParlIo, &mut buffer)
+ .and_then(|_| self.tx_channel.start_transfer())
+ };
+ if let Err(err) = result {
+ return Err((Error::DmaError(err), self, buffer));
}
while !Instance::is_tx_ready() {}
@@ -1512,37 +1539,86 @@ where
.parl_clk_tx_conf()
.modify(|_, w| w.parl_tx_rst_en().clear_bit());
- Ok(())
+ Ok(ParlIoTxTransfer {
+ parl_io: ManuallyDrop::new(self),
+ buf_view: ManuallyDrop::new(buffer.into_view()),
+ })
}
}
-impl DmaSupport for ParlIoTx<'_, Dm>
-where
- Dm: DriverMode,
-{
- fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
- while !Instance::is_tx_eof() {}
+/// Represents an ongoing (or potentially finished) transfer using the PARL_IO
+/// TX.
+pub struct ParlIoTxTransfer<'d, BUF: DmaTxBuffer, Dm: DriverMode> {
+ parl_io: ManuallyDrop>,
+ buf_view: ManuallyDrop,
+}
+
+impl<'d, BUF: DmaTxBuffer, Dm: DriverMode> ParlIoTxTransfer<'d, BUF, Dm> {
+ /// Returns true when [Self::wait] will not block.
+ pub fn is_done(&self) -> bool {
+ Instance::is_tx_eof()
+ }
+
+ /// Waits for the transfer to finish and returns the peripheral and buffer.
+ pub fn wait(mut self) -> (Result<(), DmaError>, ParlIoTx<'d, Dm>, BUF) {
+ while !self.is_done() {}
Instance::set_tx_start(false);
+ Instance::clear_is_tx_done();
+
+ // Stop the DMA as it doesn't know that the parl io has stopped.
+ self.parl_io.tx_channel.stop_transfer();
+
+ let (parl_io, view) = self.release();
+
+ let result = if parl_io.tx_channel.has_error() {
+ Err(DmaError::DescriptorError)
+ } else {
+ Ok(())
+ };
+
+ (result, parl_io, BUF::from_view(view))
}
- fn peripheral_dma_stop(&mut self) {
- unreachable!("unsupported")
+ fn release(mut self) -> (ParlIoTx<'d, Dm>, BUF::View) {
+ let (parl_io, view) = unsafe {
+ (
+ ManuallyDrop::take(&mut self.parl_io),
+ ManuallyDrop::take(&mut self.buf_view),
+ )
+ };
+ core::mem::forget(self);
+ (parl_io, view)
}
}
-impl<'d, Dm> DmaSupportTx for ParlIoTx<'d, Dm>
-where
- Dm: DriverMode,
-{
- type TX = ChannelTx<'d, Dm, PeripheralTxChannel>;
+impl Deref for ParlIoTxTransfer<'_, BUF, Dm> {
+ type Target = BUF::View;
- fn tx(&mut self) -> &mut Self::TX {
- &mut self.tx_channel
+ fn deref(&self) -> &Self::Target {
+ &self.buf_view
}
+}
- fn chain(&mut self) -> &mut DescriptorChain {
- &mut self.tx_chain
+impl DerefMut for ParlIoTxTransfer<'_, BUF, Dm> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.buf_view
+ }
+}
+
+impl Drop for ParlIoTxTransfer<'_, BUF, Dm> {
+ fn drop(&mut self) {
+ // There's no documented way to cancel the PARL IO transfer, so we'll just stop
+ // the DMA to stop the memory access.
+ self.parl_io.tx_channel.stop_transfer();
+
+ // SAFETY: This is Drop, we know that self.parl_io and self.buf_view
+ // won't be touched again.
+ let view = unsafe {
+ ManuallyDrop::drop(&mut self.parl_io);
+ ManuallyDrop::take(&mut self.buf_view)
+ };
+ let _ = BUF::from_view(view);
}
}
@@ -1552,36 +1628,23 @@ where
{
/// Perform a DMA read.
///
- /// This will return a [DmaTransferRx]
+ /// This will return a [ParlIoRxTransfer]
///
- /// The maximum amount of data is 32736 bytes when using [EofMode::ByteLen].
+ /// When the number of bytes is specified, the maximum amount of data is
+ /// 32736 bytes and the transfer ends when the number of specified bytes
+ /// is received.
///
- /// It's only limited by the size of the DMA buffer when using
- /// [EofMode::EnableSignal].
- pub fn read_dma<'t, RXBUF>(
- &'t mut self,
- words: &'t mut RXBUF,
- ) -> Result, Error>
+ /// When the number of bytes is unspecified, there's no limit the amount of
+ /// data transferred and the transfer ends when the enable signal
+ /// signals the end or the DMA buffer runs out of space.
+ pub fn read(
+ mut self,
+ number_of_bytes: Option,
+ mut buffer: BUF,
+ ) -> Result, (Error, Self, BUF)>
where
- RXBUF: WriteBuffer,
+ BUF: DmaRxBuffer,
{
- let (ptr, len) = unsafe { words.write_buffer() };
-
- if !Instance::is_suc_eof_generated_externally() && len > MAX_DMA_SIZE {
- return Err(Error::MaxDmaTransferSizeExceeded);
- }
-
- Self::start_receive_bytes_dma(&mut self.rx_channel, &mut self.rx_chain, ptr, len)?;
-
- Ok(DmaTransferRx::new(self))
- }
-
- fn start_receive_bytes_dma(
- rx_channel: &mut ChannelRx<'d, Dm, PeripheralRxChannel>,
- rx_chain: &mut DescriptorChain,
- ptr: *mut u8,
- len: usize,
- ) -> Result<(), Error> {
PCR::regs()
.parl_clk_rx_conf()
.modify(|_, w| w.parl_rx_rst_en().set_bit());
@@ -1590,56 +1653,116 @@ where
.modify(|_, w| w.parl_rx_rst_en().clear_bit());
Instance::clear_rx_interrupts();
- Instance::set_rx_bytes(len as u16);
+ if let Some(number_of_bytes) = number_of_bytes {
+ if number_of_bytes > MAX_DMA_SIZE {
+ return Err((Error::MaxDmaTransferSizeExceeded, self, buffer));
+ }
+ Instance::set_rx_bytes(number_of_bytes as u16);
+ Instance::set_eof_gen_sel(EofMode::ByteLen);
+ } else {
+ Instance::set_eof_gen_sel(EofMode::EnableSignal);
+ }
- unsafe {
- rx_chain.fill_for_rx(false, ptr, len)?;
- rx_channel
- .prepare_transfer_without_start(DmaPeripheral::ParlIo, rx_chain)
- .and_then(|_| rx_channel.start_transfer())?;
+ let result = unsafe {
+ self.rx_channel
+ .prepare_transfer(DmaPeripheral::ParlIo, &mut buffer)
+ .and_then(|_| self.rx_channel.start_transfer())
+ };
+ if let Err(err) = result {
+ return Err((Error::DmaError(err), self, buffer));
}
Instance::set_rx_reg_update();
Instance::set_rx_start(true);
- Ok(())
+
+ Ok(ParlIoRxTransfer {
+ parl_io: ManuallyDrop::new(self),
+ buf_view: ManuallyDrop::new(buffer.into_view()),
+ dma_result: None,
+ })
}
}
-impl DmaSupport for ParlIoRx<'_, Dm>
-where
- Dm: DriverMode,
-{
- fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
- loop {
- if self.rx_channel.is_done()
- || self.rx_channel.has_eof_error()
- || self.rx_channel.has_dscr_empty_error()
- {
- break;
- }
+/// Represents an ongoing (or potentially finished) transfer using the PARL_IO
+/// TX.
+pub struct ParlIoRxTransfer<'d, BUF: DmaRxBuffer, Dm: DriverMode> {
+ parl_io: ManuallyDrop>,
+ buf_view: ManuallyDrop,
+ // Needed to use DmaRxFuture, which clear the bits we check in is_done()
+ dma_result: Option>,
+}
+
+impl<'d, BUF: DmaRxBuffer, Dm: DriverMode> ParlIoRxTransfer<'d, BUF, Dm> {
+ /// Returns true when [Self::wait] will not block.
+ pub fn is_done(&self) -> bool {
+ if self.dma_result.is_some() {
+ return true;
}
+ let ch = &self.parl_io.rx_channel;
+ ch.is_done() || ch.has_eof_error() || ch.has_dscr_empty_error()
+ }
+
+ /// Waits for the transfer to finish and returns the peripheral and buffer.
+ pub fn wait(mut self) -> (Result<(), DmaError>, ParlIoRx<'d, Dm>, BUF) {
+ while !self.is_done() {}
Instance::set_rx_start(false);
+
+ // Stop the DMA as it doesn't know that the parl io has stopped.
+ self.parl_io.rx_channel.stop_transfer();
+
+ let dma_result = self.dma_result.take();
+ let (parl_io, view) = self.release();
+
+ let result = if parl_io.rx_channel.has_error() {
+ Err(DmaError::DescriptorError)
+ } else {
+ dma_result.unwrap_or(Ok(()))
+ };
+
+ (result, parl_io, BUF::from_view(view))
}
- fn peripheral_dma_stop(&mut self) {
- unreachable!("unsupported")
+ fn release(mut self) -> (ParlIoRx<'d, Dm>, BUF::View) {
+ let (parl_io, view) = unsafe {
+ (
+ ManuallyDrop::take(&mut self.parl_io),
+ ManuallyDrop::take(&mut self.buf_view),
+ )
+ };
+ core::mem::forget(self);
+ (parl_io, view)
}
}
-impl<'d, Dm> DmaSupportRx for ParlIoRx<'d, Dm>
-where
- Dm: DriverMode,
-{
- type RX = ChannelRx<'d, Dm, PeripheralRxChannel>;
+impl Deref for ParlIoRxTransfer<'_, BUF, Dm> {
+ type Target = BUF::View;
- fn rx(&mut self) -> &mut Self::RX {
- &mut self.rx_channel
+ fn deref(&self) -> &Self::Target {
+ &self.buf_view
}
+}
- fn chain(&mut self) -> &mut DescriptorChain {
- &mut self.rx_chain
+impl DerefMut for ParlIoRxTransfer<'_, BUF, Dm> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.buf_view
+ }
+}
+
+impl Drop for ParlIoRxTransfer<'_, BUF, Dm> {
+ fn drop(&mut self) {
+ // There's no documented way to cancel the PARL IO transfer, so we'll just stop
+ // the DMA to stop the memory access.
+ self.parl_io.rx_channel.stop_transfer();
+
+ // SAFETY: This is Drop, we know that self.parl_io and self.buf_view
+ // won't be touched again.
+ let view = unsafe {
+ ManuallyDrop::drop(&mut self.parl_io);
+ ManuallyDrop::take(&mut self.buf_view)
+ };
+ let _ = BUF::from_view(view);
}
}
@@ -1649,7 +1772,6 @@ where
Dm: DriverMode,
{
tx_channel: ChannelTx<'d, Dm, PeripheralTxChannel>,
- descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
}
@@ -1659,7 +1781,6 @@ where
Dm: DriverMode,
{
rx_channel: ChannelRx<'d, Dm, PeripheralRxChannel>,
- descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
}
@@ -1669,7 +1790,6 @@ where
Dm: DriverMode,
{
tx_channel: ChannelTx<'d, Dm, PeripheralTxChannel>,
- descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
}
@@ -1679,7 +1799,6 @@ where
Dm: DriverMode,
{
rx_channel: ChannelRx<'d, Dm, PeripheralRxChannel>,
- descriptors: &'static mut [DmaDescriptor],
_guard: GenericPeripheralGuard<{ system::Peripheral::ParlIo as u8 }>,
}
@@ -1689,11 +1808,10 @@ pub mod asynch {
use procmacros::handler;
- use super::{private::Instance, Error, ParlIoRx, ParlIoTx, MAX_DMA_SIZE};
+ use super::{private::Instance, ParlIoRxTransfer, ParlIoTxTransfer};
use crate::{
asynch::AtomicWaker,
- dma::{asynch::DmaRxFuture, ReadBuffer, WriteBuffer},
- peripherals::{Interrupt, PARL_IO},
+ dma::{asynch::DmaRxFuture, DmaRxBuffer, DmaTxBuffer},
};
static TX_WAKER: AtomicWaker = AtomicWaker::new();
@@ -1703,26 +1821,6 @@ pub mod asynch {
impl TxDoneFuture {
pub fn new() -> Self {
- Instance::listen_tx_done();
- let mut parl_io = unsafe { PARL_IO::steal() };
-
- #[cfg(esp32c6)]
- {
- parl_io.bind_parl_io_interrupt(interrupt_handler.handler());
- unwrap!(crate::interrupt::enable(
- Interrupt::PARL_IO,
- interrupt_handler.priority()
- ));
- }
- #[cfg(esp32h2)]
- {
- parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler());
- unwrap!(crate::interrupt::enable(
- Interrupt::PARL_IO_TX,
- interrupt_handler.priority()
- ));
- }
-
Self {}
}
}
@@ -1734,74 +1832,52 @@ pub mod asynch {
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll {
- TX_WAKER.register(cx.waker());
- if Instance::is_listening_tx_done() {
- Poll::Pending
- } else {
+ if Instance::is_tx_done_set() {
Poll::Ready(())
+ } else {
+ TX_WAKER.register(cx.waker());
+ Instance::listen_tx_done();
+ Poll::Pending
}
}
}
+ impl Drop for TxDoneFuture {
+ fn drop(&mut self) {
+ Instance::unlisten_tx_done();
+ }
+ }
+
#[handler]
- fn interrupt_handler() {
+ pub(super) fn interrupt_handler() {
if Instance::is_tx_done_set() {
- Instance::clear_is_tx_done();
Instance::unlisten_tx_done();
TX_WAKER.wake()
}
}
- impl ParlIoTx<'_, crate::Async> {
- /// Perform a DMA write.
- ///
- /// The maximum amount of data to be sent is 32736 bytes.
- pub async fn write_dma_async(&mut self, words: &TXBUF) -> Result<(), Error>
- where
- TXBUF: ReadBuffer,
- {
- let (ptr, len) = unsafe { words.read_buffer() };
-
- if len > MAX_DMA_SIZE {
- return Err(Error::MaxDmaTransferSizeExceeded);
- }
-
+ impl ParlIoTxTransfer<'_, BUF, crate::Async> {
+ /// Waits for [Self::is_done] to return true.
+ pub async fn wait_for_done(&mut self) {
let future = TxDoneFuture::new();
- self.start_write_bytes_dma(ptr, len)?;
future.await;
-
- Ok(())
}
}
- impl ParlIoRx<'_, crate::Async> {
- /// Perform a DMA write.
- ///
- /// The maximum amount of data to be sent is 32736 bytes.
- pub async fn read_dma_async<'t, RXBUF>(
- &'t mut self,
- words: &'t mut RXBUF,
- ) -> Result<(), Error>
- where
- RXBUF: WriteBuffer,
- {
- let (ptr, len) = unsafe { words.write_buffer() };
-
- if !Instance::is_suc_eof_generated_externally() && len > MAX_DMA_SIZE {
- return Err(Error::MaxDmaTransferSizeExceeded);
+ impl ParlIoRxTransfer<'_, BUF, crate::Async> {
+ /// Waits for [Self::is_done] to return true.
+ pub async fn wait_for_done(&mut self) {
+ if self.dma_result.is_some() {
+ return;
}
-
- let future = DmaRxFuture::new(&mut self.rx_channel);
- Self::start_receive_bytes_dma(future.rx, &mut self.rx_chain, ptr, len)?;
- future.await?;
-
- Ok(())
+ let future = DmaRxFuture::new(&mut self.parl_io.rx_channel);
+ self.dma_result = Some(future.await);
}
}
}
mod private {
- use super::{BitPackOrder, EofMode, Error, SampleEdge};
+ use super::{BitPackOrder, Error, SampleEdge};
use crate::peripherals::PARL_IO;
pub trait FullDuplex {}
@@ -1849,6 +1925,14 @@ mod private {
InternalSoftwareEnable = 2,
}
+ /// Generation of GDMA SUC EOF
+ pub(super) enum EofMode {
+ /// Generate GDMA SUC EOF by data byte length
+ ByteLen,
+ /// Generate GDMA SUC EOF by the external enable signal
+ EnableSignal,
+ }
+
pub(super) struct Instance;
#[cfg(esp32c6)]
@@ -1976,9 +2060,10 @@ mod private {
pub fn set_eof_gen_sel(mode: EofMode) {
let reg_block = PARL_IO::regs();
- reg_block
- .rx_cfg0()
- .modify(|_, w| w.rx_eof_gen_sel().bit(mode == EofMode::EnableSignal));
+ reg_block.rx_cfg0().modify(|_, w| {
+ w.rx_eof_gen_sel()
+ .bit(matches!(mode, EofMode::EnableSignal))
+ });
}
pub fn set_rx_pulse_submode_sel(sel: u8) {
@@ -2036,12 +2121,6 @@ mod private {
});
}
- pub fn is_suc_eof_generated_externally() -> bool {
- let reg_block = PARL_IO::regs();
-
- reg_block.rx_cfg0().read().rx_eof_gen_sel().bit_is_set()
- }
-
pub fn listen_tx_done() {
let reg_block = PARL_IO::regs();
@@ -2054,12 +2133,6 @@ mod private {
reg_block.int_ena().modify(|_, w| w.tx_eof().clear_bit());
}
- pub fn is_listening_tx_done() -> bool {
- let reg_block = PARL_IO::regs();
-
- reg_block.int_ena().read().tx_eof().bit()
- }
-
pub fn is_tx_done_set() -> bool {
let reg_block = PARL_IO::regs();
@@ -2205,9 +2278,10 @@ mod private {
pub fn set_eof_gen_sel(mode: EofMode) {
let reg_block = PARL_IO::regs();
- reg_block
- .rx_genrl_cfg()
- .modify(|_, w| w.rx_eof_gen_sel().bit(mode == EofMode::EnableSignal));
+ reg_block.rx_genrl_cfg().modify(|_, w| {
+ w.rx_eof_gen_sel()
+ .bit(matches!(mode, EofMode::EnableSignal))
+ });
}
pub fn set_rx_pulse_submode_sel(sel: u8) {
@@ -2266,16 +2340,6 @@ mod private {
});
}
- pub fn is_suc_eof_generated_externally() -> bool {
- let reg_block = PARL_IO::regs();
-
- reg_block
- .rx_genrl_cfg()
- .read()
- .rx_eof_gen_sel()
- .bit_is_set()
- }
-
pub fn listen_tx_done() {
let reg_block = PARL_IO::regs();
@@ -2288,12 +2352,6 @@ mod private {
reg_block.int_ena().modify(|_, w| w.tx_eof().clear_bit());
}
- pub fn is_listening_tx_done() -> bool {
- let reg_block = PARL_IO::regs();
-
- reg_block.int_ena().read().tx_eof().bit()
- }
-
pub fn is_tx_done_set() -> bool {
let reg_block = PARL_IO::regs();
diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml
index 968b2ef8c..28e39980f 100644
--- a/hil-test/Cargo.toml
+++ b/hil-test/Cargo.toml
@@ -115,6 +115,10 @@ harness = false
name = "spi_slave"
harness = false
+[[test]]
+name = "parl_io"
+harness = false
+
[[test]]
name = "parl_io_tx"
harness = false
diff --git a/hil-test/tests/parl_io.rs b/hil-test/tests/parl_io.rs
new file mode 100644
index 000000000..2d677f1a4
--- /dev/null
+++ b/hil-test/tests/parl_io.rs
@@ -0,0 +1,121 @@
+//! PARL_IO test
+
+//% CHIPS: esp32c6 esp32h2
+//% FEATURES: unstable
+
+#![no_std]
+#![no_main]
+
+use esp_hal::{
+ dma::{DmaChannel0, DmaRxBuf, DmaTxBuf},
+ dma_buffers,
+ gpio::{AnyPin, Pin},
+ parl_io::{
+ BitPackOrder,
+ ClkOutPin,
+ EnableMode,
+ ParlIoFullDuplex,
+ RxClkInPin,
+ RxFourBits,
+ RxPinConfigWithValidPin,
+ SampleEdge,
+ TxFourBits,
+ TxPinConfigWithValidPin,
+ },
+ peripherals::PARL_IO,
+ time::RateExtU32,
+};
+use hil_test as _;
+
+struct Context {
+ parl_io: PARL_IO,
+ dma_channel: DmaChannel0,
+ clock_pin: AnyPin,
+ valid_pin: AnyPin,
+ data_pins: [AnyPin; 4],
+}
+
+#[cfg(test)]
+#[embedded_test::tests(default_timeout = 3)]
+mod tests {
+ use super::*;
+
+ #[init]
+ fn init() -> Context {
+ let peripherals = esp_hal::init(esp_hal::Config::default());
+
+ let dma_channel = peripherals.DMA_CH0;
+
+ let parl_io = peripherals.PARL_IO;
+
+ Context {
+ parl_io,
+ dma_channel,
+ clock_pin: peripherals.GPIO11.degrade(),
+ valid_pin: peripherals.GPIO10.degrade(),
+ data_pins: [
+ peripherals.GPIO1.degrade(),
+ peripherals.GPIO0.degrade(),
+ peripherals.GPIO14.degrade(),
+ peripherals.GPIO23.degrade(),
+ ],
+ }
+ }
+
+ #[test]
+ fn test_parl_io_rx_can_read_tx(ctx: Context) {
+ const BUFFER_SIZE: usize = 64;
+
+ let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(BUFFER_SIZE);
+ let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
+ let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
+
+ let (clock_rx, clock_tx) = ctx.clock_pin.split();
+ let (valid_rx, valid_tx) = ctx.valid_pin.split();
+ let [(d0_rx, d0_tx), (d1_rx, d1_tx), (d2_rx, d2_tx), (d3_rx, d3_tx)] =
+ ctx.data_pins.map(|pin| pin.split());
+
+ let tx_pins = TxFourBits::new(d0_tx, d1_tx, d2_tx, d3_tx);
+ let rx_pins = RxFourBits::new(d0_rx, d1_rx, d2_rx, d3_rx);
+
+ let tx_pins = TxPinConfigWithValidPin::new(tx_pins, valid_tx);
+ let mut rx_pins = RxPinConfigWithValidPin::new(rx_pins, valid_rx, EnableMode::HighLevel);
+
+ let clock_out_pin = ClkOutPin::new(clock_tx);
+ let mut clock_in_pin = RxClkInPin::new(clock_rx, SampleEdge::Normal);
+
+ let pio = ParlIoFullDuplex::new(ctx.parl_io, ctx.dma_channel, 40.MHz()).unwrap();
+
+ let pio_tx = pio
+ .tx
+ .with_config(
+ tx_pins,
+ clock_out_pin,
+ 0,
+ SampleEdge::Invert,
+ BitPackOrder::Lsb,
+ )
+ .unwrap();
+ let pio_rx = pio
+ .rx
+ .with_config(&mut rx_pins, &mut clock_in_pin, BitPackOrder::Lsb, None)
+ .unwrap();
+
+ for (i, b) in dma_tx_buf.as_mut_slice().iter_mut().enumerate() {
+ *b = i as u8;
+ }
+
+ let rx_transfer = pio_rx
+ .read(Some(dma_rx_buf.len()), dma_rx_buf)
+ .map_err(|e| e.0)
+ .unwrap();
+ let tx_transfer = pio_tx
+ .write(dma_tx_buf.len(), dma_tx_buf)
+ .map_err(|e| e.0)
+ .unwrap();
+ (_, _, dma_tx_buf) = tx_transfer.wait();
+ (_, _, dma_rx_buf) = rx_transfer.wait();
+
+ assert_eq!(dma_rx_buf.as_slice(), dma_tx_buf.as_slice());
+ }
+}
diff --git a/hil-test/tests/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs
index e361f5dce..7a86b9eea 100644
--- a/hil-test/tests/parl_io_tx.rs
+++ b/hil-test/tests/parl_io_tx.rs
@@ -9,7 +9,8 @@
#[cfg(esp32c6)]
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
use esp_hal::{
- dma::DmaChannel0,
+ dma::{DmaChannel0, DmaTxBuf},
+ dma_tx_buffer,
gpio::{
interconnect::{InputSignal, OutputSignal},
NoPin,
@@ -78,8 +79,8 @@ mod tests {
#[test]
fn test_parl_io_tx_16bit_valid_clock_count(ctx: Context) {
const BUFFER_SIZE: usize = 64;
- let tx_buffer = [0u16; BUFFER_SIZE];
- let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
+
+ let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(2 * BUFFER_SIZE).unwrap();
let pins = TxSixteenBits::new(
NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin,
@@ -88,8 +89,7 @@ mod tests {
let mut pins = TxPinConfigIncludingValidPin::new(pins);
let mut clock_pin = ClkOutPin::new(ctx.clock);
- let pio =
- ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap();
+ let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz()).unwrap();
let mut pio = pio
.tx
@@ -102,7 +102,7 @@ mod tests {
)
.unwrap(); // TODO: handle error
- // use a PCNT unit to count the negitive clock edges only when valid is high
+ // use a PCNT unit to count the negative clock edges only when valid is high
let clock_unit = ctx.pcnt_unit;
clock_unit.channel0.set_edge_signal(ctx.clock_loopback);
clock_unit.channel0.set_ctrl_signal(ctx.valid_loopback);
@@ -115,8 +115,11 @@ mod tests {
for _ in 0..100 {
clock_unit.clear();
- let xfer = pio.write_dma(&tx_buffer).unwrap();
- xfer.wait().unwrap();
+ let xfer = pio
+ .write(dma_tx_buf.len(), dma_tx_buf)
+ .map_err(|e| e.0)
+ .unwrap();
+ (_, pio, dma_tx_buf) = xfer.wait();
info!("clock count: {}", clock_unit.value());
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
}
@@ -125,8 +128,7 @@ mod tests {
#[test]
fn test_parl_io_tx_8bit_valid_clock_count(ctx: Context) {
const BUFFER_SIZE: usize = 64;
- let tx_buffer = [0u8; BUFFER_SIZE];
- let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
+ let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(BUFFER_SIZE).unwrap();
let pins = TxEightBits::new(
NoPin,
@@ -149,8 +151,7 @@ mod tests {
let mut clock_pin = ClkOutPin::new(ctx.clock);
- let pio =
- ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz()).unwrap();
+ let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz()).unwrap();
let mut pio = pio
.tx
@@ -176,8 +177,11 @@ mod tests {
for _ in 0..100 {
clock_unit.clear();
- let xfer = pio.write_dma(&tx_buffer).unwrap();
- xfer.wait().unwrap();
+ let xfer = pio
+ .write(dma_tx_buf.len(), dma_tx_buf)
+ .map_err(|e| e.0)
+ .unwrap();
+ (_, pio, dma_tx_buf) = xfer.wait();
info!("clock count: {}", clock_unit.value());
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
}
diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs
index ecde95ae7..c8b09ec78 100644
--- a/hil-test/tests/parl_io_tx_async.rs
+++ b/hil-test/tests/parl_io_tx_async.rs
@@ -9,7 +9,8 @@
#[cfg(esp32c6)]
use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits};
use esp_hal::{
- dma::DmaChannel0,
+ dma::{DmaChannel0, DmaTxBuf},
+ dma_tx_buffer,
gpio::{
interconnect::{InputSignal, OutputSignal},
NoPin,
@@ -78,8 +79,7 @@ mod tests {
#[test]
async fn test_parl_io_tx_async_16bit_valid_clock_count(ctx: Context) {
const BUFFER_SIZE: usize = 64;
- let tx_buffer = [0u16; BUFFER_SIZE];
- let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
+ let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(2 * BUFFER_SIZE).unwrap();
let pins = TxSixteenBits::new(
NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin,
@@ -88,7 +88,7 @@ mod tests {
let mut pins = TxPinConfigIncludingValidPin::new(pins);
let mut clock_pin = ClkOutPin::new(ctx.clock);
- let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
+ let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz())
.unwrap()
.into_async();
@@ -116,7 +116,12 @@ mod tests {
for _ in 0..100 {
clock_unit.clear();
- pio.write_dma_async(&tx_buffer).await.unwrap();
+ let mut xfer = pio
+ .write(dma_tx_buf.len(), dma_tx_buf)
+ .map_err(|e| e.0)
+ .unwrap();
+ xfer.wait_for_done().await;
+ (_, pio, dma_tx_buf) = xfer.wait();
info!("clock count: {}", clock_unit.value());
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
}
@@ -125,8 +130,8 @@ mod tests {
#[test]
async fn test_parl_io_tx_async_8bit_valid_clock_count(ctx: Context) {
const BUFFER_SIZE: usize = 64;
- let tx_buffer = [0u8; BUFFER_SIZE];
- let (_, tx_descriptors) = esp_hal::dma_descriptors!(0, 2 * BUFFER_SIZE);
+
+ let mut dma_tx_buf: DmaTxBuf = dma_tx_buffer!(BUFFER_SIZE).unwrap();
let pins = TxEightBits::new(
NoPin,
@@ -149,7 +154,7 @@ mod tests {
let mut clock_pin = ClkOutPin::new(ctx.clock);
- let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, tx_descriptors, 10.MHz())
+ let pio = ParlIoTxOnly::new(ctx.parl_io, ctx.dma_channel, 10.MHz())
.unwrap()
.into_async();
@@ -178,7 +183,12 @@ mod tests {
for _ in 0..100 {
clock_unit.clear();
- pio.write_dma_async(&tx_buffer).await.unwrap();
+ let mut xfer = pio
+ .write(dma_tx_buf.len(), dma_tx_buf)
+ .map_err(|e| e.0)
+ .unwrap();
+ xfer.wait_for_done().await;
+ (_, pio, dma_tx_buf) = xfer.wait();
info!("clock count: {}", clock_unit.value());
assert_eq!(clock_unit.value(), BUFFER_SIZE as _);
}