De-duplicate DMA transfer implementations (#1550)

* De-duplicate DMA transfer implementations

* CHANGELOG.md

* Renaming

* Fix

* Get rid of the lambda

* Clippy
This commit is contained in:
Björn Quentin 2024-05-15 18:42:35 +02:00 committed by GitHub
parent 8a1df42309
commit 9edd098da5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 625 additions and 768 deletions

View File

@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Software interrupt 3 is now used instead of software interrupt 0 on the thread aware executor on multicore systems (#1485)
- Timer abstraction: refactor `systimer` and `timer` modules into a common `timer` module (#1527)
- Refactoring of GPIO module, have drivers for Input,Output,OutputOpenDrain, all drivers setup their GPIOs correctly (#1542)
- DMA transactions are now found in the `dma` module (#1550)
### Removed

View File

@ -276,12 +276,12 @@ pub mod dma {
use crate::{
aes::{Key, Mode},
dma::{
dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
AesPeripheral,
Channel,
ChannelTypes,
DmaError,
DmaPeripheral,
DmaTransferRxTx,
DmaTransferTxRx,
RxPrivate,
TxPrivate,
},
@ -336,61 +336,6 @@ pub mod dma {
}
}
/// An in-progress DMA transfer
#[must_use]
pub struct AesDmaTransferRxTx<'t, 'd, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
aes_dma: &'t mut AesDma<'d, C>,
}
impl<'t, 'd, C> DmaTransferRxTx for AesDmaTransferRxTx<'t, 'd, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
while self.aes_dma.aes.aes.state().read().state().bits() != 2 // DMA status DONE == 2
&& !self.aes_dma.channel.tx.is_done()
{
// wait until done
}
self.aes_dma.finish_transform();
if self.aes_dma.channel.rx.has_error() || self.aes_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
let ch = &self.aes_dma.channel;
ch.tx.is_done() && ch.rx.is_done()
}
}
impl<'t, 'd, C> Drop for AesDmaTransferRxTx<'t, 'd, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
fn drop(&mut self) {
self.aes_dma
.aes
.aes
.dma_exit()
.write(|w| w.dma_exit().set_bit());
}
}
impl<'d, C> core::fmt::Debug for AesDma<'d, C>
where
C: ChannelTypes,
@ -401,6 +346,50 @@ pub mod dma {
}
}
impl<'d, C> DmaSupport for AesDma<'d, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
while self.aes.aes.state().read().state().bits() != 2 // DMA status DONE == 2
&& !self.channel.tx.is_done()
{
// wait until done
}
self.finish_transform();
}
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
impl<'d, C> DmaSupportTx for AesDma<'d, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
type TX = C::Tx<'d>;
fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx
}
}
impl<'d, C> DmaSupportRx for AesDma<'d, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
type RX = C::Rx<'d>;
fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx
}
}
impl<'d, C> AesDma<'d, C>
where
C: ChannelTypes,
@ -427,7 +416,7 @@ pub mod dma {
/// Perform a DMA transfer.
///
/// This will return a [AesDmaTransferRxTx] owning the buffer(s) and the
/// This will return a [AesDmaTransfer] owning the buffer(s) and the
/// AES instance. The maximum amount of data to be sent/received
/// is 32736 bytes.
pub fn process<'t, K, TXBUF, RXBUF>(
@ -437,7 +426,7 @@ pub mod dma {
mode: Mode,
cipher_mode: CipherMode,
key: K,
) -> Result<AesDmaTransferRxTx<'t, 'd, C>, crate::dma::DmaError>
) -> Result<DmaTransferTxRx<Self>, crate::dma::DmaError>
where
K: Into<Key>,
TXBUF: ReadBuffer<Word = u8>,
@ -456,7 +445,7 @@ pub mod dma {
key.into(),
)?;
Ok(AesDmaTransferRxTx { aes_dma: self })
Ok(DmaTransferTxRx::new(self))
}
#[allow(clippy::too_many_arguments)]

View File

