Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unsafe dma api #1523

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- ESP32-PICO-V3-02: Initial support (#1155)
- `time::current_time` API (#1503)
- Add an unsafe API to SPI master enabling use-cases which are not possible using the safe API (#1523)

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions esp-hal/src/aes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ pub mod dma {
ChannelTypes,
DmaError,
DmaPeripheral,
DmaTransferRxTx,
DmaTransfer,
RxPrivate,
TxPrivate,
},
Expand Down Expand Up @@ -346,7 +346,7 @@ pub mod dma {
aes_dma: &'t mut AesDma<'d, C>,
}

impl<'t, 'd, C> DmaTransferRxTx for AesDmaTransferRxTx<'t, 'd, C>
impl<'t, 'd, C> DmaTransfer for AesDmaTransferRxTx<'t, 'd, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
Expand Down
10 changes: 0 additions & 10 deletions esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1504,16 +1504,6 @@ pub trait DmaTransfer: Drop {
fn is_done(&self) -> bool;
}

/// Trait to be implemented for an in progress dma transfer.
#[allow(clippy::type_complexity, drop_bounds)]
#[doc(hidden)]
pub trait DmaTransferRxTx: Drop {
/// Wait for the transfer to finish.
fn wait(self) -> Result<(), DmaError>;
/// Check if the transfer is finished.
fn is_done(&self) -> bool;
}

#[cfg(feature = "async")]
pub(crate) mod asynch {
use core::task::Poll;
Expand Down
5 changes: 1 addition & 4 deletions esp-hal/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ pub use nb;
#[cfg(any(dport, pcr, system))]
pub use crate::clock::Clock as _esp_hal_clock_Clock;
#[cfg(any(gdma, pdma))]
pub use crate::dma::{
DmaTransfer as _esp_hal_dma_DmaTransfer,
DmaTransferRxTx as _esp_hal_dma_DmaTransferRxTx,
};
pub use crate::dma::DmaTransfer as _esp_hal_dma_DmaTransfer;
#[cfg(gpio)]
pub use crate::gpio::{
InputPin as _esp_hal_gpio_InputPin,
Expand Down
113 changes: 95 additions & 18 deletions esp-hal/src/spi/master.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,6 @@ pub mod dma {
ChannelTypes,
DmaError,
DmaTransfer,
DmaTransferRxTx,
RxPrivate,
Spi2Peripheral,
SpiPeripheral,
Expand Down Expand Up @@ -901,6 +900,7 @@ pub mod dma {
}
}
}

/// An in-progress DMA transfer
#[must_use]
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
Expand All @@ -914,7 +914,7 @@ pub mod dma {
spi_dma: &'t mut SpiDma<'d, T, C, M, DmaMode>,
}

impl<'t, 'd, T, C, M, DmaMode> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
impl<'t, 'd, T, C, M, DmaMode> DmaTransfer for SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
Expand Down Expand Up @@ -1109,14 +1109,9 @@ pub mod dma {
where
TXBUF: ReadBuffer<Word = u8>,
{
let (ptr, len) = unsafe { words.read_buffer() };

if len > MAX_DMA_SIZE {
return Err(super::Error::MaxDmaTransferSizeExceeded);
unsafe {
self.dma_write_unchecked(words)?;
}

self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?;
Ok(SpiDmaTransfer { spi_dma: self })
}

Expand All @@ -1133,15 +1128,8 @@ pub mod dma {
where
RXBUF: WriteBuffer<Word = u8>,
{
let (ptr, len) = unsafe { words.write_buffer() };

if len > MAX_DMA_SIZE {
return Err(super::Error::MaxDmaTransferSizeExceeded);
}

unsafe {
self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?;
self.dma_read_unchecked(words)?;
}
Ok(SpiDmaTransfer { spi_dma: self })
}
Expand All @@ -1156,6 +1144,81 @@ pub mod dma {
words: &'t TXBUF,
read_buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>, super::Error>
where
TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>,
{
unsafe {
self.dma_transfer_unchecked(words, read_buffer)?;
}
Ok(SpiDmaTransferRxTx { spi_dma: self })
}

/// Perform a DMA write. Use [Self::wait] to await completion of the
/// current transfer.
///
/// # Safety
/// - don't use the buffers while the DMA transaction is ongoing
/// - don't start a new transfer while the DMA transaction is ongoing
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
pub unsafe fn dma_write_unchecked<TXBUF>(
&mut self,
words: &TXBUF,
) -> Result<(), super::Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
let (ptr, len) = unsafe { words.read_buffer() };

if len > MAX_DMA_SIZE {
return Err(super::Error::MaxDmaTransferSizeExceeded);
}

self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?;

Ok(())
}

/// Perform a DMA read. Use [Self::wait] to await completion of the
/// current transfer.
///
/// # Safety
/// - don't use the buffers while the DMA transaction is ongoing
/// - don't start a new transfer while the DMA transaction is ongoing
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
pub unsafe fn dma_read_unchecked<RXBUF>(
&mut self,
words: &mut RXBUF,
) -> Result<(), super::Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
let (ptr, len) = unsafe { words.write_buffer() };

if len > MAX_DMA_SIZE {
return Err(super::Error::MaxDmaTransferSizeExceeded);
}

unsafe {
self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?;
}

Ok(())
}

/// Perform a DMA transfer. Use [Self::wait] to await completion of the
/// current transfer.
///
/// # Safety
/// - don't use the buffers while the DMA transaction is ongoing
/// - don't start a new transfer while the DMA transaction is ongoing
pub unsafe fn dma_transfer_unchecked<TXBUF, RXBUF>(
&mut self,
words: &TXBUF,
read_buffer: &mut RXBUF,
) -> Result<(), super::Error>
where
TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>,
Expand All @@ -1177,7 +1240,21 @@ pub mod dma {
&mut self.channel.rx,
)?;
}
Ok(SpiDmaTransferRxTx { spi_dma: self })

Ok(())
}

/// Wait for the DMA transfer to complete
pub fn wait(&mut self) -> Result<(), DmaError> {
MabezDev marked this conversation as resolved.
Show resolved Hide resolved
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
self.spi.flush().ok();

if self.channel.rx.has_error() || self.channel.tx.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
}

Expand Down
3 changes: 1 addition & 2 deletions esp-hal/src/spi/slave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ pub mod dma {
ChannelTypes,
DmaError,
DmaTransfer,
DmaTransferRxTx,
RxPrivate,
Spi2Peripheral,
SpiPeripheral,
Expand Down Expand Up @@ -239,7 +238,7 @@ pub mod dma {
spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>,
}

impl<'t, 'd, T, C, DmaMode> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
impl<'t, 'd, T, C, DmaMode> DmaTransfer for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
Expand Down
Loading