From c11564585d83d6acce0f8f9e5bd9ea0448f78e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 29 Jan 2025 14:31:49 +0100 Subject: [PATCH] Fix async SPI on ESP32 --- esp-hal/src/spi/master.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index b8cd3aadf4..f2754e44fd 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -704,7 +704,8 @@ impl<'d> Spi<'d, Async> { return Ok(()); } - SpiFuture::new(&driver).await; + let future = SpiFuture::setup(&driver).await; + future.await; Ok(()) } @@ -3270,10 +3271,11 @@ impl Driver { /// Starts the operation and waits for it to complete. async fn execute_operation_async(&self) { - self.enable_listen(SpiInterrupt::TransferDone.into(), false); - self.clear_interrupts(SpiInterrupt::TransferDone.into()); + // On ESP32, the interrupt seems to not fire in specific circumstances, when + // `listen` is called after `start_operation`. Let's call it before, to be sure. + let future = SpiFuture::setup(self).await; self.start_operation(); - SpiFuture::new(self).await; + future.await; } #[allow(clippy::too_many_arguments)] @@ -3576,8 +3578,13 @@ struct SpiFuture<'a> { } impl<'a> SpiFuture<'a> { - pub fn new(driver: &'a Driver) -> Self { - Self { driver } + fn setup(driver: &'a Driver) -> impl Future { + core::future::poll_fn(move |cx| { + driver.state.waker.register(cx.waker()); + driver.clear_interrupts(SpiInterrupt::TransferDone.into()); + driver.enable_listen(SpiInterrupt::TransferDone.into(), true); + Poll::Ready(Self { driver }) + }) } } @@ -3590,7 +3597,7 @@ use core::{ impl Future for SpiFuture<'_> { type Output = (); - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { if self .driver .interrupts() @@ -3601,9 +3608,6 @@ impl Future for SpiFuture<'_> { return Poll::Ready(()); } - self.driver.state.waker.register(cx.waker()); - self.driver - .enable_listen(SpiInterrupt::TransferDone.into(), true); Poll::Pending } }