Simplify dma usage (#1238)

* Simplify SPI,I2S,AES

* Simplify PARL_IO and I8080

* Adapt docs

* Don't require `&mut` for tx-buffer

* Annotate DMA transfer structs as `#[must_use]`

* CHANGELOG.md entry
This commit is contained in:
Björn Quentin 2024-03-13 11:14:56 +01:00 committed by GitHub
parent cc9ccb3f83
commit c283563542
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 317 additions and 619 deletions

View File

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixing `esp-wifi` + `TRNG` issue on `ESP32-S2` (#1272) - Fixing `esp-wifi` + `TRNG` issue on `ESP32-S2` (#1272)
### Changed ### Changed
- Prefer mutable references over moving for DMA transactions (#1238)
### Removed ### Removed

View File

@ -242,8 +242,6 @@ pub enum Endianness {
#[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))]
pub mod dma { pub mod dma {
use core::mem;
use embedded_dma::{ReadBuffer, WriteBuffer}; use embedded_dma::{ReadBuffer, WriteBuffer};
use crate::{ use crate::{
@ -303,28 +301,22 @@ pub mod dma {
} }
/// An in-progress DMA transfer /// An in-progress DMA transfer
pub struct AesDmaTransferRxTx<'d, C, RBUFFER, TBUFFER> #[must_use]
pub struct AesDmaTransferRxTx<'t, 'd, C>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: AesPeripheral, C::P: AesPeripheral,
{ {
aes_dma: AesDma<'d, C>, aes_dma: &'t mut AesDma<'d, C>,
rbuffer: RBUFFER,
tbuffer: TBUFFER,
} }
impl<'d, C, RXBUF, TXBUF> DmaTransferRxTx<RXBUF, TXBUF, AesDma<'d, C>> impl<'t, 'd, C> DmaTransferRxTx for AesDmaTransferRxTx<'t, 'd, C>
for AesDmaTransferRxTx<'d, C, RXBUF, TXBUF>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: AesPeripheral, C::P: AesPeripheral,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// AES instance. fn wait(self) -> Result<(), DmaError> {
fn wait(
self,
) -> Result<(RXBUF, TXBUF, AesDma<'d, C>), (DmaError, RXBUF, TXBUF, AesDma<'d, C>)>
{
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
while self.aes_dma.aes.aes.state().read().state().bits() != 2 // DMA status DONE == 2 while self.aes_dma.aes.aes.state().read().state().bits() != 2 // DMA status DONE == 2
@ -335,25 +327,10 @@ pub mod dma {
self.aes_dma.finish_transform(); self.aes_dma.finish_transform();
let err = self.aes_dma.channel.rx.has_error() || self.aes_dma.channel.tx.has_error(); if self.aes_dma.channel.rx.has_error() || self.aes_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
// `DmaTransferRxTx` needs to have a `Drop` implementation, because we accept } else {
// managed buffers that can free their memory on drop. Because of that Ok(())
// we can't move out of the `DmaTransferRxTx`'s fields, so we use `ptr::read`
// and `mem::forget`.
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let rbuffer = core::ptr::read(&self.rbuffer);
let tbuffer = core::ptr::read(&self.tbuffer);
let payload = core::ptr::read(&self.aes_dma);
mem::forget(self);
if err {
Err((DmaError::DescriptorError, rbuffer, tbuffer, payload))
} else {
Ok((rbuffer, tbuffer, payload))
}
} }
} }
@ -364,7 +341,7 @@ pub mod dma {
} }
} }
impl<'d, C, RXBUF, TXBUF> Drop for AesDmaTransferRxTx<'d, C, RXBUF, TXBUF> impl<'t, 'd, C> Drop for AesDmaTransferRxTx<'t, 'd, C>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: AesPeripheral, C::P: AesPeripheral,
@ -409,14 +386,14 @@ pub mod dma {
/// This will return a [AesDmaTransferRxTx] owning the buffer(s) and the /// This will return a [AesDmaTransferRxTx] owning the buffer(s) and the
/// AES instance. The maximum amount of data to be sent/received /// AES instance. The maximum amount of data to be sent/received
/// is 32736 bytes. /// is 32736 bytes.
pub fn process<TXBUF, RXBUF>( pub fn process<'t, TXBUF, RXBUF>(
mut self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
mut read_buffer: RXBUF, read_buffer: &'t mut RXBUF,
mode: Mode, mode: Mode,
cipher_mode: CipherMode, cipher_mode: CipherMode,
key: [u8; 16], key: [u8; 16],
) -> Result<AesDmaTransferRxTx<'d, C, RXBUF, TXBUF>, crate::dma::DmaError> ) -> Result<AesDmaTransferRxTx<'t, 'd, C>, crate::dma::DmaError>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
@ -434,11 +411,7 @@ pub mod dma {
key, key,
)?; )?;
Ok(AesDmaTransferRxTx { Ok(AesDmaTransferRxTx { aes_dma: self })
aes_dma: self,
rbuffer: read_buffer,
tbuffer: words,
})
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]

View File

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

View File

@ -198,16 +198,16 @@ impl DataFormat {
} }
/// An in-progress DMA write transfer. /// An in-progress DMA write transfer.
pub struct I2sWriteDmaTransfer<'d, T, CH, BUFFER> #[must_use]
pub struct I2sWriteDmaTransfer<'t, 'd, T, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
i2s_tx: I2sTx<'d, T, CH>, i2s_tx: &'t mut I2sTx<'d, T, CH>,
buffer: BUFFER,
} }
impl<'d, T, CH, BUFFER> I2sWriteDmaTransfer<'d, T, CH, BUFFER> impl<'t, 'd, T, CH> I2sWriteDmaTransfer<'t, 'd, T, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
@ -235,61 +235,32 @@ where
/// Stop for the DMA transfer and return the buffer and the /// Stop for the DMA transfer and return the buffer and the
/// I2sTx instance. /// I2sTx instance.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn stop(self) -> Result<(BUFFER, I2sTx<'d, T, CH>), (DmaError, BUFFER, I2sTx<'d, T, CH>)> { pub fn stop(self) -> Result<(), DmaError> {
T::tx_stop(); T::tx_stop();
let err = self.i2s_tx.tx_channel.has_error(); if self.i2s_tx.tx_channel.has_error() {
Err(DmaError::DescriptorError)
// `DmaTransfer` needs to have a `Drop` implementation, because we accept } else {
// managed buffers that can free their memory on drop. Because of that Ok(())
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read`
// and `mem::forget`.
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.i2s_tx);
core::mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }
} }
impl<'d, T, CH, BUFFER> DmaTransfer<BUFFER, I2sTx<'d, T, CH>> impl<'t, 'd, T, CH> DmaTransfer for I2sWriteDmaTransfer<'t, 'd, T, CH>
for I2sWriteDmaTransfer<'d, T, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// I2sTx instance. fn wait(self) -> Result<(), DmaError> {
fn wait(self) -> Result<(BUFFER, I2sTx<'d, T, CH>), (DmaError, BUFFER, I2sTx<'d, T, CH>)> {
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
self.i2s_tx.wait_tx_dma_done().ok(); self.i2s_tx.wait_tx_dma_done().ok();
let err = self.i2s_tx.tx_channel.has_error();
// `DmaTransfer` needs to have a `Drop` implementation, because we accept if self.i2s_tx.tx_channel.has_error() {
// managed buffers that can free their memory on drop. Because of that Err(DmaError::DescriptorError)
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read` } else {
// and `mem::forget`. Ok(())
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.i2s_tx);
core::mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }
@ -299,7 +270,7 @@ where
} }
} }
impl<'d, T, CH, BUFFER> Drop for I2sWriteDmaTransfer<'d, T, CH, BUFFER> impl<'t, 'd, T, CH> Drop for I2sWriteDmaTransfer<'t, 'd, T, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
@ -323,31 +294,34 @@ where
/// Write I2S. /// Write I2S.
/// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA /// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA
/// transfer /// transfer
fn write_dma(self, words: TXBUF) -> Result<I2sWriteDmaTransfer<'d, T, CH, TXBUF>, Error> fn write_dma<'t>(
&'t mut self,
words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
where where
TXBUF: ReadBuffer<Word = u8>; TXBUF: ReadBuffer<Word = u8>;
/// Continuously write to I2S. Returns [I2sWriteDmaTransfer] which /// Continuously write to I2S. Returns [I2sWriteDmaTransfer] which
/// represents the in-progress DMA transfer /// represents the in-progress DMA transfer
fn write_dma_circular( fn write_dma_circular<'t>(
self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'d, T, CH, TXBUF>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
where where
TXBUF: ReadBuffer<Word = u8>; TXBUF: ReadBuffer<Word = u8>;
} }
/// An in-progress DMA read transfer. /// An in-progress DMA read transfer.
pub struct I2sReadDmaTransfer<'d, T, CH, BUFFER> #[must_use]
pub struct I2sReadDmaTransfer<'t, 'd, T, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
i2s_rx: I2sRx<'d, T, CH>, i2s_rx: &'t mut I2sRx<'d, T, CH>,
buffer: BUFFER,
} }
impl<'d, T, CH, BUFFER> I2sReadDmaTransfer<'d, T, CH, BUFFER> impl<'t, 'd, T, CH> I2sReadDmaTransfer<'t, 'd, T, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
@ -361,72 +335,38 @@ where
Ok(self.i2s_rx.rx_channel.pop(data)?) Ok(self.i2s_rx.rx_channel.pop(data)?)
} }
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete.
/// I2sTx instance after copying the read data to the given buffer. /// Length of the received data is returned
/// Length of the received data is returned at the third element of the
/// tuple.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn wait_receive( pub fn wait_receive(self, dst: &mut [u8]) -> Result<usize, (DmaError, usize)> {
mut self,
dst: &mut [u8],
) -> Result<(BUFFER, I2sRx<'d, T, CH>, usize), (DmaError, BUFFER, I2sRx<'d, T, CH>, usize)>
{
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
self.i2s_rx.wait_rx_dma_done().ok(); self.i2s_rx.wait_rx_dma_done().ok();
let len = self.i2s_rx.rx_channel.drain_buffer(dst).unwrap(); let len = self.i2s_rx.rx_channel.drain_buffer(dst).unwrap();
let err = self.i2s_rx.rx_channel.has_error();
// `DmaTransfer` needs to have a `Drop` implementation, because we accept if self.i2s_rx.rx_channel.has_error() {
// managed buffers that can free their memory on drop. Because of that Err((DmaError::DescriptorError, len))
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read` } else {
// and `mem::forget`. Ok(len)
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.i2s_rx);
core::mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload, len))
} else {
Ok((buffer, payload, len))
}
} }
} }
} }
impl<'d, T, CH, BUFFER> DmaTransfer<BUFFER, I2sRx<'d, T, CH>> impl<'t, 'd, T, CH> DmaTransfer for I2sReadDmaTransfer<'t, 'd, T, CH>
for I2sReadDmaTransfer<'d, T, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// I2sTx instance. fn wait(self) -> Result<(), DmaError> {
fn wait(self) -> Result<(BUFFER, I2sRx<'d, T, CH>), (DmaError, BUFFER, I2sRx<'d, T, CH>)> {
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
self.i2s_rx.wait_rx_dma_done().ok(); self.i2s_rx.wait_rx_dma_done().ok();
let err = self.i2s_rx.rx_channel.has_error();
// `DmaTransfer` needs to have a `Drop` implementation, because we accept if self.i2s_rx.rx_channel.has_error() {
// managed buffers that can free their memory on drop. Because of that Err(DmaError::DescriptorError)
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read` } else {
// and `mem::forget`. Ok(())
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.i2s_rx);
core::mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }
@ -436,7 +376,7 @@ where
} }
} }
impl<T, CH, BUFFER> Drop for I2sReadDmaTransfer<'_, T, CH, BUFFER> impl<'t, T, CH> Drop for I2sReadDmaTransfer<'t, '_, T, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
@ -460,14 +400,20 @@ where
/// Read I2S. /// Read I2S.
/// Returns [I2sReadDmaTransfer] which represents the in-progress DMA /// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
/// transfer /// transfer
fn read_dma(self, words: RXBUF) -> Result<I2sReadDmaTransfer<'d, T, CH, RXBUF>, Error> fn read_dma<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
where where
RXBUF: WriteBuffer<Word = u8>; RXBUF: WriteBuffer<Word = u8>;
/// Continuously read from I2S. /// Continuously read from I2S.
/// Returns [I2sReadDmaTransfer] which represents the in-progress DMA /// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
/// transfer /// transfer
fn read_dma_circular(self, words: RXBUF) -> Result<I2sReadDmaTransfer<'d, T, CH, RXBUF>, Error> fn read_dma_circular<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
where where
RXBUF: WriteBuffer<Word = u8>; RXBUF: WriteBuffer<Word = u8>;
} }
@ -628,11 +574,11 @@ where
Ok(()) Ok(())
} }
fn start_tx_transfer<TXBUF>( fn start_tx_transfer<'t, TXBUF>(
mut self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
circular: bool, circular: bool,
) -> Result<I2sWriteDmaTransfer<'d, T, CH, TXBUF>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -653,10 +599,7 @@ where
// start: set I2S_TX_START // start: set I2S_TX_START
T::tx_start(); T::tx_start();
Ok(I2sWriteDmaTransfer { Ok(I2sWriteDmaTransfer { i2s_tx: self })
i2s_tx: self,
buffer: words,
})
} }
fn wait_tx_dma_done(&self) -> Result<(), Error> { fn wait_tx_dma_done(&self) -> Result<(), Error> {
@ -713,17 +656,20 @@ where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
fn write_dma(self, words: TXBUF) -> Result<I2sWriteDmaTransfer<'d, T, CH, TXBUF>, Error> fn write_dma<'t>(
&'t mut self,
words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
self.start_tx_transfer(words, false) self.start_tx_transfer(words, false)
} }
fn write_dma_circular( fn write_dma_circular<'t>(
self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'d, T, CH, TXBUF>, Error> ) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -787,11 +733,11 @@ where
Ok(()) Ok(())
} }
fn start_rx_transfer<RXBUF>( fn start_rx_transfer<'t, RXBUF>(
mut self, &'t mut self,
mut words: RXBUF, words: &'t mut RXBUF,
circular: bool, circular: bool,
) -> Result<I2sReadDmaTransfer<'d, T, CH, RXBUF>, Error> ) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -820,10 +766,7 @@ where
#[cfg(esp32)] #[cfg(esp32)]
T::rx_start(len); T::rx_start(len);
Ok(I2sReadDmaTransfer { Ok(I2sReadDmaTransfer { i2s_rx: self })
i2s_rx: self,
buffer: words,
})
} }
fn wait_rx_dma_done(&self) -> Result<(), Error> { fn wait_rx_dma_done(&self) -> Result<(), Error> {
@ -891,14 +834,20 @@ where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes, CH: ChannelTypes,
{ {
fn read_dma(self, words: RXBUF) -> Result<I2sReadDmaTransfer<'d, T, CH, RXBUF>, Error> fn read_dma<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
self.start_rx_transfer(words, false) self.start_rx_transfer(words, false)
} }
fn read_dma_circular(self, words: RXBUF) -> Result<I2sReadDmaTransfer<'d, T, CH, RXBUF>, Error> fn read_dma_circular<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -2130,7 +2079,7 @@ pub mod asynch {
&mut self, &mut self,
f: impl FnOnce(&mut [u8]) -> usize, f: impl FnOnce(&mut [u8]) -> usize,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
let avail = self.available().await; let _avail = self.available().await;
Ok(self.i2s_tx.tx_channel.push_with(f)?) Ok(self.i2s_tx.tx_channel.push_with(f)?)
} }
} }

