mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 14:44:42 +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::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)
|
- `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)
|
- `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)
|
- `gpio::interconnect` types now have a lifetime associated with them (#3302)
|
||||||
|
|
||||||
|
@ -1277,7 +1277,8 @@ mod dma {
|
|||||||
impl<'d> SpiDma<'d, Blocking> {
|
impl<'d> SpiDma<'d, Blocking> {
|
||||||
/// Converts the SPI instance into async mode.
|
/// Converts the SPI instance into async mode.
|
||||||
#[instability::unstable]
|
#[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 {
|
SpiDma {
|
||||||
spi: self.spi,
|
spi: self.spi,
|
||||||
channel: self.channel.into_async(),
|
channel: self.channel.into_async(),
|
||||||
@ -1354,12 +1355,42 @@ mod dma {
|
|||||||
pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
|
pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<SpiInterrupt>>) {
|
||||||
self.driver().clear_interrupts(interrupts.into());
|
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> {
|
impl<'d> SpiDma<'d, Async> {
|
||||||
/// Converts the SPI instance into async mode.
|
/// Converts the SPI instance into async mode.
|
||||||
#[instability::unstable]
|
#[instability::unstable]
|
||||||
pub fn into_blocking(self) -> SpiDma<'d, Blocking> {
|
pub fn into_blocking(self) -> SpiDma<'d, Blocking> {
|
||||||
|
crate::interrupt::disable(Cpu::current(), self.driver().info.interrupt);
|
||||||
SpiDma {
|
SpiDma {
|
||||||
spi: self.spi,
|
spi: self.spi,
|
||||||
channel: self.channel.into_blocking(),
|
channel: self.channel.into_blocking(),
|
||||||
@ -1448,23 +1479,44 @@ mod dma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_idle_async(&mut self) {
|
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 {
|
if self.rx_transfer_in_progress {
|
||||||
_ = DmaRxFuture::new(&mut self.channel.rx).await;
|
_ = DmaRxFuture::new(&mut self.channel.rx).await;
|
||||||
self.rx_transfer_in_progress = false;
|
self.rx_transfer_in_progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
core::future::poll_fn(|cx| {
|
struct Fut(Driver);
|
||||||
use core::task::Poll;
|
impl Future for Fut {
|
||||||
if self.is_done() {
|
type Output = ();
|
||||||
Poll::Ready(())
|
|
||||||
} else {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
cx.waker().wake_by_ref();
|
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
|
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 {
|
if self.tx_transfer_in_progress {
|
||||||
// In case DMA TX buffer is bigger than what the SPI consumes, stop the DMA.
|
// 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 };
|
let driver = Driver { info, state };
|
||||||
if driver.interrupts().contains(SpiInterrupt::TransferDone) {
|
if driver.interrupts().contains(SpiInterrupt::TransferDone) {
|
||||||
state.waker.wake();
|
|
||||||
driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
|
driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
|
||||||
|
state.waker.wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user