@ -1494,24 +1494,264 @@ where
}
}
/// Trait to be implemented for an in progress dma transfer.
#[allow(drop_bounds)]
#[doc(hidden)]
pub trait DmaTransfer: Drop {
/// Wait for the transfer to finish.
fn wait(self) -> Result<(), DmaError>;
/// Check if the transfer is finished.
fn is_done(&self) -> bool;
pub(crate) mod dma_private {
use super::*;
pub trait DmaSupport {
/// Wait until the transfer is done.
///
/// Depending on the peripheral this might include checking the DMA
/// channel and/or the peripheral.
///
/// After this all data should be processed by the peripheral - i.e. the
/// peripheral should have processed it's FIFO(s)
fn peripheral_wait_dma(&mut self, is_tx: bool, is_rx: bool);
/// Only used by circular DMA transfers
fn peripheral_dma_stop(&mut self);
}
pub trait DmaSupportTx: DmaSupport {
type TX: Tx;
fn tx(&mut self) -> &mut Self::TX;
}
pub trait DmaSupportRx: DmaSupport {
type RX: Rx;
fn rx(&mut self) -> &mut Self::RX;
}
}
/// Trait to be implemented for an in progress dma transfer.
#[allow(clippy::type_complexity, drop_bounds)]
#[doc(hidden)]
pub trait DmaTransferRxTx: Drop {
/// DMA transaction for TX only transfers
#[non_exhaustive]
#[must_use]
pub struct DmaTransferTx<'a, I>
where
I: dma_private::DmaSupportTx,
{
instance: &'a mut I,
}
impl<'a, I> DmaTransferTx<'a, I>
where
I: dma_private::DmaSupportTx,
{
pub(crate) fn new(instance: &'a mut I) -> Self {
Self { instance }
}
/// Wait for the transfer to finish.
fn wait(self) -> Result<(), DmaError>;
pub fn wait(self) -> Result<(), DmaError> {
self.instance.peripheral_wait_dma(true, false);
if self.instance.tx().has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the transfer is finished.
fn is_done(&self) -> bool;
pub fn is_done(&mut self) -> bool {
self.instance.tx().is_done()
}
}
impl<'a, I> Drop for DmaTransferTx<'a, I>
where
I: dma_private::DmaSupportTx,
{
fn drop(&mut self) {
self.instance.peripheral_wait_dma(true, false);
}
}
/// DMA transaction for RX only transfers
#[non_exhaustive]
#[must_use]
pub struct DmaTransferRx<'a, I>
where
I: dma_private::DmaSupportRx,
{
instance: &'a mut I,
}
impl<'a, I> DmaTransferRx<'a, I>
where
I: dma_private::DmaSupportRx,
{
pub(crate) fn new(instance: &'a mut I) -> Self {
Self { instance }
}
/// Wait for the transfer to finish.
pub fn wait(self) -> Result<(), DmaError> {
self.instance.peripheral_wait_dma(false, true);
if self.instance.rx().has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the transfer is finished.
pub fn is_done(&mut self) -> bool {
self.instance.rx().is_done()
}
}
impl<'a, I> Drop for DmaTransferRx<'a, I>
where
I: dma_private::DmaSupportRx,
{
fn drop(&mut self) {
self.instance.peripheral_wait_dma(false, true);
}
}
/// DMA transaction for TX+RX transfers
#[non_exhaustive]
#[must_use]
pub struct DmaTransferTxRx<'a, I>
where
I: dma_private::DmaSupportTx + dma_private::DmaSupportRx,
{
instance: &'a mut I,
}
impl<'a, I> DmaTransferTxRx<'a, I>
where
I: dma_private::DmaSupportTx + dma_private::DmaSupportRx,
{
pub(crate) fn new(instance: &'a mut I) -> Self {
Self { instance }
}
/// Wait for the transfer to finish.
pub fn wait(self) -> Result<(), DmaError> {
self.instance.peripheral_wait_dma(true, true);
if self.instance.tx().has_error() || self.instance.rx().has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the transfer is finished.
pub fn is_done(&mut self) -> bool {
self.instance.tx().is_done() && self.instance.rx().is_done()
}
}
impl<'a, I> Drop for DmaTransferTxRx<'a, I>
where
I: dma_private::DmaSupportTx + dma_private::DmaSupportRx,
{
fn drop(&mut self) {
self.instance.peripheral_wait_dma(true, true);
}
}
/// DMA transaction for TX only circular transfers
#[non_exhaustive]
#[must_use]
pub struct DmaTransferTxCircular<'a, I>
where
I: dma_private::DmaSupportTx,
{
instance: &'a mut I,
}
impl<'a, I> DmaTransferTxCircular<'a, I>
where
I: dma_private::DmaSupportTx,
{
#[allow(unused)] // currently used by peripherals not available on all chips
pub(crate) fn new(instance: &'a mut I) -> Self {
Self { instance }
}
/// Amount of bytes which can be pushed.
pub fn available(&mut self) -> usize {
self.instance.tx().available()
}
/// Push bytes into the DMA buffer.
pub fn push(&mut self, data: &[u8]) -> Result<usize, DmaError> {
self.instance.tx().push(data)
}
/// Push bytes into the DMA buffer via the given closure.
/// The closure *must* return the actual number of bytes written.
/// The closure *might* get called with a slice which is smaller than the
/// total available buffer.
pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> Result<usize, DmaError> {
self.instance.tx().push_with(f)
}
/// Stop the DMA transfer
#[allow(clippy::type_complexity)]
pub fn stop(self) -> Result<(), DmaError> {
self.instance.peripheral_dma_stop();
if self.instance.tx().has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
}
impl<'a, I> Drop for DmaTransferTxCircular<'a, I>
where
I: dma_private::DmaSupportTx,
{
fn drop(&mut self) {
self.instance.peripheral_dma_stop();
}
}
/// DMA transaction for RX only circular transfers
#[non_exhaustive]
#[must_use]
pub struct DmaTransferRxCircular<'a, I>
where
I: dma_private::DmaSupportRx,
{
instance: &'a mut I,
}
impl<'a, I> DmaTransferRxCircular<'a, I>
where
I: dma_private::DmaSupportRx,
{
#[allow(unused)] // currently used by peripherals not available on all chips
pub(crate) fn new(instance: &'a mut I) -> Self {
Self { instance }
}
/// Amount of bytes which can be popped
pub fn available(&mut self) -> usize {
self.instance.rx().available()
}
/// Get available data
pub fn pop(&mut self, data: &mut [u8]) -> Result<usize, DmaError> {
self.instance.rx().pop(data)
}
}
impl<'a, I> Drop for DmaTransferRxCircular<'a, I>
where
I: dma_private::DmaSupportRx,
{
fn drop(&mut self) {
self.instance.peripheral_dma_stop();
}
}
#[cfg(feature = "async")]

View File

@ -76,10 +76,14 @@ use crate::dma::I2s1Peripheral;
use crate::{
clock::Clocks,
dma::{
dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
Channel,
ChannelTypes,
DmaError,
DmaTransfer,
DmaTransferRx,
DmaTransferRxCircular,
DmaTransferTx,
DmaTransferTxCircular,
I2s0Peripheral,
I2sPeripheral,
RxPrivate,
@ -210,93 +214,6 @@ impl DataFormat {
}
}
/// An in-progress DMA write transfer.
#[must_use]
pub struct I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
i2s_tx: &'t mut I2sTx<'d, T, CH, DmaMode>,
}
impl<'t, 'd, T, CH, DmaMode> I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
/// Amount of bytes which can be pushed.
/// Only useful for circular DMA transfers
pub fn available(&mut self) -> usize {
self.i2s_tx.tx_channel.available()
}
/// Push bytes into the DMA buffer.
/// Only useful for circular DMA transfers
pub fn push(&mut self, data: &[u8]) -> Result<usize, Error> {
Ok(self.i2s_tx.tx_channel.push(data)?)
}
/// Push bytes into the DMA buffer via the given closure.
/// The closure *must* return the actual number of bytes written.
/// The closure *might* get called with a slice which is smaller than the
/// total available buffer. Only useful for circular DMA transfers
pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> Result<usize, Error> {
Ok(self.i2s_tx.tx_channel.push_with(f)?)
}
/// Stop for the DMA transfer and return the buffer and the
/// I2sTx instance.
#[allow(clippy::type_complexity)]
pub fn stop(self) -> Result<(), DmaError> {
T::tx_stop();
if self.i2s_tx.tx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
}
impl<'t, 'd, T, CH, DmaMode> DmaTransfer for I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
self.i2s_tx.wait_tx_dma_done().ok();
if self.i2s_tx.tx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
self.i2s_tx.tx_channel.is_done()
}
}
impl<'t, 'd, T, CH, DmaMode> Drop for I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
fn drop(&mut self) {
self.i2s_tx.wait_tx_dma_done().ok();
}
}
/// Blocking I2s Write
pub trait I2sWrite<W> {
fn write(&mut self, words: &[W]) -> Result<(), Error>;
@ -308,14 +225,12 @@ where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
Self: DmaSupportTx + Sized,
{
/// Write I2S.
/// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA
/// transfer
fn write_dma<'t>(
&'t mut self,
words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
fn write_dma<'t>(&'t mut self, words: &'t TXBUF) -> Result<DmaTransferTx<Self>, Error>
where
TXBUF: ReadBuffer<Word = u8>;
@ -324,90 +239,11 @@ where
fn write_dma_circular<'t>(
&'t mut self,
words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
) -> Result<DmaTransferTxCircular<Self>, Error>
where
TXBUF: ReadBuffer<Word = u8>;
}
/// An in-progress DMA read transfer.
#[must_use]
pub struct I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
i2s_rx: &'t mut I2sRx<'d, T, CH, DmaMode>,
}
impl<'t, 'd, T, CH, DmaMode> I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
/// Amount of bytes which can be popped
pub fn available(&mut self) -> usize {
self.i2s_rx.rx_channel.available()
}
pub fn pop(&mut self, data: &mut [u8]) -> Result<usize, Error> {
Ok(self.i2s_rx.rx_channel.pop(data)?)
}
/// Wait for the DMA transfer to complete.
/// Length of the received data is returned
#[allow(clippy::type_complexity)]
pub fn wait_receive(self, dst: &mut [u8]) -> Result<usize, (DmaError, usize)> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
self.i2s_rx.wait_rx_dma_done().ok();
let len = self.i2s_rx.rx_channel.drain_buffer(dst).unwrap();
if self.i2s_rx.rx_channel.has_error() {
Err((DmaError::DescriptorError, len))
} else {
Ok(len)
}
}
}
impl<'t, 'd, T, CH, DmaMode> DmaTransfer for I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
self.i2s_rx.wait_rx_dma_done().ok();
if self.i2s_rx.rx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
self.i2s_rx.rx_channel.is_done()
}
}
impl<'t, T, CH, DmaMode> Drop for I2sReadDmaTransfer<'t, '_, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
fn drop(&mut self) {
self.i2s_rx.wait_rx_dma_done().ok();
}
}
/// Blocking I2S Read
pub trait I2sRead<W> {
fn read(&mut self, words: &mut [W]) -> Result<(), Error>;
@ -419,14 +255,12 @@ where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
Self: DmaSupportRx + Sized,
{
/// Read I2S.
/// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
/// transfer
fn read_dma<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
fn read_dma<'t>(&'t mut self, words: &'t mut RXBUF) -> Result<DmaTransferRx<Self>, Error>
where
RXBUF: WriteBuffer<Word = u8>;
@ -436,7 +270,7 @@ where
fn read_dma_circular<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
) -> Result<DmaTransferRxCircular<Self>, Error>
where
RXBUF: WriteBuffer<Word = u8>;
}
@ -606,6 +440,34 @@ where
}
}
impl<'d, T, CH, DmaMode> DmaSupport for I2sTx<'d, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
self.wait_tx_dma_done().ok();
}
fn peripheral_dma_stop(&mut self) {
T::tx_stop();
}
}
impl<'d, T, CH, DmaMode> DmaSupportTx for I2sTx<'d, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
type TX = CH::Tx<'d>;
fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel
}
}
impl<'d, T, CH, DmaMode> I2sTx<'d, T, CH, DmaMode>
where
T: RegisterAccess,
@ -648,7 +510,7 @@ where
&'t mut self,
words: &'t TXBUF,
circular: bool,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
) -> Result<(), Error>
where
TXBUF: ReadBuffer<Word = u8>,
DmaMode: Mode,
@ -670,7 +532,7 @@ where
// start: set I2S_TX_START
T::tx_start();
Ok(I2sWriteDmaTransfer { i2s_tx: self })
Ok(())
}
fn wait_tx_dma_done(&self) -> Result<(), Error> {
@ -704,24 +566,23 @@ where
CH: ChannelTypes,
DmaMode: Mode,
{
fn write_dma<'t>(
&'t mut self,
words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
fn write_dma<'t>(&'t mut self, words: &'t TXBUF) -> Result<DmaTransferTx<Self>, Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
self.start_tx_transfer(words, false)
self.start_tx_transfer(words, false)?;
Ok(DmaTransferTx::new(self))
}
fn write_dma_circular<'t>(
&'t mut self,
words: &'t TXBUF,
) -> Result<I2sWriteDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
) -> Result<DmaTransferTxCircular<Self>, Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
self.start_tx_transfer(words, true)
self.start_tx_transfer(words, true)?;
Ok(DmaTransferTxCircular::new(self))
}
}
@ -748,6 +609,34 @@ where
}
}
impl<'d, T, CH, DmaMode> DmaSupport for I2sRx<'d, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
T::wait_for_rx_done();
}
fn peripheral_dma_stop(&mut self) {
T::reset_rx();
}
}
impl<'d, T, CH, DmaMode> DmaSupportRx for I2sRx<'d, T, CH, DmaMode>
where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
{
type RX = CH::Rx<'d>;
fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel
}
}
impl<'d, T, CH, DmaMode> I2sRx<'d, T, CH, DmaMode>
where
T: RegisterAccess,
@ -792,7 +681,7 @@ where
&'t mut self,
words: &'t mut RXBUF,
circular: bool,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
) -> Result<(), Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
@ -818,13 +707,6 @@ where
// start: set I2S_RX_START
T::rx_start(len);
Ok(I2sReadDmaTransfer { i2s_rx: self })
}
fn wait_rx_dma_done(&self) -> Result<(), Error> {
T::wait_for_rx_done();
Ok(())
}
}
@ -855,25 +737,25 @@ where
T: RegisterAccess,
CH: ChannelTypes,
DmaMode: Mode,
Self: DmaSupportRx + Sized,
{
fn read_dma<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
fn read_dma<'t>(&'t mut self, words: &'t mut RXBUF) -> Result<DmaTransferRx<Self>, Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
self.start_rx_transfer(words, false)
self.start_rx_transfer(words, false)?;
Ok(DmaTransferRx::new(self))
}
fn read_dma_circular<'t>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<I2sReadDmaTransfer<'t, 'd, T, CH, DmaMode>, Error>
) -> Result<DmaTransferRxCircular<Self>, Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
self.start_rx_transfer(words, true)
self.start_rx_transfer(words, true)?;
Ok(DmaTransferRxCircular::new(self))
}
}