View File

@ -296,12 +296,12 @@ where
Ok(()) Ok(())
} }
pub fn send_dma<TXBUF>( pub fn send_dma<'t, TXBUF>(
mut self, &'t mut self,
cmd: impl Into<Command<P::Word>>, cmd: impl Into<Command<P::Word>>,
dummy: u8, dummy: u8,
data: TXBUF, data: &'t TXBUF,
) -> Result<Transfer<'d, TX, TXBUF, P>, DmaError> ) -> Result<Transfer<'t, 'd, TX, P>, DmaError>
where where
TXBUF: ReadBuffer<Word = P::Word>, TXBUF: ReadBuffer<Word = P::Word>,
{ {
@ -313,7 +313,6 @@ where
Ok(Transfer { Ok(Transfer {
instance: Some(self), instance: Some(self),
buffer: Some(data),
}) })
} }
} }
@ -432,17 +431,15 @@ impl<'d, TX, P> core::fmt::Debug for I8080<'d, TX, P> {
} }
/// An in-progress transfer /// An in-progress transfer
pub struct Transfer<'d, TX: Tx, BUFFER, P> { #[must_use]
instance: Option<I8080<'d, TX, P>>, pub struct Transfer<'t, 'd, TX: Tx, P> {
buffer: Option<BUFFER>, instance: Option<&'t mut I8080<'d, TX, P>>,
} }
impl<'d, TX: Tx, BUFFER, P> Transfer<'d, TX, BUFFER, P> { impl<'t, 'd, TX: Tx, P> Transfer<'t, 'd, TX, P> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn wait( pub fn wait(mut self) -> Result<(), DmaError> {
mut self, let instance = self
) -> Result<(BUFFER, I8080<'d, TX, P>), (DmaError, BUFFER, I8080<'d, TX, P>)> {
let mut instance = self
.instance .instance
.take() .take()
.expect("instance must be available throughout object lifetime"); .expect("instance must be available throughout object lifetime");
@ -454,15 +451,10 @@ impl<'d, TX: Tx, BUFFER, P> Transfer<'d, TX, BUFFER, P> {
instance.tear_down_send(); instance.tear_down_send();
} }
let buffer = self
.buffer
.take()
.expect("buffer must be available throughout object lifetime");
if instance.tx_channel.has_error() { if instance.tx_channel.has_error() {
Err((DmaError::DescriptorError, buffer, instance)) Err(DmaError::DescriptorError)
} else { } else {
Ok((buffer, instance)) Ok(())
} }
} }
@ -477,7 +469,7 @@ impl<'d, TX: Tx, BUFFER, P> Transfer<'d, TX, BUFFER, P> {
} }
} }
impl<'d, TX: Tx, BUFFER, P> Drop for Transfer<'d, TX, BUFFER, P> { impl<'t, 'd, TX: Tx, P> Drop for Transfer<'t, 'd, TX, P> {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(instance) = self.instance.as_mut() { if let Some(instance) = self.instance.as_mut() {
// This will cancel the transfer. // This will cancel the transfer.

View File

@ -43,11 +43,9 @@
//! //!
//! ### Start TX transfer //! ### Start TX transfer
//! ```no_run //! ```no_run
//! let transfer = parl_io_tx.write_dma(buffer).unwrap(); //! let mut transfer = parl_io_tx.write_dma(buffer).unwrap();
//! //!
//! // the buffer and driver is moved into the transfer and we can get it back via //! transfer.wait().unwrap();
//! // `wait`
//! (buffer, parl_io_tx) = transfer.wait().unwrap();
//! ``` //! ```
//! //!
//! ### Initialization for RX //! ### Initialization for RX
@ -75,15 +73,10 @@
//! //!
//! ### Start RX transfer //! ### Start RX transfer
//! ```no_run //! ```no_run
//! let transfer = parl_io_rx.read_dma(buffer).unwrap(); //! let mut transfer = parl_io_rx.read_dma(buffer).unwrap();
//! //! transfer.wait().unwrap();
//! // the buffer and driver is moved into the transfer and we can get it back via
//! // `wait`
//! (buffer, parl_io_rx) = transfer.wait().unwrap();
//! ``` //! ```
use core::mem;
use embedded_dma::{ReadBuffer, WriteBuffer}; use embedded_dma::{ReadBuffer, WriteBuffer};
use fugit::HertzU32; use fugit::HertzU32;
use peripheral::PeripheralRef; use peripheral::PeripheralRef;
@ -1172,10 +1165,10 @@ where
/// instance. /// instance.
/// ///
/// The maximum amount of data to be sent is 32736 bytes. /// The maximum amount of data to be sent is 32736 bytes.
pub fn write_dma<TXBUF>( pub fn write_dma<'t, TXBUF>(
mut self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
) -> Result<DmaTransfer<'d, CH, TXBUF, P, CP>, Error> ) -> Result<DmaTransfer<'t, 'd, CH, P, CP>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1187,10 +1180,7 @@ where
self.start_write_bytes_dma(ptr, len)?; self.start_write_bytes_dma(ptr, len)?;
Ok(DmaTransfer { Ok(DmaTransfer { instance: self })
instance: self,
buffer: words,
})
} }
fn start_write_bytes_dma(&mut self, ptr: *const u8, len: usize) -> Result<(), Error> { fn start_write_bytes_dma(&mut self, ptr: *const u8, len: usize) -> Result<(), Error> {
@ -1221,54 +1211,37 @@ where
} }
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
pub struct DmaTransfer<'d, C, BUFFER, P, CP> #[must_use]
pub struct DmaTransfer<'t, 'd, C, P, CP>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
{ {
instance: ParlIoTx<'d, C, P, CP>, instance: &'t mut ParlIoTx<'d, C, P, CP>,
buffer: BUFFER,
} }
impl<'d, C, BUFFER, P, CP> DmaTransfer<'d, C, BUFFER, P, CP> impl<'t, 'd, C, P, CP> DmaTransfer<'t, 'd, C, P, CP>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: TxPins + ConfigurePins, P: TxPins + ConfigurePins,
CP: TxClkPin, CP: TxClkPin,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// SPI instance.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn wait( pub fn wait(self) -> Result<(), DmaError> {
self,
) -> Result<(BUFFER, ParlIoTx<'d, C, P, CP>), (DmaError, BUFFER, ParlIoTx<'d, C, P, CP>)> {
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
while !Instance::is_tx_eof() {} while !Instance::is_tx_eof() {}
Instance::set_tx_start(false); Instance::set_tx_start(false);
let err = self.instance.tx_channel.has_error(); if self.instance.tx_channel.has_error() {
Err(DmaError::DescriptorError)
// `DmaTransfer` needs to have a `Drop` implementation, because we accept } else {
// managed buffers that can free their memory on drop. Because of that Ok(())
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read`
// and `mem::forget`.
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.instance);
mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }
@ -1295,10 +1268,10 @@ where
/// ///
/// It's only limited by the size of the DMA buffer when using /// It's only limited by the size of the DMA buffer when using
/// [EofMode::EnableSignal]. /// [EofMode::EnableSignal].
pub fn read_dma<RXBUF>( pub fn read_dma<'t, RXBUF>(
mut self, &'t mut self,
mut words: RXBUF, words: &'t mut RXBUF,
) -> Result<RxDmaTransfer<'d, CH, RXBUF, P, CP>, Error> ) -> Result<RxDmaTransfer<'t, 'd, CH, P, CP>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1310,10 +1283,7 @@ where
self.start_receive_bytes_dma(ptr, len)?; self.start_receive_bytes_dma(ptr, len)?;
Ok(RxDmaTransfer { Ok(RxDmaTransfer { instance: self })
instance: self,
buffer: words,
})
} }
fn start_receive_bytes_dma(&mut self, ptr: *mut u8, len: usize) -> Result<(), Error> { fn start_receive_bytes_dma(&mut self, ptr: *mut u8, len: usize) -> Result<(), Error> {
@ -1338,30 +1308,26 @@ where
} }
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
pub struct RxDmaTransfer<'d, C, BUFFER, P, CP> pub struct RxDmaTransfer<'t, 'd, C, P, CP>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
{ {
instance: ParlIoRx<'d, C, P, CP>, instance: &'t mut ParlIoRx<'d, C, P, CP>,
buffer: BUFFER,
} }
impl<'d, C, BUFFER, P, CP> RxDmaTransfer<'d, C, BUFFER, P, CP> impl<'t, 'd, C, P, CP> RxDmaTransfer<'t, 'd, C, P, CP>
where where
C: ChannelTypes, C: ChannelTypes,
C::P: ParlIoPeripheral, C::P: ParlIoPeripheral,
P: RxPins + ConfigurePins, P: RxPins + ConfigurePins,
CP: RxClkPin, CP: RxClkPin,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// SPI instance.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn wait( pub fn wait(self) -> Result<(), DmaError> {
self,
) -> Result<(BUFFER, ParlIoRx<'d, C, P, CP>), (DmaError, BUFFER, ParlIoRx<'d, C, P, CP>)> {
loop { loop {
if self.is_done() || self.is_eof_error() { if self.is_done() || self.is_eof_error() {
break; break;
@ -1370,23 +1336,10 @@ where
Instance::set_rx_start(false); Instance::set_rx_start(false);
// `DmaTransfer` needs to have a `Drop` implementation, because we accept if self.instance.rx_channel.has_error() {
// managed buffers that can free their memory on drop. Because of that Err(DmaError::DescriptorError)
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read` } else {
// and `mem::forget`. Ok(())
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.instance);
let err = self.instance.rx_channel.has_error();
mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }

View File

@ -759,8 +759,6 @@ where
} }
pub mod dma { pub mod dma {
use core::mem;
use embedded_dma::{ReadBuffer, WriteBuffer}; use embedded_dma::{ReadBuffer, WriteBuffer};
use super::*; use super::*;
@ -841,56 +839,34 @@ pub mod dma {
} }
} }
/// An in-progress DMA transfer /// An in-progress DMA transfer
pub struct SpiDmaTransferRxTx<'d, T, C, RBUFFER, TBUFFER, M> #[must_use]
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
spi_dma: SpiDma<'d, T, C, M>, spi_dma: &'t mut SpiDma<'d, T, C, M>,
rbuffer: RBUFFER,
tbuffer: TBUFFER,
} }
impl<'d, T, C, RXBUF, TXBUF, M> DmaTransferRxTx<RXBUF, TXBUF, SpiDma<'d, T, C, M>> impl<'t, 'd, T, C, M> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, M>
for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// SPI instance. fn wait(self) -> Result<(), DmaError> {
fn wait(
mut self,
) -> Result<
(RXBUF, TXBUF, SpiDma<'d, T, C, M>),
(DmaError, RXBUF, TXBUF, SpiDma<'d, T, C, M>),
> {
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
self.spi_dma.spi.flush().ok(); self.spi_dma.spi.flush().ok();
let err = self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error();
// `DmaTransfer` needs to have a `Drop` implementation, because we accept if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
// managed buffers that can free their memory on drop. Because of that Err(DmaError::DescriptorError)
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read` } else {
// and `mem::forget`. Ok(())
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let rbuffer = core::ptr::read(&self.rbuffer);
let tbuffer = core::ptr::read(&self.tbuffer);
let payload = core::ptr::read(&self.spi_dma);
mem::forget(self);
if err {
Err((DmaError::DescriptorError, rbuffer, tbuffer, payload))
} else {
Ok((rbuffer, tbuffer, payload))
}
} }
} }
@ -901,7 +877,7 @@ pub mod dma {
} }
} }
impl<'d, T, C, RXBUF, TXBUF, M> Drop for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M> impl<'t, 'd, T, C, M> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, M>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -914,52 +890,34 @@ pub mod dma {
} }
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
pub struct SpiDmaTransfer<'d, T, C, BUFFER, M> #[must_use]
pub struct SpiDmaTransfer<'t, 'd, T, C, M>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
spi_dma: SpiDma<'d, T, C, M>, spi_dma: &'t mut SpiDma<'d, T, C, M>,
buffer: BUFFER,
} }
impl<'d, T, C, BUFFER, M> DmaTransfer<BUFFER, SpiDma<'d, T, C, M>> impl<'t, 'd, T, C, M> DmaTransfer for SpiDmaTransfer<'t, 'd, T, C, M>
for SpiDmaTransfer<'d, T, C, BUFFER, M>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// SPI instance. fn wait(self) -> Result<(), DmaError> {
fn wait(
mut self,
) -> Result<(BUFFER, SpiDma<'d, T, C, M>), (DmaError, BUFFER, SpiDma<'d, T, C, M>)>
{
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
self.spi_dma.spi.flush().ok(); self.spi_dma.spi.flush().ok();
let err = self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error();
// `DmaTransfer` needs to have a `Drop` implementation, because we accept if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
// managed buffers that can free their memory on drop. Because of that Err(DmaError::DescriptorError)
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read` } else {
// and `mem::forget`. Ok(())
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.spi_dma);
mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }
@ -970,7 +928,7 @@ pub mod dma {
} }
} }
impl<'d, T, C, BUFFER, M> Drop for SpiDmaTransfer<'d, T, C, BUFFER, M> impl<'t, 'd, T, C, M> Drop for SpiDmaTransfer<'t, 'd, T, C, M>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -1030,10 +988,10 @@ pub mod dma {
/// instance. The maximum amount of data to be sent is 32736 /// instance. The maximum amount of data to be sent is 32736
/// bytes. /// bytes.
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)] #[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
pub fn dma_write<TXBUF>( pub fn dma_write<'t, TXBUF>(
mut self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
) -> Result<SpiDmaTransfer<'d, T, C, TXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1045,10 +1003,7 @@ pub mod dma {
self.spi self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?; .start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?;
Ok(SpiDmaTransfer { Ok(SpiDmaTransfer { spi_dma: self })
spi_dma: self,
buffer: words,
})
} }
/// Perform a DMA read. /// Perform a DMA read.
@ -1057,10 +1012,10 @@ pub mod dma {
/// instance. The maximum amount of data to be received is 32736 /// instance. The maximum amount of data to be received is 32736
/// bytes. /// bytes.
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)] #[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
pub fn dma_read<RXBUF>( pub fn dma_read<'t, RXBUF>(
mut self, &'t mut self,
mut words: RXBUF, words: &'t mut RXBUF,
) -> Result<SpiDmaTransfer<'d, T, C, RXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1072,10 +1027,7 @@ pub mod dma {
self.spi self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?; .start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?;
Ok(SpiDmaTransfer { Ok(SpiDmaTransfer { spi_dma: self })
spi_dma: self,
buffer: words,
})
} }
/// Perform a DMA transfer. /// Perform a DMA transfer.
@ -1083,11 +1035,11 @@ pub mod dma {
/// This will return a [SpiDmaTransfer] owning the buffer(s) and the SPI /// This will return a [SpiDmaTransfer] owning the buffer(s) and the SPI
/// instance. The maximum amount of data to be sent/received is /// instance. The maximum amount of data to be sent/received is
/// 32736 bytes. /// 32736 bytes.
pub fn dma_transfer<TXBUF, RXBUF>( pub fn dma_transfer<'t, TXBUF, RXBUF>(
mut self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
mut read_buffer: RXBUF, read_buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M>, super::Error> ) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, M>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
@ -1108,11 +1060,7 @@ pub mod dma {
&mut self.channel.rx, &mut self.channel.rx,
false, false,
)?; )?;
Ok(SpiDmaTransferRxTx { Ok(SpiDmaTransferRxTx { spi_dma: self })
spi_dma: self,
rbuffer: read_buffer,
tbuffer: words,
})
} }
} }
@ -1124,14 +1072,14 @@ pub mod dma {
M: IsHalfDuplex, M: IsHalfDuplex,
{ {
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)] #[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
pub fn read<RXBUF>( pub fn read<'t, RXBUF>(
mut self, &'t mut self,
data_mode: SpiDataMode, data_mode: SpiDataMode,
cmd: Command, cmd: Command,
address: Address, address: Address,
dummy: u8, dummy: u8,
mut buffer: RXBUF, buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransfer<'d, T, C, RXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1191,21 +1139,18 @@ pub mod dma {
self.spi self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?; .start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?;
Ok(SpiDmaTransfer { Ok(SpiDmaTransfer { spi_dma: self })
spi_dma: self,
buffer,
})
} }
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)] #[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
pub fn write<TXBUF>( pub fn write<'t, TXBUF>(
mut self, &'t mut self,
data_mode: SpiDataMode, data_mode: SpiDataMode,
cmd: Command, cmd: Command,
address: Address, address: Address,
dummy: u8, dummy: u8,
buffer: TXBUF, buffer: &'t TXBUF,
) -> Result<SpiDmaTransfer<'d, T, C, TXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'t, 'd, T, C, M>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1265,10 +1210,7 @@ pub mod dma {
self.spi self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?; .start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?;
Ok(SpiDmaTransfer { Ok(SpiDmaTransfer { spi_dma: self })
spi_dma: self,
buffer,
})
} }
} }
@ -1516,8 +1458,7 @@ pub mod dma {
mod ehal1 { mod ehal1 {
use embedded_hal_1::spi::{ErrorType, SpiBus}; use embedded_hal_1::spi::{ErrorType, SpiBus};
use super::{super::InstanceDma, *}; use super::*;
use crate::{dma::ChannelTypes, FlashSafeDma};
impl<'d, T, C, M> ErrorType for SpiDma<'d, T, C, M> impl<'d, T, C, M> ErrorType for SpiDma<'d, T, C, M>
where where

View File

@ -137,8 +137,6 @@ where
} }
pub mod dma { pub mod dma {
use core::mem;
use embedded_dma::{ReadBuffer, WriteBuffer}; use embedded_dma::{ReadBuffer, WriteBuffer};
use super::*; use super::*;
@ -220,54 +218,33 @@ pub mod dma {
} }
} }
/// An in-progress DMA transfer /// An in-progress DMA transfer
pub struct SpiDmaTransferRxTx<'d, T, C, RBUFFER, TBUFFER> #[must_use]
pub struct SpiDmaTransferRxTx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
{ {
spi_dma: SpiDma<'d, T, C>, spi_dma: &'t mut SpiDma<'d, T, C>,
rbuffer: RBUFFER,
tbuffer: TBUFFER,
} }
impl<'d, T, C, RXBUF, TXBUF> DmaTransferRxTx<RXBUF, TXBUF, SpiDma<'d, T, C>> impl<'t, 'd, T, C> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C>
for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// SPI instance. fn wait(self) -> Result<(), DmaError> {
fn wait(
mut self,
) -> Result<(RXBUF, TXBUF, SpiDma<'d, T, C>), (DmaError, RXBUF, TXBUF, SpiDma<'d, T, C>)>
{
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
while !self.is_done() {} while !self.is_done() {}
self.spi_dma.spi.flush().ok(); self.spi_dma.spi.flush().ok();
let err = self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error(); if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
// `DmaTransfer` needs to have a `Drop` implementation, because we accept } else {
// managed buffers that can free their memory on drop. Because of that Ok(())
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read`
// and `mem::forget`.
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let rbuffer = core::ptr::read(&self.rbuffer);
let tbuffer = core::ptr::read(&self.tbuffer);
let payload = core::ptr::read(&self.spi_dma);
mem::forget(self);
if err {
Err((DmaError::DescriptorError, rbuffer, tbuffer, payload))
} else {
Ok((rbuffer, tbuffer, payload))
}
} }
} }
@ -278,7 +255,7 @@ pub mod dma {
} }
} }
impl<'d, T, C, RXBUF, TXBUF> Drop for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF> impl<'t, 'd, T, C> Drop for SpiDmaTransferRxTx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -290,48 +267,32 @@ pub mod dma {
} }
} }
pub struct SpiDmaTransferRx<'d, T, C, BUFFER> /// An in-progress DMA transfer.
#[must_use]
pub struct SpiDmaTransferRx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
{ {
spi_dma: SpiDma<'d, T, C>, spi_dma: &'t mut SpiDma<'d, T, C>,
buffer: BUFFER,
} }
impl<'d, T, C, BUFFER> DmaTransfer<BUFFER, SpiDma<'d, T, C>> for SpiDmaTransferRx<'d, T, C, BUFFER> impl<'t, 'd, T, C> DmaTransfer for SpiDmaTransferRx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// SPI instance. fn wait(self) -> Result<(), DmaError> {
fn wait(
mut self,
) -> Result<(BUFFER, SpiDma<'d, T, C>), (DmaError, BUFFER, SpiDma<'d, T, C>)> {
while !self.is_done() {} while !self.is_done() {}
self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is not enough self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is not enough
// `DmaTransfer` needs to have a `Drop` implementation, because we accept if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
// managed buffers that can free their memory on drop. Because of that Err(DmaError::DescriptorError)
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read` } else {
// and `mem::forget`. Ok(())
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.spi_dma);
let err =
self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error();
mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }
@ -342,7 +303,7 @@ pub mod dma {
} }
} }
impl<'d, T, C, BUFFER> Drop for SpiDmaTransferRx<'d, T, C, BUFFER> impl<'t, 'd, T, C> Drop for SpiDmaTransferRx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -356,50 +317,33 @@ pub mod dma {
} }
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
pub struct SpiDmaTransferTx<'d, T, C, BUFFER> #[must_use]
pub struct SpiDmaTransferTx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
{ {
spi_dma: SpiDma<'d, T, C>, spi_dma: &'t mut SpiDma<'d, T, C>,
buffer: BUFFER,
} }
impl<'d, T, C, BUFFER> DmaTransfer<BUFFER, SpiDma<'d, T, C>> for SpiDmaTransferTx<'d, T, C, BUFFER> impl<'t, 'd, T, C> DmaTransfer for SpiDmaTransferTx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
C::P: SpiPeripheral, C::P: SpiPeripheral,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete
/// SPI instance. fn wait(self) -> Result<(), DmaError> {
fn wait(
mut self,
) -> Result<(BUFFER, SpiDma<'d, T, C>), (DmaError, BUFFER, SpiDma<'d, T, C>)> {
// Waiting for the DMA transfer is not enough. We need to wait for the // Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too. // peripheral to finish flushing its buffers, too.
while !self.is_done() {} while !self.is_done() {}
self.spi_dma.spi.flush().ok(); self.spi_dma.spi.flush().ok();
let err = self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error(); if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
// `DmaTransfer` needs to have a `Drop` implementation, because we accept } else {
// managed buffers that can free their memory on drop. Because of that Ok(())
// we can't move out of the `DmaTransfer`'s fields, so we use `ptr::read`
// and `mem::forget`.
//
// NOTE(unsafe) There is no panic branch between getting the resources
// and forgetting `self`.
unsafe {
let buffer = core::ptr::read(&self.buffer);
let payload = core::ptr::read(&self.spi_dma);
mem::forget(self);
if err {
Err((DmaError::DescriptorError, buffer, payload))
} else {
Ok((buffer, payload))
}
} }
} }
@ -410,7 +354,7 @@ pub mod dma {
} }
} }
impl<'d, T, C, BUFFER> Drop for SpiDmaTransferTx<'d, T, C, BUFFER> impl<'t, 'd, T, C> Drop for SpiDmaTransferTx<'t, 'd, T, C>
where where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes, C: ChannelTypes,
@ -456,10 +400,10 @@ pub mod dma {
/// bytes. /// bytes.
/// ///
/// The write is driven by the SPI master's sclk signal and cs line. /// The write is driven by the SPI master's sclk signal and cs line.
pub fn dma_write<TXBUF>( pub fn dma_write<'t, TXBUF>(
mut self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
) -> Result<SpiDmaTransferTx<'d, T, C, TXBUF>, Error> ) -> Result<SpiDmaTransferTx<'t, 'd, T, C>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -471,10 +415,7 @@ pub mod dma {
self.spi self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx) .start_write_bytes_dma(ptr, len, &mut self.channel.tx)
.map(move |_| SpiDmaTransferTx { .map(move |_| SpiDmaTransferTx { spi_dma: self })
spi_dma: self,
buffer: words,
})
} }
/// Register a buffer for a DMA read. /// Register a buffer for a DMA read.
@ -484,10 +425,10 @@ pub mod dma {
/// 32736 bytes. /// 32736 bytes.
/// ///
/// The read is driven by the SPI master's sclk signal and cs line. /// The read is driven by the SPI master's sclk signal and cs line.
pub fn dma_read<RXBUF>( pub fn dma_read<'t, RXBUF>(
mut self, &'t mut self,
mut words: RXBUF, words: &'t mut RXBUF,
) -> Result<SpiDmaTransferRx<'d, T, C, RXBUF>, Error> ) -> Result<SpiDmaTransferRx<'t, 'd, T, C>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -499,10 +440,7 @@ pub mod dma {
self.spi self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx) .start_read_bytes_dma(ptr, len, &mut self.channel.rx)
.map(move |_| SpiDmaTransferRx { .map(move |_| SpiDmaTransferRx { spi_dma: self })
spi_dma: self,
buffer: words,
})
} }
/// Register buffers for a DMA transfer. /// Register buffers for a DMA transfer.
@ -513,11 +451,11 @@ pub mod dma {
/// ///
/// The data transfer is driven by the SPI master's sclk signal and cs /// The data transfer is driven by the SPI master's sclk signal and cs
/// line. /// line.
pub fn dma_transfer<TXBUF, RXBUF>( pub fn dma_transfer<'t, TXBUF, RXBUF>(
mut self, &'t mut self,
words: TXBUF, words: &'t TXBUF,
mut read_buffer: RXBUF, read_buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF>, Error> ) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
@ -538,11 +476,7 @@ pub mod dma {
&mut self.channel.tx, &mut self.channel.tx,
&mut self.channel.rx, &mut self.channel.rx,
) )
.map(move |_| SpiDmaTransferRxTx { .map(move |_| SpiDmaTransferRxTx { spi_dma: self })
spi_dma: self,
rbuffer: read_buffer,
tbuffer: words,
})
} }
} }
} }

