mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-29 21:30:39 +00:00
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:
parent
8a1df42309
commit
9edd098da5
@ -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
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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")]
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user