mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-30 13:50:38 +00:00
SpiDma<Async>
now uses the SPI interrupt (instead of DMA) to wait f… (#3303)
* `SpiDma<Async>` now uses the SPI interrupt (instead of DMA) to wait for completion * fmt and fix * hail mary * review comment
This commit is contained in:
parent
4dcb1c7193
commit
6d84ee2acf
@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `esp_hal::i2s::master::AnyI2s` has been moved to `esp_hal::i2s::AnyI2s` (#3226)
|
||||
- `esp_hal::i2c::master::AnyI2c` has been moved to `esp_hal::i2c::AnyI2c` (#3226)
|
||||
- `SpiDmaBus` no longer adjusts the DMA buffer length for each transfer (#3263)
|
||||
- `SpiDma<Async>` now uses the SPI interrupt (instead of DMA) to wait for completion (#3303)
|
||||
|
||||
- `gpio::interconnect` types now have a lifetime associated with them (#3302)
|
||||
|
||||
|
@ -1277,7 +1277,8 @@ mod dma {
|
||||
impl<'d> SpiDma<'d, Blocking> {
|
||||
/// Converts the SPI instance into async mode.
|
||||
#[instability::unstable]
|
||||
pub fn into_async(self) -> SpiDma<'d, Async> {
|
||||
pub fn into_async(mut self) -> SpiDma<'d, Async> {
|
||||
self.set_interrupt_handler(self.spi.handler());
|
||||
SpiDma {
|
||||
spi: self.spi,
|
||||
channel: self.channel.into_async(),
|
||||
@ -1354,12 +1355,42 @@ mod dma {
|
||||
pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
|
||||
self.driver().clear_interrupts(interrupts.into());
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(multi_core),
|
||||
doc = "Registers an interrupt handler for the peripheral."
|
||||
)]
|
||||
#[cfg_attr(
|
||||
multi_core,
|
||||
doc = "Registers an interrupt handler for the peripheral on the current core."
|
||||
)]
|
||||
#[doc = ""]
|
||||
/// Note that this will replace any previously registered interrupt
|
||||
/// handlers.
|
||||
///
|
||||
/// You can restore the default/unhandled interrupt handler by using
|
||||
/// [crate::interrupt::DEFAULT_INTERRUPT_HANDLER]
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if passed interrupt handler is invalid (e.g. has priority
|
||||
/// `None`)
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
let interrupt = self.driver().info.interrupt;
|
||||
for core in Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> SpiDma<'d, Async> {
|
||||
/// Converts the SPI instance into async mode.
|
||||
#[instability::unstable]
|
||||
pub fn into_blocking(self) -> SpiDma<'d, Blocking> {
|
||||
crate::interrupt::disable(Cpu::current(), self.driver().info.interrupt);
|
||||
SpiDma {
|
||||
spi: self.spi,
|
||||
channel: self.channel.into_blocking(),
|
||||
@ -1448,23 +1479,44 @@ mod dma {
|
||||
}
|
||||
|
||||
async fn wait_for_idle_async(&mut self) {
|
||||
// As a future enhancement, setup Spi Future in here as well.
|
||||
|
||||
if self.rx_transfer_in_progress {
|
||||
_ = DmaRxFuture::new(&mut self.channel.rx).await;
|
||||
self.rx_transfer_in_progress = false;
|
||||
}
|
||||
|
||||
core::future::poll_fn(|cx| {
|
||||
use core::task::Poll;
|
||||
if self.is_done() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
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
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
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.
|
||||
@ -3735,8 +3787,8 @@ fn handle_async<I: Instance>(instance: I) {
|
||||
|
||||
let driver = Driver { info, state };
|
||||
if driver.interrupts().contains(SpiInterrupt::TransferDone) {
|
||||
state.waker.wake();
|
||||
driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
|
||||
state.waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user