View File

@ -16,7 +16,8 @@ use esp_hal::{
Aes, Aes,
Mode, Mode,
}, },
dma::{Dma, DmaDescriptor, DmaPriority}, dma::{Dma, DmaPriority},
dma_buffers,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
}; };
@ -30,73 +31,65 @@ fn main() -> ! {
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);
let dma_channel = dma.channel0; let dma_channel = dma.channel0;
let mut descriptors = [DmaDescriptor::EMPTY; 1]; let (input, mut tx_descriptors, mut output, mut rx_descriptors) = dma_buffers!(16, 16);
let mut rx_descriptors = [DmaDescriptor::EMPTY; 1];
let aes = Aes::new(peripherals.AES).with_dma(dma_channel.configure( let mut aes = Aes::new(peripherals.AES).with_dma(dma_channel.configure(
false, false,
&mut descriptors, &mut tx_descriptors,
&mut rx_descriptors, &mut rx_descriptors,
DmaPriority::Priority0, DmaPriority::Priority0,
)); ));
let keytext = buffer1(); let keytext = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let plaintext = buffer2(); input.copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
plaintext.copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
keytext.copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
// create an array with aes128 key size
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
// create an array with aes block size
let mut block_buf = [0_u8; 16];
block_buf[..plaintext.len()].copy_from_slice(plaintext);
let hw_encrypted = buffer3();
let pre_hw_encrypt = cycles(); let pre_hw_encrypt = cycles();
let transfer = aes let transfer = aes
.process( .process(
plaintext, &input,
hw_encrypted, &mut output,
Mode::Encryption128, Mode::Encryption128,
CipherMode::Ecb, CipherMode::Ecb,
keybuf, keytext,
) )
.unwrap(); .unwrap();
let (hw_encrypted, plaintext, aes) = transfer.wait().unwrap(); transfer.wait().unwrap();
let post_hw_encrypt = cycles(); let post_hw_encrypt = cycles();
println!( println!(
"it took {} cycles for hw encrypt", "it took {} cycles for hw encrypt",
post_hw_encrypt - pre_hw_encrypt post_hw_encrypt - pre_hw_encrypt
); );
let keytext = buffer4(); let mut hw_encrypted = [0u8; 16];
plaintext.copy_from_slice(hw_encrypted); (&mut hw_encrypted[..]).copy_from_slice(output);
keytext.copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut keybuf = [0_u8; 16]; input.copy_from_slice(output);
keybuf[..keytext.len()].copy_from_slice(keytext);
let hw_decrypted = buffer5();
let pre_hw_decrypt = cycles(); let pre_hw_decrypt = cycles();
let transfer = aes let transfer = aes
.process( .process(
plaintext, &input,
hw_decrypted, &mut output,
Mode::Decryption128, Mode::Decryption128,
CipherMode::Ecb, CipherMode::Ecb,
keybuf, keytext,
) )
.unwrap(); .unwrap();
let (hw_decrypted, _, _) = transfer.wait().unwrap(); transfer.wait().unwrap();
let post_hw_decrypt = cycles(); let post_hw_decrypt = cycles();
println!( println!(
"it took {} cycles for hw decrypt", "it took {} cycles for hw decrypt",
post_hw_decrypt - pre_hw_decrypt post_hw_decrypt - pre_hw_decrypt
); );
let key = GenericArray::from(keybuf); let mut hw_decrypted = [0u8; 16];
(&mut hw_decrypted[..]).copy_from_slice(output);
// create an array with aes block size
let mut block_buf = [0_u8; 16];
block_buf[..].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let key = GenericArray::from(keytext);
let mut block = GenericArray::from(block_buf); let mut block = GenericArray::from(block_buf);
let cipher = Aes128SW::new(&key); let cipher = Aes128SW::new(&key);
let pre_sw_encrypt = cycles(); let pre_sw_encrypt = cycles();
@ -123,31 +116,6 @@ fn main() -> ! {
loop {} loop {}
} }
fn buffer1() -> &'static mut [u8; 16] {
static mut BUFFER: [u8; 16] = [0u8; 16];
unsafe { &mut BUFFER }
}
fn buffer2() -> &'static mut [u8; 16] {
static mut BUFFER: [u8; 16] = [0u8; 16];
unsafe { &mut BUFFER }
}
fn buffer3() -> &'static mut [u8; 16] {
static mut BUFFER: [u8; 16] = [0u8; 16];
unsafe { &mut BUFFER }
}
fn buffer4() -> &'static mut [u8; 16] {
static mut BUFFER: [u8; 16] = [0u8; 16];
unsafe { &mut BUFFER }
}
fn buffer5() -> &'static mut [u8; 16] {
static mut BUFFER: [u8; 16] = [0u8; 16];
unsafe { &mut BUFFER }
}
fn eq(slice1: &[u8; 16], slice2: &[u8; 16]) -> bool { fn eq(slice1: &[u8; 16], slice2: &[u8; 16]) -> bool {
slice1.iter().zip(slice2.iter()).all(|(a, b)| a == b) slice1.iter().zip(slice2.iter()).all(|(a, b)| a == b)
} }

