Skip to content

Commit

Permalink
Change semantics of DMA futures (#1835)
Browse files Browse the repository at this point in the history
* Change semantics of DMA futures

* Only clear specific interrupt bit when listening for an "in progress" interrupt

* Fix PARL_IO Rx

* Only enable interrupts when future is polled

---------

Co-authored-by: Dominic Fischer <git@dominicfischer.me>
  • Loading branch information
Dominaezzz and Dominic Fischer authored Jul 24, 2024
1 parent 38f1d28 commit 4ef91c5
Showing 1 changed file with 90 additions and 32 deletions.
122 changes: 90 additions & 32 deletions esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2141,7 +2141,10 @@ pub(crate) mod asynch {

use super::*;

pub struct DmaTxFuture<'a, TX> {
pub struct DmaTxFuture<'a, TX>
where
TX: Tx,
{
pub(crate) tx: &'a mut TX,
_a: (),
}
Expand All @@ -2151,8 +2154,6 @@ pub(crate) mod asynch {
TX: Tx,
{
pub fn new(tx: &'a mut TX) -> Self {
tx.listen_eof();
tx.listen_out_descriptor_error();
Self { tx, _a: () }
}

Expand All @@ -2172,18 +2173,34 @@ pub(crate) mod asynch {
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
TX::waker().register(cx.waker());
if self.tx.is_listening_eof() {
Poll::Pending
if self.tx.is_done() {
self.tx.clear_interrupts();
Poll::Ready(Ok(()))
} else if self.tx.has_error() {
self.tx.clear_interrupts();
Poll::Ready(Err(DmaError::DescriptorError))
} else {
Poll::Ready(Ok(()))
self.tx.listen_eof();
self.tx.listen_out_descriptor_error();
Poll::Pending
}
}
}

pub struct DmaRxFuture<'a, RX> {
impl<'a, TX> Drop for DmaTxFuture<'a, TX>
where
TX: Tx,
{
fn drop(&mut self) {
self.tx.unlisten_eof();
self.tx.unlisten_out_descriptor_error();
}
}

pub struct DmaRxFuture<'a, RX>
where
RX: Rx,
{
pub(crate) rx: &'a mut RX,
_a: (),
}
Expand All @@ -2193,10 +2210,6 @@ pub(crate) mod asynch {
RX: Rx,
{
pub fn new(rx: &'a mut RX) -> Self {
rx.listen_eof();
rx.listen_in_descriptor_error();
rx.listen_in_descriptor_error_dscr_empty();
rx.listen_in_descriptor_error_err_eof();
Self { rx, _a: () }
}

Expand All @@ -2216,22 +2229,42 @@ pub(crate) mod asynch {
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
RX::waker().register(cx.waker());
if self.rx.is_listening_eof() {
Poll::Pending
if self.rx.is_done() {
self.rx.clear_interrupts();
Poll::Ready(Ok(()))
} else if self.rx.has_error()
|| self.rx.has_dscr_empty_error()
|| self.rx.has_eof_error()
{
self.rx.clear_interrupts();
Poll::Ready(Err(DmaError::DescriptorError))
} else {
Poll::Ready(Ok(()))
self.rx.listen_eof();
self.rx.listen_in_descriptor_error();
self.rx.listen_in_descriptor_error_dscr_empty();
self.rx.listen_in_descriptor_error_err_eof();
Poll::Pending
}
}
}

impl<'a, RX> Drop for DmaRxFuture<'a, RX>
where
RX: Rx,
{
fn drop(&mut self) {
self.rx.unlisten_eof();
self.rx.unlisten_in_descriptor_error();
self.rx.unlisten_in_descriptor_error_dscr_empty();
self.rx.unlisten_in_descriptor_error_err_eof();
}
}

#[cfg(any(i2s0, i2s1))]
pub struct DmaTxDoneChFuture<'a, TX> {
pub struct DmaTxDoneChFuture<'a, TX>
where
TX: Tx,
{
pub(crate) tx: &'a mut TX,
_a: (),
}
Expand All @@ -2242,8 +2275,6 @@ pub(crate) mod asynch {
TX: Tx,
{
pub fn new(tx: &'a mut TX) -> Self {
tx.listen_ch_out_done();
tx.listen_out_descriptor_error();
Self { tx, _a: () }
}
}
Expand All @@ -2260,19 +2291,36 @@ pub(crate) mod asynch {
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
TX::waker().register(cx.waker());
if self.tx.is_listening_ch_out_done() {
Poll::Pending
if self.tx.is_ch_out_done_set() {
self.tx.clear_ch_out_done();
Poll::Ready(Ok(()))
} else if self.tx.has_error() {
self.tx.clear_interrupts();
Poll::Ready(Err(DmaError::DescriptorError))
} else {
Poll::Ready(Ok(()))
self.tx.listen_ch_out_done();
self.tx.listen_out_descriptor_error();
Poll::Pending
}
}
}

#[cfg(any(i2s0, i2s1))]
pub struct DmaRxDoneChFuture<'a, RX> {
impl<'a, TX> Drop for DmaTxDoneChFuture<'a, TX>
where
TX: Tx,
{
fn drop(&mut self) {
self.tx.unlisten_ch_out_done();
self.tx.unlisten_out_descriptor_error();
}
}

#[cfg(any(i2s0, i2s1))]
pub struct DmaRxDoneChFuture<'a, RX>
where
RX: Rx,
{
pub(crate) rx: &'a mut RX,
_a: (),
}
Expand All @@ -2283,10 +2331,6 @@ pub(crate) mod asynch {
RX: Rx,
{
pub fn new(rx: &'a mut RX) -> Self {
rx.listen_ch_in_done();
rx.listen_in_descriptor_error();
rx.listen_in_descriptor_error_dscr_empty();
rx.listen_in_descriptor_error_err_eof();
Self { rx, _a: () }
}
}
Expand All @@ -2303,20 +2347,38 @@ pub(crate) mod asynch {
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
RX::waker().register(cx.waker());
if self.rx.is_listening_ch_in_done() {
Poll::Pending
if self.rx.is_ch_in_done_set() {
self.rx.clear_ch_in_done();
Poll::Ready(Ok(()))
} else if self.rx.has_error()
|| self.rx.has_dscr_empty_error()
|| self.rx.has_eof_error()
{
self.rx.clear_interrupts();
Poll::Ready(Err(DmaError::DescriptorError))
} else {
Poll::Ready(Ok(()))
self.rx.listen_ch_in_done();
self.rx.listen_in_descriptor_error();
self.rx.listen_in_descriptor_error_dscr_empty();
self.rx.listen_in_descriptor_error_err_eof();
Poll::Pending
}
}
}

#[cfg(any(i2s0, i2s1))]
impl<'a, RX> Drop for DmaRxDoneChFuture<'a, RX>
where
RX: Rx,
{
fn drop(&mut self) {
self.rx.unlisten_ch_in_done();
self.rx.unlisten_in_descriptor_error();
self.rx.unlisten_in_descriptor_error_dscr_empty();
self.rx.unlisten_in_descriptor_error_err_eof();
}
}

fn handle_interrupt<Channel: RegisterAccess, Rx: RxChannel<Channel>, Tx: TxChannel<Channel>>() {
if Channel::has_in_descriptor_error()
|| Channel::has_in_descriptor_error_dscr_empty()
Expand All @@ -2338,25 +2400,21 @@ pub(crate) mod asynch {
}

if Channel::is_in_done() && Channel::is_listening_in_eof() {
Channel::clear_in_interrupts();
Channel::unlisten_in_eof();
Rx::waker().wake()
}

if Channel::is_ch_in_done_set() {
Channel::clear_ch_in_done();
Channel::unlisten_ch_in_done();
Rx::waker().wake()
}

if Channel::is_out_done() && Channel::is_listening_out_eof() {
Channel::clear_out_interrupts();
Channel::unlisten_out_eof();
Tx::waker().wake()
}

if Channel::is_ch_out_done_set() {
Channel::clear_ch_out_done();
Channel::unlisten_ch_out_done();
Tx::waker().wake()
}
Expand Down

0 comments on commit 4ef91c5

Please sign in to comment.