GPIO: prevent woken task interrupting GPIO handler (#2838)
* Clear interrupt bit before allowing waker to wake a task * Add test
This commit is contained in:
parent
b8f15f0a8b
commit
97598968eb
@ -930,8 +930,11 @@ fn handle_pin_interrupts(user_handler: fn()) {
|
|||||||
intr_bits -= 1 << pin_pos;
|
intr_bits -= 1 << pin_pos;
|
||||||
|
|
||||||
let pin_nr = pin_pos as u8 + bank.offset();
|
let pin_nr = pin_pos as u8 + bank.offset();
|
||||||
asynch::PIN_WAKERS[pin_nr as usize].wake();
|
|
||||||
set_int_enable(pin_nr, Some(0), 0, false);
|
crate::interrupt::free(|| {
|
||||||
|
asynch::PIN_WAKERS[pin_nr as usize].wake();
|
||||||
|
set_int_enable(pin_nr, Some(0), 0, false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bank.write_interrupt_status_clear(intrs);
|
bank.write_interrupt_status_clear(intrs);
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
//! interrupt15() => Priority::Priority15
|
//! interrupt15() => Priority::Priority15
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
pub(crate) use esp_riscv_rt::riscv::interrupt::free;
|
||||||
pub use esp_riscv_rt::TrapFrame;
|
pub use esp_riscv_rt::TrapFrame;
|
||||||
use riscv::register::{mcause, mtvec};
|
use riscv::register::{mcause, mtvec};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
//! Interrupt handling
|
//! Interrupt handling
|
||||||
|
|
||||||
use xtensa_lx::interrupt;
|
use xtensa_lx::interrupt;
|
||||||
|
pub(crate) use xtensa_lx::interrupt::free;
|
||||||
use xtensa_lx_rt::exception::Context;
|
use xtensa_lx_rt::exception::Context;
|
||||||
|
|
||||||
pub use self::vectored::*;
|
pub use self::vectored::*;
|
||||||
|
|||||||
@ -904,7 +904,7 @@ where
|
|||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(esp32)] {
|
if #[cfg(esp32)] {
|
||||||
// https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/esp32/cpu-subsequent-access-halted-when-get-interrupted.html
|
// https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/esp32/cpu-subsequent-access-halted-when-get-interrupted.html
|
||||||
xtensa_lx::interrupt::free(|| {
|
crate::interrupt::free(|| {
|
||||||
*byte = fifo.read().rxfifo_rd_byte().bits();
|
*byte = fifo.read().rxfifo_rd_byte().bits();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -399,4 +399,33 @@ mod tests {
|
|||||||
|
|
||||||
_ = Input::new(pin, Pull::Down);
|
_ = Input::new(pin, Pull::Down);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn interrupt_executor_is_not_frozen(ctx: Context) {
|
||||||
|
use esp_hal::interrupt::{software::SoftwareInterrupt, Priority};
|
||||||
|
use esp_hal_embassy::InterruptExecutor;
|
||||||
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
|
static INTERRUPT_EXECUTOR: StaticCell<InterruptExecutor<1>> = StaticCell::new();
|
||||||
|
let interrupt_executor = INTERRUPT_EXECUTOR.init(InterruptExecutor::new(unsafe {
|
||||||
|
SoftwareInterrupt::<1>::steal()
|
||||||
|
}));
|
||||||
|
|
||||||
|
let spawner = interrupt_executor.start(Priority::max());
|
||||||
|
|
||||||
|
spawner.must_spawn(test_task(ctx.test_gpio1.degrade()));
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn test_task(pin: AnyPin) {
|
||||||
|
let mut pin = Input::new(pin, Pull::Down);
|
||||||
|
|
||||||
|
// This line must return, even if the executor
|
||||||
|
// is running at a higher priority than the GPIO handler.
|
||||||
|
pin.wait_for_low().await;
|
||||||
|
|
||||||
|
embedded_test::export::check_outcome(());
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user