View File

@ -42,11 +42,13 @@ use fugit::HertzU32;
use crate::{
clock::Clocks,
dma::{
dma_private::{DmaSupport, DmaSupportRx},
ChannelRx,
ChannelTypes,
DmaError,
DmaPeripheral,
DmaTransfer,
DmaTransferRx,
DmaTransferRxCircular,
LcdCamPeripheral,
RegisterAccess,
Rx,
@ -54,7 +56,6 @@ use crate::{
RxPrivate,
},
gpio::{InputPin, InputSignal, OutputPin, OutputSignal},
i2s::Error,
lcd_cam::{cam::private::RxPins, private::calculate_clkm, BitOrder, ByteOrder},
peripheral::{Peripheral, PeripheralRef},
peripherals::LCD_CAM,
@ -177,6 +178,31 @@ where
}
}
impl<'d, RX: Rx> DmaSupport for Camera<'d, RX> {
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
while !
// Wait for IN_SUC_EOF (i.e. VSYNC)
self.rx_channel.is_done() ||
// Or for IN_DSCR_EMPTY (i.e. No more buffer space)
self.rx_channel.has_dscr_empty_error() ||
// Or for IN_DSCR_ERR (i.e. bad descriptor)
self.rx_channel.has_error()
{}
}
fn peripheral_dma_stop(&mut self) {
// TODO: Stop DMA?? self.instance.rx_channel.stop_transfer();
}
}
impl<'d, RX: Rx> DmaSupportRx for Camera<'d, RX> {
type RX = RX;
fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel
}
}
impl<'d, RX: Rx> Camera<'d, RX> {
pub fn set_byte_order(&mut self, byte_order: ByteOrder) -> &mut Self {
self.lcd_cam
@ -295,96 +321,25 @@ impl<'d, RX: Rx> Camera<'d, RX> {
pub fn read_dma<'t, RXBUF: WriteBuffer>(
&'t mut self,
buf: &'t mut RXBUF,
) -> Result<Transfer<'t, 'd, RX>, DmaError> {
) -> Result<DmaTransferRx<Self>, DmaError> {
self.reset_unit_and_fifo();
// Start DMA to receive incoming transfer.
self.start_dma(false, buf)?;
self.start_unit();
Ok(Transfer { instance: self })
Ok(DmaTransferRx::new(self))
}
pub fn read_dma_circular<'t, RXBUF: WriteBuffer>(
&'t mut self,
buf: &'t mut RXBUF,
) -> Result<Transfer<'t, 'd, RX>, DmaError> {
) -> Result<DmaTransferRxCircular<Self>, DmaError> {
self.reset_unit_and_fifo();
// Start DMA to receive incoming transfer.
self.start_dma(true, buf)?;
self.start_unit();
Ok(Transfer { instance: self })
}
}
/// An in-progress transfer
#[must_use]
pub struct Transfer<'t, 'd, RX: Rx> {
instance: &'t mut Camera<'d, RX>,
}
impl<'t, 'd, RX: Rx> Transfer<'t, 'd, RX> {
/// Amount of bytes which can be popped
pub fn available(&mut self) -> usize {
self.instance.rx_channel.available()
}
pub fn pop(&mut self, data: &mut [u8]) -> Result<usize, Error> {
Ok(self.instance.rx_channel.pop(data)?)
}
/// Wait for the DMA transfer to complete.
/// Length of the received data is returned
#[allow(clippy::type_complexity)]
pub fn wait_receive(self, dst: &mut [u8]) -> Result<usize, (DmaError, usize)> {
// Wait for DMA transfer to finish.
while !self.is_done() {}
let len = self
.instance
.rx_channel
.drain_buffer(dst)
.map_err(|e| (e, 0))?;
if self.instance.rx_channel.has_error() {
Err((DmaError::DescriptorError, len))
} else {
Ok(len)
}
}
}
impl<'t, 'd, RX: Rx> DmaTransfer for Transfer<'t, 'd, RX> {
fn wait(self) -> Result<(), DmaError> {
// Wait for DMA transfer to finish.
while !self.is_done() {}
let ch = &self.instance.rx_channel;
if ch.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
fn is_done(&self) -> bool {
let ch = &self.instance.rx_channel;
// Wait for IN_SUC_EOF (i.e. VSYNC)
ch.is_done() ||
// Or for IN_DSCR_EMPTY (i.e. No more buffer space)
ch.has_dscr_empty_error() ||
// Or for IN_DSCR_ERR (i.e. bad descriptor)
ch.has_error()
}
}
impl<'t, 'd, RX: Rx> Drop for Transfer<'t, 'd, RX> {
fn drop(&mut self) {
self.instance
.lcd_cam
.cam_ctrl1()
.modify(|_, w| w.cam_start().clear_bit());
// TODO: Stop DMA?? self.instance.rx_channel.stop_transfer();
Ok(DmaTransferRxCircular::new(self))
}
}

View File

@ -43,10 +43,12 @@ use fugit::HertzU32;
use crate::{
clock::Clocks,
dma::{
dma_private::{DmaSupport, DmaSupportTx},
ChannelTx,
ChannelTypes,
DmaError,
DmaPeripheral,
DmaTransferTx,
LcdCamPeripheral,
RegisterAccess,
Tx,
@ -229,6 +231,27 @@ where
}
}
impl<'d, TX: Tx, P: TxPins> DmaSupport for I8080<'d, TX, P> {
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
let dma_int_raw = self.lcd_cam.lc_dma_int_raw();
// Wait until LCD_TRANS_DONE is set.
while dma_int_raw.read().lcd_trans_done_int_raw().bit_is_clear() {}
self.tear_down_send();
}
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
impl<'d, TX: Tx, P: TxPins> DmaSupportTx for I8080<'d, TX, P> {
type TX = TX;
fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel
}
}
impl<'d, TX: Tx, P: TxPins> I8080<'d, TX, P>
where
P::Word: Into<u16>,
@ -301,7 +324,7 @@ where
cmd: impl Into<Command<P::Word>>,
dummy: u8,
data: &'t TXBUF,
) -> Result<Transfer<'t, 'd, TX, P>, DmaError>
) -> Result<DmaTransferTx<Self>, DmaError>
where
TXBUF: ReadBuffer<Word = P::Word>,
{
@ -311,9 +334,7 @@ where
self.start_write_bytes_dma(ptr as _, len * size_of::<P::Word>())?;
self.start_send();
Ok(Transfer {
instance: Some(self),
})
Ok(DmaTransferTx::new(self))
}
}
@ -434,54 +455,6 @@ impl<'d, TX, P> core::fmt::Debug for I8080<'d, TX, P> {
}
}
/// An in-progress transfer
#[must_use]
pub struct Transfer<'t, 'd, TX: Tx, P> {
instance: Option<&'t mut I8080<'d, TX, P>>,
}
impl<'t, 'd, TX: Tx, P> Transfer<'t, 'd, TX, P> {
#[allow(clippy::type_complexity)]
pub fn wait(mut self) -> Result<(), DmaError> {
let instance = self
.instance
.take()
.expect("instance must be available throughout object lifetime");
{
let dma_int_raw = instance.lcd_cam.lc_dma_int_raw();
// Wait until LCD_TRANS_DONE is set.
while dma_int_raw.read().lcd_trans_done_int_raw().bit_is_clear() {}
instance.tear_down_send();
}
if instance.tx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
pub fn is_done(&self) -> bool {
let int_raw = self
.instance
.as_ref()
.expect("instance must be available throughout object lifetime")
.lcd_cam
.lc_dma_int_raw();
int_raw.read().lcd_trans_done_int_raw().bit_is_set()
}
}
impl<'t, 'd, TX: Tx, P> Drop for Transfer<'t, 'd, TX, P> {
fn drop(&mut self) {
if let Some(instance) = self.instance.as_mut() {
// This will cancel the transfer.
instance.tear_down_send();
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Config {

View File

@ -88,7 +88,18 @@ use private::*;
use crate::{
clock::Clocks,
dma::{Channel, ChannelTypes, DmaError, DmaPeripheral, ParlIoPeripheral, RxPrivate, TxPrivate},
dma::{
dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
Channel,
ChannelTypes,
DmaError,
DmaPeripheral,
DmaTransferRx,
DmaTransferTx,
ParlIoPeripheral,
RxPrivate,
TxPrivate,
},
gpio::{InputPin, OutputPin},
interrupt::InterruptHandler,
peripheral::{self, Peripheral},
@ -1417,7 +1428,7 @@ where
pub fn write_dma<'t, TXBUF>(
&'t mut self,
words: &'t TXBUF,
) -> Result<DmaTransfer<'t, 'd, CH, P, CP, DM>, Error>
) -> Result<DmaTransferTx<Self>, Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
@ -1429,7 +1440,7 @@ where
self.start_write_bytes_dma(ptr, len)?;
Ok(DmaTransfer { instance: self })
Ok(DmaTransferTx::new(self))
}
fn start_write_bytes_dma(&mut self, ptr: *const u8, len: usize) -> Result<(), Error> {
@ -1459,47 +1470,37 @@ where
}
}
/// An in-progress DMA transfer.
#[must_use]
pub struct DmaTransfer<'t, 'd, C, P, CP, DM>
impl<'d, CH, P, CP, DM> DmaSupport for ParlIoTx<'d, CH, P, CP, DM>
where
C: ChannelTypes,
C::P: ParlIoPeripheral,
CH: ChannelTypes,
CH::P: ParlIoPeripheral,
P: TxPins + ConfigurePins,
CP: TxClkPin,
DM: Mode,
{
instance: &'t mut ParlIoTx<'d, C, P, CP, DM>,
}
impl<'t, 'd, C, P, CP, DM> DmaTransfer<'t, 'd, C, P, CP, DM>
where
C: ChannelTypes,
C::P: ParlIoPeripheral,
P: TxPins + ConfigurePins,
CP: TxClkPin,
DM: Mode,
{
/// Wait for the DMA transfer to complete
#[allow(clippy::type_complexity)]
pub fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
while !Instance::is_tx_eof() {}
Instance::set_tx_start(false);
if self.instance.tx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
pub fn is_done(&self) -> bool {
let ch = &self.instance.tx_channel;
ch.is_done()
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
impl<'d, CH, P, CP, DM> DmaSupportTx for ParlIoTx<'d, CH, P, CP, DM>
where
CH: ChannelTypes,
CH::P: ParlIoPeripheral,
P: TxPins + ConfigurePins,
CP: TxClkPin,
DM: Mode,
{
type TX = CH::Tx<'d>;
fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel
}
}
@ -1522,7 +1523,7 @@ where
pub fn read_dma<'t, RXBUF>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<RxDmaTransfer<'t, 'd, CH, P, CP, DM>, Error>
) -> Result<DmaTransferRx<Self>, Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
@ -1534,7 +1535,7 @@ where
Self::start_receive_bytes_dma(&mut self.rx_channel, ptr, len)?;
Ok(RxDmaTransfer { instance: self })
Ok(DmaTransferRx::new(self))
}
fn start_receive_bytes_dma(
@ -1564,55 +1565,44 @@ where
}
}
/// An in-progress DMA transfer.
pub struct RxDmaTransfer<'t, 'd, C, P, CP, DM>
impl<'d, CH, P, CP, DM> DmaSupport for ParlIoRx<'d, CH, P, CP, DM>
where
C: ChannelTypes,
C::P: ParlIoPeripheral,
CH: ChannelTypes,
CH::P: ParlIoPeripheral,
P: RxPins + ConfigurePins,
CP: RxClkPin,
DM: Mode,
{
instance: &'t mut ParlIoRx<'d, C, P, CP, DM>,
}
impl<'t, 'd, C, P, CP, DM> RxDmaTransfer<'t, 'd, C, P, CP, DM>
where
C: ChannelTypes,
C::P: ParlIoPeripheral,
P: RxPins + ConfigurePins,
CP: RxClkPin,
DM: Mode,
{
/// Wait for the DMA transfer to complete
#[allow(clippy::type_complexity)]
pub fn wait(self) -> Result<(), DmaError> {
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
loop {
if self.is_done() || self.is_eof_error() {
if self.rx_channel.is_done()
|| self.rx_channel.has_eof_error()
|| self.rx_channel.has_dscr_empty_error()
{
break;
}
}
Instance::set_rx_start(false);
if self.instance.rx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
pub fn is_done(&self) -> bool {
let ch = &self.instance.rx_channel;
ch.is_done()
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
/// Check if the DMA transfer is completed by buffer full or source EOF
/// error
pub fn is_eof_error(&self) -> bool {
let ch = &self.instance.rx_channel;
ch.has_eof_error() || ch.has_dscr_empty_error()
impl<'d, CH, P, CP, DM> DmaSupportRx for ParlIoRx<'d, CH, P, CP, DM>
where
CH: ChannelTypes,
CH::P: ParlIoPeripheral,
P: RxPins + ConfigurePins,
CP: RxClkPin,
DM: Mode,
{
type RX = CH::Rx<'d>;
fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel
}
}

View File

@ -15,11 +15,6 @@ 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,
};
#[cfg(gpio)]
pub use crate::gpio::{
InputPin as _esp_hal_gpio_InputPin,

View File

@ -837,12 +837,12 @@ pub mod dma {
use crate::dma::Spi3Peripheral;
use crate::{
dma::{
dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
Channel,
ChannelTypes,
DmaError,
DmaTransfer,
DmaTransferRxTx,
RxPrivate,
DmaTransferRx,
DmaTransferTx,
DmaTransferTxRx,
Spi2Peripheral,
SpiPeripheral,
TxPrivate,
@ -919,113 +919,6 @@ pub mod dma {
}
}
}
/// An in-progress DMA transfer
#[must_use]
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
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>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
self.spi_dma.spi.flush().ok();
if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
let ch = &self.spi_dma.channel;
ch.tx.is_done() && ch.rx.is_done()
}
}
impl<'t, 'd, T, C, M, DmaMode> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
fn drop(&mut self) {
self.spi_dma.spi.flush().ok();
}
}
/// An in-progress DMA transfer.
#[must_use]
pub struct SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
spi_dma: &'t mut SpiDma<'d, T, C, M, DmaMode>,
}
impl<'t, 'd, T, C, M, DmaMode> DmaTransfer for SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
self.spi_dma.spi.flush().ok();
if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
let ch = &self.spi_dma.channel;
ch.tx.is_done() && ch.rx.is_done()
}
}
impl<'t, 'd, T, C, M, DmaMode> Drop for SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
fn drop(&mut self) {
self.spi_dma.spi.flush().ok();
}
}
/// A DMA capable SPI instance.
pub struct SpiDma<'d, T, C, M, DmaMode>
@ -1106,6 +999,53 @@ pub mod dma {
}
}
impl<'d, T, C, M, DmaMode> DmaSupport for SpiDma<'d, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
fn peripheral_wait_dma(&mut self, _is_tx: bool, _is_rx: bool) {
self.spi.flush().ok();
}
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
impl<'d, T, C, M, DmaMode> DmaSupportTx for SpiDma<'d, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
type TX = C::Tx<'d>;
fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx
}
}
impl<'d, T, C, M, DmaMode> DmaSupportRx for SpiDma<'d, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
DmaMode: Mode,
{
type RX = C::Rx<'d>;
fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx
}
}
impl<'d, T, C, M, DmaMode> SpiDma<'d, T, C, M, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
@ -1123,7 +1063,7 @@ pub mod dma {
pub fn dma_write<'t, TXBUF>(
&'t mut self,
words: &'t TXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
) -> Result<DmaTransferTx<Self>, super::Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
@ -1135,7 +1075,7 @@ pub mod dma {
self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?;
Ok(SpiDmaTransfer { spi_dma: self })
Ok(DmaTransferTx::new(self))
}
/// Perform a DMA read.
@ -1147,7 +1087,7 @@ pub mod dma {
pub fn dma_read<'t, RXBUF>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
) -> Result<DmaTransferRx<Self>, super::Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
@ -1161,7 +1101,7 @@ pub mod dma {
self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?;
}
Ok(SpiDmaTransfer { spi_dma: self })
Ok(DmaTransferRx::new(self))
}
/// Perform a DMA transfer.
@ -1173,7 +1113,7 @@ pub mod dma {
&'t mut self,
words: &'t TXBUF,
read_buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, M, DmaMode>, super::Error>
) -> Result<DmaTransferTxRx<Self>, super::Error>
where
TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>,
@ -1195,7 +1135,7 @@ pub mod dma {
&mut self.channel.rx,
)?;
}
Ok(SpiDmaTransferRxTx { spi_dma: self })
Ok(DmaTransferTxRx::new(self))
}
}
@ -1215,7 +1155,7 @@ pub mod dma {
address: Address,
dummy: u8,
buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
) -> Result<DmaTransferRx<Self>, super::Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
@ -1279,7 +1219,7 @@ pub mod dma {
self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx, false)?;
}
Ok(SpiDmaTransfer { spi_dma: self })
Ok(DmaTransferRx::new(self))
}
#[cfg_attr(feature = "place-spi-driver-in-ram", ram)]
@ -1290,7 +1230,7 @@ pub mod dma {
address: Address,
dummy: u8,
buffer: &'t TXBUF,
) -> Result<SpiDmaTransfer<'t, 'd, T, C, M, DmaMode>, super::Error>
) -> Result<DmaTransferTx<Self>, super::Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
@ -1352,7 +1292,7 @@ pub mod dma {
self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx, false)?;
Ok(SpiDmaTransfer { spi_dma: self })
Ok(DmaTransferTx::new(self))
}
}

