Remove Rx and Tx traits from the dma module (#3338)

* Remove Rx and Tx traits from the dma module

* merge impl blocks
This commit is contained in:
Dominic Fischer 2025-04-08 13:33:33 +01:00 committed by GitHub
parent e1e04451ca
commit 17c09ccaec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 187 additions and 267 deletions

View File

@ -243,8 +243,6 @@ pub mod dma {
DmaRxBuffer,
DmaTxBuffer,
PeripheralDmaChannel,
Rx,
Tx,
},
peripherals::AES,
Blocking,

View File

@ -23,8 +23,6 @@ use crate::{
DmaTxBuf,
DmaTxBuffer,
DmaTxInterrupt,
Rx,
Tx,
},
Async,
Blocking,

View File

@ -1324,9 +1324,10 @@ impl TxCircularState {
}
}
pub(crate) fn update<T>(&mut self, channel: &T) -> Result<(), DmaError>
pub(crate) fn update<Dm, CH>(&mut self, channel: &ChannelTx<Dm, CH>) -> Result<(), DmaError>
where
T: Tx,
Dm: DriverMode,
CH: DmaTxChannel,
{
if channel
.pending_out_interrupts()
@ -1735,60 +1736,6 @@ where
{
}
/// The functions here are not meant to be used outside the HAL
#[doc(hidden)]
pub trait Rx: crate::private::Sealed {
unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
chain: &DescriptorChain,
) -> Result<(), DmaError>;
unsafe fn prepare_transfer<BUF: DmaRxBuffer>(
&mut self,
peri: DmaPeripheral,
buffer: &mut BUF,
) -> Result<(), DmaError>;
fn start_transfer(&mut self) -> Result<(), DmaError>;
fn stop_transfer(&mut self);
#[cfg(gdma)]
fn set_mem2mem_mode(&mut self, value: bool);
fn listen_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>);
fn unlisten_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>);
fn is_listening_in(&self) -> EnumSet<DmaRxInterrupt>;
fn clear_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>);
fn pending_in_interrupts(&self) -> EnumSet<DmaRxInterrupt>;
fn is_done(&self) -> bool;
fn has_error(&self) -> bool {
self.pending_in_interrupts()
.contains(DmaRxInterrupt::DescriptorError)
}
fn has_dscr_empty_error(&self) -> bool {
self.pending_in_interrupts()
.contains(DmaRxInterrupt::DescriptorEmpty)
}
fn has_eof_error(&self) -> bool {
self.pending_in_interrupts()
.contains(DmaRxInterrupt::ErrorEof)
}
fn clear_interrupts(&self);
fn waker(&self) -> &'static crate::asynch::AtomicWaker;
}
// NOTE(p4): because the P4 has two different GDMAs, we won't be able to use
// `GenericPeripheralGuard`.
cfg_if::cfg_if! {
@ -1940,14 +1887,15 @@ where
{
}
impl<Dm, CH> Rx for ChannelRx<Dm, CH>
#[allow(unused)]
impl<Dm, CH> ChannelRx<Dm, CH>
where
Dm: DriverMode,
CH: DmaRxChannel,
{
// TODO: used by I2S, which should be rewritten to use the Preparation-based
// API.
unsafe fn prepare_transfer_without_start(
pub(crate) unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
chain: &DescriptorChain,
@ -1992,7 +1940,7 @@ where
self.do_prepare(preparation, peri)
}
unsafe fn prepare_transfer<BUF: DmaRxBuffer>(
pub(crate) unsafe fn prepare_transfer<BUF: DmaRxBuffer>(
&mut self,
peri: DmaPeripheral,
buffer: &mut BUF,
@ -2002,7 +1950,7 @@ where
self.do_prepare(preparation, peri)
}
fn start_transfer(&mut self) -> Result<(), DmaError> {
pub(crate) fn start_transfer(&mut self) -> Result<(), DmaError> {
self.rx_impl.start();
if self
@ -2015,93 +1963,62 @@ where
}
}
fn stop_transfer(&mut self) {
pub(crate) fn stop_transfer(&mut self) {
self.rx_impl.stop()
}
#[cfg(gdma)]
fn set_mem2mem_mode(&mut self, value: bool) {
pub(crate) fn set_mem2mem_mode(&mut self, value: bool) {
self.rx_impl.set_mem2mem_mode(value);
}
fn listen_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
pub(crate) fn listen_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
self.rx_impl.listen(interrupts);
}
fn unlisten_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
pub(crate) fn unlisten_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
self.rx_impl.unlisten(interrupts);
}
fn is_listening_in(&self) -> EnumSet<DmaRxInterrupt> {
pub(crate) fn is_listening_in(&self) -> EnumSet<DmaRxInterrupt> {
self.rx_impl.is_listening()
}
fn clear_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
pub(crate) fn clear_in(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
self.rx_impl.clear(interrupts);
}
fn pending_in_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
pub(crate) fn pending_in_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
self.rx_impl.pending_interrupts()
}
fn is_done(&self) -> bool {
pub(crate) fn is_done(&self) -> bool {
self.pending_in_interrupts()
.contains(DmaRxInterrupt::SuccessfulEof)
}
fn clear_interrupts(&self) {
pub(crate) fn clear_interrupts(&self) {
self.rx_impl.clear_all();
}
fn waker(&self) -> &'static crate::asynch::AtomicWaker {
pub(crate) fn waker(&self) -> &'static crate::asynch::AtomicWaker {
self.rx_impl.waker()
}
}
/// The functions here are not meant to be used outside the HAL
#[doc(hidden)]
pub trait Tx: crate::private::Sealed {
unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
chain: &DescriptorChain,
) -> Result<(), DmaError>;
unsafe fn prepare_transfer<BUF: DmaTxBuffer>(
&mut self,
peri: DmaPeripheral,
buffer: &mut BUF,
) -> Result<(), DmaError>;
fn listen_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>);
fn unlisten_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>);
fn is_listening_out(&self) -> EnumSet<DmaTxInterrupt>;
fn clear_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>);
fn pending_out_interrupts(&self) -> EnumSet<DmaTxInterrupt>;
fn start_transfer(&mut self) -> Result<(), DmaError>;
fn stop_transfer(&mut self);
fn is_done(&self) -> bool {
self.pending_out_interrupts()
.contains(DmaTxInterrupt::TotalEof)
pub(crate) fn has_error(&self) -> bool {
self.pending_in_interrupts()
.contains(DmaRxInterrupt::DescriptorError)
}
fn has_error(&self) -> bool {
self.pending_out_interrupts()
.contains(DmaTxInterrupt::DescriptorError)
pub(crate) fn has_dscr_empty_error(&self) -> bool {
self.pending_in_interrupts()
.contains(DmaRxInterrupt::DescriptorEmpty)
}
fn clear_interrupts(&self);
fn waker(&self) -> &'static crate::asynch::AtomicWaker;
fn last_out_dscr_address(&self) -> usize;
pub(crate) fn has_eof_error(&self) -> bool {
self.pending_in_interrupts()
.contains(DmaRxInterrupt::ErrorEof)
}
}
/// DMA transmit channel
@ -2235,14 +2152,15 @@ where
{
}
impl<Dm, CH> Tx for ChannelTx<Dm, CH>
#[allow(unused)]
impl<Dm, CH> ChannelTx<Dm, CH>
where
Dm: DriverMode,
CH: DmaTxChannel,
{
// TODO: used by I2S, which should be rewritten to use the Preparation-based
// API.
unsafe fn prepare_transfer_without_start(
pub(crate) unsafe fn prepare_transfer_without_start(
&mut self,
peri: DmaPeripheral,
chain: &DescriptorChain,
@ -2291,7 +2209,7 @@ where
Ok(())
}
unsafe fn prepare_transfer<BUF: DmaTxBuffer>(
pub(crate) unsafe fn prepare_transfer<BUF: DmaTxBuffer>(
&mut self,
peri: DmaPeripheral,
buffer: &mut BUF,
@ -2301,7 +2219,7 @@ where
self.do_prepare(preparation, peri)
}
fn start_transfer(&mut self) -> Result<(), DmaError> {
pub(crate) fn start_transfer(&mut self) -> Result<(), DmaError> {
self.tx_impl.start();
while self.tx_impl.is_fifo_empty() && self.pending_out_interrupts().is_empty() {}
@ -2315,41 +2233,51 @@ where
}
}
fn stop_transfer(&mut self) {
pub(crate) fn stop_transfer(&mut self) {
self.tx_impl.stop()
}
fn listen_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
pub(crate) fn listen_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
self.tx_impl.listen(interrupts);
}
fn unlisten_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
pub(crate) fn unlisten_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
self.tx_impl.unlisten(interrupts);
}
fn is_listening_out(&self) -> EnumSet<DmaTxInterrupt> {
pub(crate) fn is_listening_out(&self) -> EnumSet<DmaTxInterrupt> {
self.tx_impl.is_listening()
}
fn clear_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
pub(crate) fn clear_out(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
self.tx_impl.clear(interrupts);
}
fn pending_out_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
pub(crate) fn pending_out_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
self.tx_impl.pending_interrupts()
}
fn waker(&self) -> &'static crate::asynch::AtomicWaker {
pub(crate) fn waker(&self) -> &'static crate::asynch::AtomicWaker {
self.tx_impl.waker()
}
fn clear_interrupts(&self) {
pub(crate) fn clear_interrupts(&self) {
self.tx_impl.clear_all();
}
fn last_out_dscr_address(&self) -> usize {
pub(crate) fn last_out_dscr_address(&self) -> usize {
self.tx_impl.last_dscr_address()
}
pub(crate) fn is_done(&self) -> bool {
self.pending_out_interrupts()
.contains(DmaTxInterrupt::TotalEof)
}
pub(crate) fn has_error(&self) -> bool {
self.pending_out_interrupts()
.contains(DmaTxInterrupt::DescriptorError)
}
}
#[doc(hidden)]
@ -2569,6 +2497,8 @@ pub(crate) mod dma_private {
use super::*;
pub trait DmaSupport {
type DriverMode: DriverMode;
/// Wait until the transfer is done.
///
/// Depending on the peripheral this might include checking the DMA
@ -2587,17 +2517,17 @@ pub(crate) mod dma_private {
}
pub trait DmaSupportTx: DmaSupport {
type TX: Tx;
type Channel: DmaTxChannel;
fn tx(&mut self) -> &mut Self::TX;
fn tx(&mut self) -> &mut ChannelTx<Self::DriverMode, Self::Channel>;
fn chain(&mut self) -> &mut DescriptorChain;
}
pub trait DmaSupportRx: DmaSupport {
type RX: Rx;
type Channel: DmaRxChannel;
fn rx(&mut self) -> &mut Self::RX;
fn rx(&mut self) -> &mut ChannelRx<Self::DriverMode, Self::Channel>;
fn chain(&mut self) -> &mut DescriptorChain;
}
@ -2906,26 +2836,26 @@ pub(crate) mod asynch {
use super::*;
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct DmaTxFuture<'a, TX>
pub struct DmaTxFuture<'a, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
pub(crate) tx: &'a mut TX,
pub(crate) tx: &'a mut ChannelTx<Async, CH>,
}
impl<'a, TX> DmaTxFuture<'a, TX>
impl<'a, CH> DmaTxFuture<'a, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
#[cfg_attr(esp32c2, allow(dead_code))]
pub fn new(tx: &'a mut TX) -> Self {
pub fn new(tx: &'a mut ChannelTx<Async, CH>) -> Self {
Self { tx }
}
}
impl<TX> core::future::Future for DmaTxFuture<'_, TX>
impl<CH> core::future::Future for DmaTxFuture<'_, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
type Output = Result<(), DmaError>;
@ -2952,9 +2882,9 @@ pub(crate) mod asynch {
}
}
impl<TX> Drop for DmaTxFuture<'_, TX>
impl<CH> Drop for DmaTxFuture<'_, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
fn drop(&mut self) {
self.tx
@ -2963,25 +2893,25 @@ pub(crate) mod asynch {
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct DmaRxFuture<'a, RX>
pub struct DmaRxFuture<'a, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
pub(crate) rx: &'a mut RX,
pub(crate) rx: &'a mut ChannelRx<Async, CH>,
}
impl<'a, RX> DmaRxFuture<'a, RX>
impl<'a, CH> DmaRxFuture<'a, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
pub fn new(rx: &'a mut RX) -> Self {
pub fn new(rx: &'a mut ChannelRx<Async, CH>) -> Self {
Self { rx }
}
}
impl<RX> core::future::Future for DmaRxFuture<'_, RX>
impl<CH> core::future::Future for DmaRxFuture<'_, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
type Output = Result<(), DmaError>;
@ -3012,9 +2942,9 @@ pub(crate) mod asynch {
}
}
impl<RX> Drop for DmaRxFuture<'_, RX>
impl<CH> Drop for DmaRxFuture<'_, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
fn drop(&mut self) {
self.rx.unlisten_in(
@ -3026,28 +2956,28 @@ pub(crate) mod asynch {
}
#[cfg(any(i2s0, i2s1))]
pub struct DmaTxDoneChFuture<'a, TX>
pub struct DmaTxDoneChFuture<'a, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
pub(crate) tx: &'a mut TX,
pub(crate) tx: &'a mut ChannelTx<Async, CH>,
_a: (),
}
#[cfg(any(i2s0, i2s1))]
impl<'a, TX> DmaTxDoneChFuture<'a, TX>
impl<'a, CH> DmaTxDoneChFuture<'a, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
pub fn new(tx: &'a mut TX) -> Self {
pub fn new(tx: &'a mut ChannelTx<Async, CH>) -> Self {
Self { tx, _a: () }
}
}
#[cfg(any(i2s0, i2s1))]
impl<TX> core::future::Future for DmaTxDoneChFuture<'_, TX>
impl<CH> core::future::Future for DmaTxDoneChFuture<'_, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
type Output = Result<(), DmaError>;
@ -3079,9 +3009,9 @@ pub(crate) mod asynch {
}
#[cfg(any(i2s0, i2s1))]
impl<TX> Drop for DmaTxDoneChFuture<'_, TX>
impl<CH> Drop for DmaTxDoneChFuture<'_, CH>
where
TX: Tx,
CH: DmaTxChannel,
{
fn drop(&mut self) {
self.tx
@ -3090,28 +3020,28 @@ pub(crate) mod asynch {
}
#[cfg(any(i2s0, i2s1))]
pub struct DmaRxDoneChFuture<'a, RX>
pub struct DmaRxDoneChFuture<'a, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
pub(crate) rx: &'a mut RX,
pub(crate) rx: &'a mut ChannelRx<Async, CH>,
_a: (),
}
#[cfg(any(i2s0, i2s1))]
impl<'a, RX> DmaRxDoneChFuture<'a, RX>
impl<'a, CH> DmaRxDoneChFuture<'a, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
pub fn new(rx: &'a mut RX) -> Self {
pub fn new(rx: &'a mut ChannelRx<Async, CH>) -> Self {
Self { rx, _a: () }
}
}
#[cfg(any(i2s0, i2s1))]
impl<RX> core::future::Future for DmaRxDoneChFuture<'_, RX>
impl<CH> core::future::Future for DmaRxDoneChFuture<'_, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
type Output = Result<(), DmaError>;
@ -3147,9 +3077,9 @@ pub(crate) mod asynch {
}
#[cfg(any(i2s0, i2s1))]
impl<RX> Drop for DmaRxDoneChFuture<'_, RX>
impl<CH> Drop for DmaRxDoneChFuture<'_, CH>
where
RX: Rx,
CH: DmaRxChannel,
{
fn drop(&mut self) {
self.rx.unlisten_in(

View File

@ -89,8 +89,6 @@ use crate::{
PeripheralRxChannel,
PeripheralTxChannel,
ReadBuffer,
Rx,
Tx,
WriteBuffer,
},
gpio::interconnect::PeripheralOutput,
@ -420,6 +418,8 @@ impl<Dm> DmaSupport for I2sTx<'_, Dm>
where
Dm: DriverMode,
{
type DriverMode = Dm;
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
self.i2s.wait_for_tx_done();
}
@ -433,9 +433,9 @@ impl<'d, Dm> DmaSupportTx for I2sTx<'d, Dm>
where
Dm: DriverMode,
{
type TX = ChannelTx<Dm, PeripheralTxChannel<AnyI2s<'d>>>;
type Channel = PeripheralTxChannel<AnyI2s<'d>>;
fn tx(&mut self) -> &mut Self::TX {
fn tx(&mut self) -> &mut ChannelTx<Dm, PeripheralTxChannel<AnyI2s<'d>>> {
&mut self.tx_channel
}
@ -548,6 +548,8 @@ impl<Dm> DmaSupport for I2sRx<'_, Dm>
where
Dm: DriverMode,
{
type DriverMode = Dm;
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
self.i2s.wait_for_rx_done();
}
@ -561,9 +563,9 @@ impl<'d, Dm> DmaSupportRx for I2sRx<'d, Dm>
where
Dm: DriverMode,
{
type RX = ChannelRx<Dm, PeripheralRxChannel<AnyI2s<'d>>>;
type Channel = PeripheralRxChannel<AnyI2s<'d>>;
fn rx(&mut self) -> &mut Self::RX {
fn rx(&mut self) -> &mut ChannelRx<Dm, PeripheralRxChannel<AnyI2s<'d>>> {
&mut self.rx_channel
}
@ -1784,9 +1786,7 @@ pub mod asynch {
asynch::{DmaRxDoneChFuture, DmaRxFuture, DmaTxDoneChFuture, DmaTxFuture},
DmaEligible,
ReadBuffer,
Rx,
RxCircularState,
Tx,
TxCircularState,
WriteBuffer,
},

View File

@ -112,7 +112,6 @@ use crate::{
DmaError,
DmaTxBuffer,
PeripheralTxChannel,
Tx,
},
gpio::{
interconnect::{OutputConnection, PeripheralOutput},

View File

@ -62,7 +62,7 @@ use core::{
use crate::{
clock::Clocks,
dma::{ChannelRx, DmaError, DmaPeripheral, DmaRxBuffer, PeripheralRxChannel, Rx, RxChannelFor},
dma::{ChannelRx, DmaError, DmaPeripheral, DmaRxBuffer, PeripheralRxChannel, RxChannelFor},
gpio::{
interconnect::{PeripheralInput, PeripheralOutput},
InputSignal,

View File

@ -103,7 +103,7 @@ use core::{
use crate::{
clock::Clocks,
dma::{ChannelTx, DmaError, DmaPeripheral, DmaTxBuffer, PeripheralTxChannel, Tx, TxChannelFor},
dma::{ChannelTx, DmaError, DmaPeripheral, DmaTxBuffer, PeripheralTxChannel, TxChannelFor},
gpio::{interconnect::PeripheralOutput, Level, OutputSignal},
lcd_cam::{
calculate_clkm,

View File

@ -59,7 +59,7 @@ use core::{
use crate::{
clock::Clocks,
dma::{ChannelTx, DmaError, DmaPeripheral, DmaTxBuffer, PeripheralTxChannel, Tx, TxChannelFor},
dma::{ChannelTx, DmaError, DmaPeripheral, DmaTxBuffer, PeripheralTxChannel, TxChannelFor},
gpio::{
interconnect::{OutputConnection, PeripheralOutput},
OutputSignal,

View File

@ -139,9 +139,7 @@ use crate::{
DmaTxBuffer,
PeripheralRxChannel,
PeripheralTxChannel,
Rx,
RxChannelFor,
Tx,
TxChannelFor,
},
gpio::{

View File

@ -48,7 +48,7 @@ use super::{BitOrder, DataMode, DmaError, Error, Mode};
use crate::{
asynch::AtomicWaker,
clock::Clocks,
dma::{DmaChannelFor, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx},
dma::{DmaChannelFor, DmaEligible, DmaRxBuffer, DmaTxBuffer},
gpio::{
interconnect::{PeripheralInput, PeripheralOutput},
InputSignal,
@ -1394,6 +1394,55 @@ mod dma {
pins: self.pins,
}
}
async fn wait_for_idle_async(&mut self) {
if self.rx_transfer_in_progress {
_ = DmaRxFuture::new(&mut self.channel.rx).await;
self.rx_transfer_in_progress = false;
}
struct Fut(Driver);
impl Future for Fut {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0.interrupts().contains(SpiInterrupt::TransferDone) {
#[cfg(esp32)]
// Need to poll for done-ness even after interrupt fires.
if self.0.busy() {
cx.waker().wake_by_ref();
return Poll::Pending;
}
self.0.clear_interrupts(SpiInterrupt::TransferDone.into());
return Poll::Ready(());
}
self.0.state.waker.register(cx.waker());
self.0
.enable_listen(SpiInterrupt::TransferDone.into(), true);
Poll::Pending
}
}
impl Drop for Fut {
fn drop(&mut self) {
self.0
.enable_listen(SpiInterrupt::TransferDone.into(), false);
}
}
if !self.is_done() {
Fut(self.driver()).await;
}
if self.tx_transfer_in_progress {
// In case DMA TX buffer is bigger than what the SPI consumes, stop the DMA.
if !self.channel.tx.is_done() {
self.channel.tx.stop_transfer();
}
self.tx_transfer_in_progress = false;
}
}
}
impl<Dm> core::fmt::Debug for SpiDma<'_, Dm>
@ -1470,55 +1519,6 @@ mod dma {
fence(Ordering::Acquire);
}
async fn wait_for_idle_async(&mut self) {
if self.rx_transfer_in_progress {
_ = DmaRxFuture::new(&mut self.channel.rx).await;
self.rx_transfer_in_progress = false;
}
struct Fut(Driver);
impl Future for Fut {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0.interrupts().contains(SpiInterrupt::TransferDone) {
#[cfg(esp32)]
// Need to poll for done-ness even after interrupt fires.
if self.0.busy() {
cx.waker().wake_by_ref();
return Poll::Pending;
}
self.0.clear_interrupts(SpiInterrupt::TransferDone.into());
return Poll::Ready(());
}
self.0.state.waker.register(cx.waker());
self.0
.enable_listen(SpiInterrupt::TransferDone.into(), true);
Poll::Pending
}
}
impl Drop for Fut {
fn drop(&mut self) {
self.0
.enable_listen(SpiInterrupt::TransferDone.into(), false);
}
}
if !self.is_done() {
Fut(self.driver()).await;
}
if self.tx_transfer_in_progress {
// In case DMA TX buffer is bigger than what the SPI consumes, stop the DMA.
if !self.channel.tx.is_done() {
self.channel.tx.stop_transfer();
}
self.tx_transfer_in_progress = false;
}
}
/// # Safety:
///
/// The caller must ensure to not access the buffer contents while the
@ -1545,8 +1545,7 @@ mod dma {
bytes_to_write,
rx_buffer,
tx_buffer,
&mut self.channel.rx,
&mut self.channel.tx,
&mut self.channel,
)
}
}
@ -1591,8 +1590,7 @@ mod dma {
bytes_to_write,
&mut EmptyBuf,
&mut self.address_buffer,
&mut self.channel.rx,
&mut self.channel.tx,
&mut self.channel,
)
}
}
@ -2748,15 +2746,14 @@ impl DmaDriver {
#[allow(clippy::too_many_arguments)]
#[cfg_attr(place_spi_driver_in_ram, ram)]
unsafe fn start_transfer_dma<RX: Rx, TX: Tx>(
unsafe fn start_transfer_dma<Dm: DriverMode>(
&self,
_full_duplex: bool,
rx_len: usize,
tx_len: usize,
rx_buffer: &mut impl DmaRxBuffer,
tx_buffer: &mut impl DmaTxBuffer,
rx: &mut RX,
tx: &mut TX,
channel: &mut Channel<Dm, PeripheralDmaChannel<AnySpi<'_>>>,
) -> Result<(), Error> {
#[cfg(esp32s2)]
{
@ -2775,8 +2772,10 @@ impl DmaDriver {
self.enable_dma();
if rx_len > 0 {
rx.prepare_transfer(self.dma_peripheral, rx_buffer)
.and_then(|_| rx.start_transfer())?;
channel
.rx
.prepare_transfer(self.dma_peripheral, rx_buffer)
.and_then(|_| channel.rx.start_transfer())?;
} else {
#[cfg(esp32)]
{
@ -2793,8 +2792,10 @@ impl DmaDriver {
}
}
if tx_len > 0 {
tx.prepare_transfer(self.dma_peripheral, tx_buffer)
.and_then(|_| tx.start_transfer())?;
channel
.tx
.prepare_transfer(self.dma_peripheral, tx_buffer)
.and_then(|_| channel.tx.start_transfer())?;
}
#[cfg(gdma)]
@ -3849,6 +3850,8 @@ use core::{
task::{Context, Poll},
};
use crate::dma::{Channel, PeripheralDmaChannel};
impl Future for SpiFuture<'_> {
type Output = ();

View File

@ -172,8 +172,6 @@ pub mod dma {
DmaTxBuffer,
EmptyBuf,
PeripheralDmaChannel,
Rx,
Tx,
},
DriverMode,
};
@ -259,8 +257,7 @@ pub mod dma {
bytes_to_write,
&mut EmptyBuf,
&mut buffer,
&mut self.channel.rx,
&mut self.channel.tx,
&mut self.channel,
)
};
if let Err(err) = result {
@ -295,8 +292,7 @@ pub mod dma {
0,
&mut buffer,
&mut EmptyBuf,
&mut self.channel.rx,
&mut self.channel.tx,
&mut self.channel,
)
};
if let Err(err) = result {
@ -341,8 +337,7 @@ pub mod dma {
bytes_to_write,
&mut rx_buffer,
&mut tx_buffer,
&mut self.channel.rx,
&mut self.channel.tx,
&mut self.channel,
)
};
if let Err(err) = result {
@ -462,29 +457,28 @@ pub mod dma {
}
#[allow(clippy::too_many_arguments)]
unsafe fn start_transfer_dma<RX, TX>(
unsafe fn start_transfer_dma<Dm: DriverMode>(
&self,
read_buffer_len: usize,
write_buffer_len: usize,
rx_buffer: &mut impl DmaRxBuffer,
tx_buffer: &mut impl DmaTxBuffer,
rx: &mut RX,
tx: &mut TX,
) -> Result<(), Error>
where
RX: Rx,
TX: Tx,
{
channel: &mut Channel<Dm, PeripheralDmaChannel<AnySpi<'_>>>,
) -> Result<(), Error> {
self.enable_dma();
self.info.reset_spi();
if read_buffer_len > 0 {
rx.prepare_transfer(self.dma_peripheral, rx_buffer)?;
channel
.rx
.prepare_transfer(self.dma_peripheral, rx_buffer)?;
}
if write_buffer_len > 0 {
tx.prepare_transfer(self.dma_peripheral, tx_buffer)?;
channel
.tx
.prepare_transfer(self.dma_peripheral, tx_buffer)?;
}
#[cfg(esp32)]
@ -503,11 +497,11 @@ pub mod dma {
self.regs().cmd().modify(|_, w| w.usr().set_bit());
if read_buffer_len > 0 {
rx.start_transfer()?;
channel.rx.start_transfer()?;
}
if write_buffer_len > 0 {
tx.start_transfer()?;
channel.tx.start_transfer()?;
}
Ok(())