Skip to content

Commit

Permalink
GPIO: prevent woken task interrupting GPIO handler (#2838)
Browse files Browse the repository at this point in the history
* Clear interrupt bit before allowing waker to wake a task

* Add test
  • Loading branch information
bugadani authored Dec 19, 2024
1 parent b8f15f0 commit 9759896
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 3 deletions.
7 changes: 5 additions & 2 deletions esp-hal/src/gpio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,8 +930,11 @@ fn handle_pin_interrupts(user_handler: fn()) {
intr_bits -= 1 << pin_pos;

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);
Expand Down
1 change: 1 addition & 0 deletions esp-hal/src/interrupt/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//! interrupt15() => Priority::Priority15
//! ```
pub(crate) use esp_riscv_rt::riscv::interrupt::free;
pub use esp_riscv_rt::TrapFrame;
use riscv::register::{mcause, mtvec};

Expand Down
1 change: 1 addition & 0 deletions esp-hal/src/interrupt/xtensa.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Interrupt handling
use xtensa_lx::interrupt;
pub(crate) use xtensa_lx::interrupt::free;
use xtensa_lx_rt::exception::Context;

pub use self::vectored::*;
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ where
cfg_if::cfg_if! {
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
xtensa_lx::interrupt::free(|| {
crate::interrupt::free(|| {
*byte = fifo.read().rxfifo_rd_byte().bits();
});
} else {
Expand Down
29 changes: 29 additions & 0 deletions hil-test/tests/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,4 +399,33 @@ mod tests {

_ = 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 {}
}
}

0 comments on commit 9759896

Please sign in to comment.