View File

@ -7,7 +7,7 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use core::cell::RefCell; use core::{cell::RefCell, ptr::addr_of_mut};
use critical_section::Mutex; use critical_section::Mutex;
use esp_backtrace as _; use esp_backtrace as _;
@ -39,8 +39,8 @@ fn main() -> ! {
static mut _stack_end: u32; static mut _stack_end: u32;
} }
let stack_top = unsafe { &mut _stack_start } as *mut _ as u32; let stack_top = unsafe { addr_of_mut!(_stack_start) } as *mut _ as u32;
let stack_bottom = unsafe { &mut _stack_end } as *mut _ as u32; let stack_bottom = unsafe { addr_of_mut!(_stack_end) } as *mut _ as u32;
let size = 4096; let size = 4096;
} else { } else {

View File

@ -26,7 +26,7 @@ use embassy_time::{Duration, Timer};
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
clock::ClockControl, clock::ClockControl,
dma::{DmaPriority, *}, dma::*,
dma_descriptors, dma_descriptors,
embassy::{self}, embassy::{self},
peripherals::Peripherals, peripherals::Peripherals,

View File

@ -42,7 +42,7 @@ fn main() -> ! {
#[cfg(not(any(feature = "esp32", feature = "esp32s2")))] #[cfg(not(any(feature = "esp32", feature = "esp32s2")))]
let dma_channel = dma.channel0; let dma_channel = dma.channel0;
let (_, mut tx_descriptors, rx_buffer, mut rx_descriptors) = dma_buffers!(0, 4 * 4092); let (_, mut tx_descriptors, mut rx_buffer, mut rx_descriptors) = dma_buffers!(0, 4 * 4092);
// Here we test that the type is // Here we test that the type is
// 1) reasonably simple (or at least this will flag changes that may make it // 1) reasonably simple (or at least this will flag changes that may make it
@ -67,16 +67,14 @@ fn main() -> ! {
i2s.with_mclk(io.pins.gpio0); i2s.with_mclk(io.pins.gpio0);
} }
let i2s_rx = i2s let mut i2s_rx = i2s
.i2s_rx .i2s_rx
.with_bclk(io.pins.gpio2) .with_bclk(io.pins.gpio2)
.with_ws(io.pins.gpio4) .with_ws(io.pins.gpio4)
.with_din(io.pins.gpio5) .with_din(io.pins.gpio5)
.build(); .build();
let buffer = rx_buffer; let mut transfer = i2s_rx.read_dma_circular(&mut rx_buffer).unwrap();
let mut transfer = i2s_rx.read_dma_circular(buffer).unwrap();
println!("Started transfer"); println!("Started transfer");
loop { loop {

View File

@ -80,7 +80,7 @@ fn main() -> ! {
&clocks, &clocks,
); );
let i2s_tx = i2s let mut i2s_tx = i2s
.i2s_tx .i2s_tx
.with_bclk(io.pins.gpio2) .with_bclk(io.pins.gpio2)
.with_ws(io.pins.gpio4) .with_ws(io.pins.gpio4)
@ -90,10 +90,9 @@ fn main() -> ! {
let data = let data =
unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) }; unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) };
let buffer = tx_buffer;
let mut idx = 0; let mut idx = 0;
for i in 0..usize::min(data.len(), buffer.len()) { for i in 0..usize::min(data.len(), tx_buffer.len()) {
buffer[i] = data[idx]; tx_buffer[i] = data[idx];
idx += 1; idx += 1;
@ -103,7 +102,7 @@ fn main() -> ! {
} }
let mut filler = [0u8; 10000]; let mut filler = [0u8; 10000];
let mut transfer = i2s_tx.write_dma_circular(buffer).unwrap(); let mut transfer = i2s_tx.write_dma_circular(&tx_buffer).unwrap();
loop { loop {
let avail = transfer.available(); let avail = transfer.available();

View File

@ -213,7 +213,7 @@ fn main() -> ! {
let total_pixels = width as usize * height as usize; let total_pixels = width as usize * height as usize;
let total_bytes = total_pixels * 2; let total_bytes = total_pixels * 2;
let mut buffer = tx_buffer; let buffer = tx_buffer;
for color in [RED, BLUE].iter().cycle() { for color in [RED, BLUE].iter().cycle() {
let color = color.to_be_bytes(); let color = color.to_be_bytes();
@ -223,20 +223,20 @@ fn main() -> ! {
let mut bytes_left_to_write = total_bytes; let mut bytes_left_to_write = total_bytes;
let transfer = i8080.send_dma(0x2C, 0, buffer).unwrap(); let transfer = i8080.send_dma(0x2C, 0, &buffer).unwrap();
(buffer, i8080) = transfer.wait().unwrap(); transfer.wait().unwrap();
bytes_left_to_write -= buffer.len(); bytes_left_to_write -= buffer.len();
while bytes_left_to_write >= buffer.len() { while bytes_left_to_write >= buffer.len() {
let transfer = i8080.send_dma(0x3C, 0, buffer).unwrap(); let transfer = i8080.send_dma(0x3C, 0, &buffer).unwrap();
(buffer, i8080) = transfer.wait().unwrap(); transfer.wait().unwrap();
bytes_left_to_write -= buffer.len(); bytes_left_to_write -= buffer.len();
} }
if bytes_left_to_write > 0 { if bytes_left_to_write > 0 {
let transfer = i8080.send_dma(0x3C, 0, buffer).unwrap(); let transfer = i8080.send_dma(0x3C, 0, &buffer).unwrap();
(buffer, i8080) = transfer.wait().unwrap(); transfer.wait().unwrap();
} }
delay.delay_ms(1_000u32); delay.delay_ms(1_000u32);

View File

@ -60,11 +60,8 @@ fn main() -> ! {
let mut delay = Delay::new(&clocks); let mut delay = Delay::new(&clocks);
loop { loop {
let transfer = parl_io_rx.read_dma(buffer).unwrap(); let transfer = parl_io_rx.read_dma(&mut buffer).unwrap();
transfer.wait().unwrap();
// the buffer and driver is moved into the transfer and we can get it back via
// `wait`
(buffer, parl_io_rx) = transfer.wait().unwrap();
println!("Received: {:02x?} ...", &buffer[..30]); println!("Received: {:02x?} ...", &buffer[..30]);
delay.delay_ms(500u32); delay.delay_ms(500u32);

View File

@ -75,7 +75,7 @@ fn main() -> ! {
) )
.unwrap(); .unwrap();
let mut buffer = tx_buffer; let buffer = tx_buffer;
for i in 0..buffer.len() { for i in 0..buffer.len() {
buffer[i] = (i % 255) as u8; buffer[i] = (i % 255) as u8;
} }
@ -83,11 +83,8 @@ fn main() -> ! {
let mut delay = Delay::new(&clocks); let mut delay = Delay::new(&clocks);
loop { loop {
let transfer = parl_io_tx.write_dma(buffer).unwrap(); let transfer = parl_io_tx.write_dma(&buffer).unwrap();
transfer.wait().unwrap();
// the buffer and driver is moved into the transfer and we can get it back via
// `wait`
(buffer, parl_io_tx) = transfer.wait().unwrap();
println!("Transferred {} bytes", buffer.len()); println!("Transferred {} bytes", buffer.len());
delay.delay_ms(500u32); delay.delay_ms(500u32);

View File

@ -96,7 +96,7 @@ fn main() -> ! {
let mut delay = Delay::new(&clocks); let mut delay = Delay::new(&clocks);
// DMA buffer require a static life-time // DMA buffer require a static life-time
let mut zero_buf = zero_buffer(); let (zero_buf, _, _, _) = dma_buffers!(0);
let send = tx_buffer; let send = tx_buffer;
let mut receive = rx_buffer; let mut receive = rx_buffer;
@ -107,10 +107,10 @@ fn main() -> ! {
Command::Command8(0x06, SpiDataMode::Single), Command::Command8(0x06, SpiDataMode::Single),
Address::None, Address::None,
0, 0,
zero_buf, &zero_buf,
) )
.unwrap(); .unwrap();
(zero_buf, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
delay.delay_ms(250u32); delay.delay_ms(250u32);
// erase sector // erase sector
@ -120,10 +120,10 @@ fn main() -> ! {
Command::Command8(0x20, SpiDataMode::Single), Command::Command8(0x20, SpiDataMode::Single),
Address::Address24(0x000000, SpiDataMode::Single), Address::Address24(0x000000, SpiDataMode::Single),
0, 0,
zero_buf, &zero_buf,
) )
.unwrap(); .unwrap();
(zero_buf, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
delay.delay_ms(250u32); delay.delay_ms(250u32);
// write enable // write enable
@ -133,10 +133,10 @@ fn main() -> ! {
Command::Command8(0x06, SpiDataMode::Single), Command::Command8(0x06, SpiDataMode::Single),
Address::None, Address::None,
0, 0,
zero_buf, &zero_buf,
) )
.unwrap(); .unwrap();
(_, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
delay.delay_ms(250u32); delay.delay_ms(250u32);
// write data / program page // write data / program page
@ -148,10 +148,10 @@ fn main() -> ! {
Command::Command8(0x32, SpiDataMode::Single), Command::Command8(0x32, SpiDataMode::Single),
Address::Address24(0x000000, SpiDataMode::Single), Address::Address24(0x000000, SpiDataMode::Single),
0, 0,
send, &send,
) )
.unwrap(); .unwrap();
(_, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
delay.delay_ms(250u32); delay.delay_ms(250u32);
loop { loop {
@ -162,14 +162,14 @@ fn main() -> ! {
Command::Command8(0xeb, SpiDataMode::Single), Command::Command8(0xeb, SpiDataMode::Single),
Address::Address32(0x000000 << 8, SpiDataMode::Quad), Address::Address32(0x000000 << 8, SpiDataMode::Quad),
4, 4,
receive, &mut receive,
) )
.unwrap(); .unwrap();
// here we could do something else while DMA transfer is in progress // here we could do something else while DMA transfer is in progress
// the buffers and spi is moved into the transfer and we can get it back via // the buffers and spi is moved into the transfer and we can get it back via
// `wait` // `wait`
(receive, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
println!("{:x?}", &receive); println!("{:x?}", &receive);
for b in &mut receive.iter() { for b in &mut receive.iter() {
@ -184,8 +184,3 @@ fn main() -> ! {
delay.delay_ms(250u32); delay.delay_ms(250u32);
} }
} }
fn zero_buffer() -> &'static mut [u8; 0] {
static mut BUFFER: [u8; 0] = [0u8; 0];
unsafe { &mut BUFFER }
}

View File

@ -80,7 +80,7 @@ fn main() -> ! {
send[send.len() - 1] = i; send[send.len() - 1] = i;
i = i.wrapping_add(1); i = i.wrapping_add(1);
let transfer = spi.dma_transfer(send, receive).unwrap(); let transfer = spi.dma_transfer(&mut send, &mut receive).unwrap();
// here we could do something else while DMA transfer is in progress // here we could do something else while DMA transfer is in progress
let mut n = 0; let mut n = 0;
// Check is_done until the transfer is almost done (32000 bytes at 100kHz is // Check is_done until the transfer is almost done (32000 bytes at 100kHz is
@ -89,9 +89,8 @@ fn main() -> ! {
delay.delay_ms(250u32); delay.delay_ms(250u32);
n += 1; n += 1;
} }
// the buffers and spi is moved into the transfer and we can get it back via
// `wait` transfer.wait().unwrap();
(receive, send, spi) = transfer.wait().unwrap();
println!( println!(
"{:x?} .. {:x?}", "{:x?} .. {:x?}",
&receive[..10], &receive[..10],

View File

@ -107,7 +107,9 @@ fn main() -> ! {
slave_receive.fill(0xff); slave_receive.fill(0xff);
i = i.wrapping_add(1); i = i.wrapping_add(1);
let transfer = spi.dma_transfer(slave_send, slave_receive).unwrap(); let transfer = spi
.dma_transfer(&mut slave_send, &mut slave_receive)
.unwrap();
// Bit-bang out the contents of master_send and read into master_receive // Bit-bang out the contents of master_send and read into master_receive
// as quickly as manageable. MSB first. Mode 0, so sampled on the rising // as quickly as manageable. MSB first. Mode 0, so sampled on the rising
// edge and set on the falling edge. // edge and set on the falling edge.
@ -138,7 +140,7 @@ fn main() -> ! {
master_sclk.set_low().unwrap(); master_sclk.set_low().unwrap();
// the buffers and spi is moved into the transfer and we can get it back via // the buffers and spi is moved into the transfer and we can get it back via
// `wait` // `wait`
(slave_receive, slave_send, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
println!( println!(
"slave got {:x?} .. {:x?}, master got {:x?} .. {:x?}", "slave got {:x?} .. {:x?}, master got {:x?} .. {:x?}",
&slave_receive[..10], &slave_receive[..10],
@ -150,7 +152,7 @@ fn main() -> ! {
delay.delay_ms(250u32); delay.delay_ms(250u32);
slave_receive.fill(0xff); slave_receive.fill(0xff);
let transfer = spi.dma_read(slave_receive).unwrap(); let transfer = spi.dma_read(&mut slave_receive).unwrap();
master_cs.set_high().unwrap(); master_cs.set_high().unwrap();
master_cs.set_low().unwrap(); master_cs.set_low().unwrap();
@ -168,7 +170,7 @@ fn main() -> ! {
} }
} }
master_cs.set_high().unwrap(); master_cs.set_high().unwrap();
(slave_receive, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
println!( println!(
"slave got {:x?} .. {:x?}", "slave got {:x?} .. {:x?}",
&slave_receive[..10], &slave_receive[..10],
@ -176,7 +178,7 @@ fn main() -> ! {
); );
delay.delay_ms(250u32); delay.delay_ms(250u32);
let transfer = spi.dma_write(slave_send).unwrap(); let transfer = spi.dma_write(&mut slave_send).unwrap();
master_receive.fill(0); master_receive.fill(0);
@ -194,7 +196,7 @@ fn main() -> ! {
master_receive[j] = rb; master_receive[j] = rb;
} }
master_cs.set_high().unwrap(); master_cs.set_high().unwrap();
(slave_send, spi) = transfer.wait().unwrap(); transfer.wait().unwrap();
println!( println!(
"master got {:x?} .. {:x?}", "master got {:x?} .. {:x?}",