View File

@ -134,11 +134,12 @@ pub mod dma {
use crate::dma::Spi3Peripheral;
use crate::{
dma::{
dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
Channel,
ChannelTypes,
DmaError,
DmaTransfer,
DmaTransferRxTx,
DmaTransferRx,
DmaTransferTx,
DmaTransferTxRx,
RxPrivate,
Spi2Peripheral,
SpiPeripheral,
@ -228,164 +229,6 @@ pub mod dma {
}
}
}
/// An in-progress DMA transfer
#[must_use]
pub struct SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>,
}
impl<'t, 'd, T, C, DmaMode> DmaTransferRxTx for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
while !self.is_done() {}
self.spi_dma.spi.flush().ok();
if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
let ch = &self.spi_dma.channel;
ch.tx.is_done() && ch.rx.is_done() && !self.spi_dma.spi.is_bus_busy()
}
}
impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
fn drop(&mut self) {
while !self.is_done() {}
self.spi_dma.spi.flush().ok();
}
}
/// An in-progress DMA transfer.
#[must_use]
pub struct SpiDmaTransferRx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>,
}
impl<'t, 'd, T, C, DmaMode> DmaTransfer for SpiDmaTransferRx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
while !self.is_done() {}
self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is not enough
if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
let ch = &self.spi_dma.channel;
ch.rx.is_done()
}
}
impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferRx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
fn drop(&mut self) {
while !self.is_done() {}
self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is
// not enough
}
}
/// An in-progress DMA transfer.
#[must_use]
pub struct SpiDmaTransferTx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
spi_dma: &'t mut SpiDma<'d, T, C, DmaMode>,
}
impl<'t, 'd, T, C, DmaMode> DmaTransfer for SpiDmaTransferTx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
/// Wait for the DMA transfer to complete
fn wait(self) -> Result<(), DmaError> {
// Waiting for the DMA transfer is not enough. We need to wait for the
// peripheral to finish flushing its buffers, too.
while !self.is_done() {}
self.spi_dma.spi.flush().ok();
if self.spi_dma.channel.rx.has_error() || self.spi_dma.channel.tx.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
}
}
/// Check if the DMA transfer is complete
fn is_done(&self) -> bool {
let ch = &self.spi_dma.channel;
ch.tx.is_done()
}
}
impl<'t, 'd, T, C, DmaMode> Drop for SpiDmaTransferTx<'t, 'd, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
fn drop(&mut self) {
while !self.is_done() {}
self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is
// not enough
}
}
/// A DMA capable SPI instance.
pub struct SpiDma<'d, T, C, DmaMode>
@ -409,6 +252,55 @@ pub mod dma {
}
}
impl<'d, T, C, DmaMode> DmaSupport for SpiDma<'d, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
fn peripheral_wait_dma(&mut self, is_tx: bool, is_rx: bool) {
while !((!is_tx || self.channel.tx.is_done())
&& (!is_rx || self.channel.rx.is_done())
&& !self.spi.is_bus_busy())
{}
self.spi.flush().ok();
}
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
impl<'d, T, C, DmaMode> DmaSupportTx for SpiDma<'d, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
type TX = C::Tx<'d>;
fn tx(&mut self) -> &mut Self::TX {
&mut self.channel.tx
}
}
impl<'d, T, C, DmaMode> DmaSupportRx for SpiDma<'d, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
DmaMode: Mode,
{
type RX = C::Rx<'d>;
fn rx(&mut self) -> &mut Self::RX {
&mut self.channel.rx
}
}
impl<'d, T, C, DmaMode> SpiDma<'d, T, C, DmaMode>
where
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
@ -426,7 +318,7 @@ pub mod dma {
pub fn dma_write<'t, TXBUF>(
&'t mut self,
words: &'t TXBUF,
) -> Result<SpiDmaTransferTx<'t, 'd, T, C, DmaMode>, Error>
) -> Result<DmaTransferTx<Self>, Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
@ -438,7 +330,7 @@ pub mod dma {
self.spi
.start_write_bytes_dma(ptr, len, &mut self.channel.tx)
.map(move |_| SpiDmaTransferTx { spi_dma: self })
.map(move |_| DmaTransferTx::new(self))
}
/// Register a buffer for a DMA read.
@ -451,7 +343,7 @@ pub mod dma {
pub fn dma_read<'t, RXBUF>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<SpiDmaTransferRx<'t, 'd, T, C, DmaMode>, Error>
) -> Result<DmaTransferRx<Self>, Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
@ -464,7 +356,7 @@ pub mod dma {
unsafe {
self.spi
.start_read_bytes_dma(ptr, len, &mut self.channel.rx)
.map(move |_| SpiDmaTransferRx { spi_dma: self })
.map(move |_| DmaTransferRx::new(self))
}
}
@ -480,7 +372,7 @@ pub mod dma {
&'t mut self,
words: &'t TXBUF,
read_buffer: &'t mut RXBUF,
) -> Result<SpiDmaTransferRxTx<'t, 'd, T, C, DmaMode>, Error>
) -> Result<DmaTransferTxRx<Self>, Error>
where
TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>,
@ -502,7 +394,7 @@ pub mod dma {
&mut self.channel.tx,
&mut self.channel.rx,
)
.map(move |_| SpiDmaTransferRxTx { spi_dma: self })
.map(move |_| DmaTransferTxRx::new(self))
}
}
}

View File

@ -81,7 +81,7 @@ fn main() -> ! {
send[send.len() - 1] = i;
i = i.wrapping_add(1);
let transfer = spi.dma_transfer(&mut send, &mut receive).unwrap();
let mut transfer = spi.dma_transfer(&mut send, &mut receive).unwrap();
// here we could do something else while DMA transfer is in progress
let mut n = 0;
// Check is_done until the transfer is almost done (32000 bytes at 100kHz is