From f7311d860f8c225e8777422cd98d04b6f9bd147b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Apr 2026 10:04:27 +0200 Subject: [PATCH] possible bugfix for asynch GPIO --- .../examples/embassy/src/bin/async-gpio.rs | 10 ++++- vorago-shared-hal/src/gpio/asynch.rs | 41 +++++++++---------- vorago-shared-hal/src/gpio/ll.rs | 10 +++++ vorago-shared-hal/src/gpio/mod.rs | 5 +++ vorago-shared-hal/src/gpio/regs.rs | 1 - vorago-shared-hal/src/lib.rs | 2 +- 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/va108xx/examples/embassy/src/bin/async-gpio.rs b/va108xx/examples/embassy/src/bin/async-gpio.rs index 537ccd4..edd23b6 100644 --- a/va108xx/examples/embassy/src/bin/async-gpio.rs +++ b/va108xx/examples/embassy/src/bin/async-gpio.rs @@ -71,8 +71,14 @@ async fn main(spawner: Spawner) { let out_pb22 = Output::new(portb.pb22, PinState::Low); let in_pb23 = Input::new_floating(portb.pb23); - let mut in_pa1_async = InputPinAsync::new(in_pa1, pac::Interrupt::OC10); - let mut in_pb23_async = InputPinAsync::new(in_pb23, PB22_TO_PB23_IRQ); + let mut in_pa1_async = InputPinAsync::new( + in_pa1, + va108xx_hal::InterruptConfig::new(pac::Interrupt::OC10, true, true), + ); + let mut in_pb23_async = InputPinAsync::new( + in_pb23, + va108xx_hal::InterruptConfig::new(PB22_TO_PB23_IRQ, true, true), + ); spawner .spawn(output_task( diff --git a/vorago-shared-hal/src/gpio/asynch.rs b/vorago-shared-hal/src/gpio/asynch.rs index 5531bb5..d419d37 100644 --- a/vorago-shared-hal/src/gpio/asynch.rs +++ b/vorago-shared-hal/src/gpio/asynch.rs @@ -21,9 +21,6 @@ use crate::{InterruptConfig, NUM_PORT_A, NUM_PORT_B}; #[cfg(feature = "vor4x")] use super::ll::PortDoesNotSupportInterrupts; -#[cfg(feature = "vor1x")] -use va108xx as pac; - pub use super::ll::InterruptEdge; use super::{ Input, Port, @@ -118,10 +115,13 @@ pub fn on_interrupt_for_async_gpio_for_port( } fn on_interrupt_for_async_gpio_for_port_generic(port: Port) { - let gpio = unsafe { port.steal_gpio() }; + let mut gpio = unsafe { port.steal_regs() }; let irq_enb = gpio.read_irq_enable(); let edge_status = gpio.read_edge_status(); + // Clear the edge status event. We have the relevant copy now. + gpio.write_edge_status(edge_status); + let (wakers, edge_detection) = pin_group_to_waker_and_edge_detection_group(port); on_interrupt_for_port(irq_enb, edge_status, wakers, edge_detection); @@ -134,14 +134,16 @@ fn on_interrupt_for_port( wakers: &'static [AtomicWaker], edge_detection: &'static [AtomicBool], ) { + // Check all enabled interrupts. while irq_enb != 0 { + // For all enabled interrupts, check whether the corresponding edge detection has + // triggered. let bit_pos = irq_enb.trailing_zeros() as usize; let bit_mask = 1 << bit_pos; - wakers[bit_pos].wake(); - if edge_status & bit_mask != 0 { edge_detection[bit_pos].store(true, core::sync::atomic::Ordering::Relaxed); + wakers[bit_pos].wake(); // Clear the processed bit irq_enb &= !bit_mask; @@ -163,13 +165,11 @@ pub struct InputPinFuture { impl InputPinFuture { /// Create a new input pin future from mutable reference to an [Input] pin. #[cfg(feature = "vor1x")] - pub fn new_with_input_pin(pin: &mut Input, irq: pac::Interrupt, edge: InterruptEdge) -> Self { + pub fn new_with_input_pin(pin: &mut Input, edge: InterruptEdge) -> Self { let (waker_group, edge_detection_group) = pin_group_to_waker_and_edge_detection_group(pin.id().port()); edge_detection_group[pin.id().offset()].store(false, core::sync::atomic::Ordering::Relaxed); pin.configure_edge_interrupt(edge); - #[cfg(feature = "vor1x")] - pin.enable_interrupt(InterruptConfig::new(irq, true, true)); Self { id: pin.id(), waker_group, @@ -223,8 +223,6 @@ impl Future for InputPinFuture { /// Input pin which has additional asynchronous support. pub struct InputPinAsync { pin: Input, - #[cfg(feature = "vor1x")] - irq: va108xx::Interrupt, } impl InputPinAsync { @@ -235,8 +233,10 @@ impl InputPinAsync { /// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function /// for the asynchronous functionality to work. #[cfg(feature = "vor1x")] - pub fn new(pin: Input, irq: va108xx::Interrupt) -> Self { - Self { pin, irq } + pub fn new(mut pin: Input, irq_config: InterruptConfig) -> Self { + pin.enable_interrupt(irq_config); + pin.clear_edge_event(); + Self { pin } } /// Create a new asynchronous input pin from an [Input] pin. The interrupt ID to be used must be @@ -246,10 +246,11 @@ impl InputPinAsync { /// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function /// for the asynchronous functionality to work. #[cfg(feature = "vor4x")] - pub fn new(pin: Input) -> Result { + pub fn new(mut pin: Input) -> Result { if pin.id().port() == Port::G { return Err(PortDoesNotSupportInterrupts); } + pin.clear_edge_event(); Ok(Self { pin }) } @@ -259,8 +260,7 @@ impl InputPinAsync { pub async fn wait_for_high(&mut self) { // Unwrap okay, checked pin in constructor. #[cfg(feature = "vor1x")] - let fut = - InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh); + let fut = InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::LowToHigh); #[cfg(feature = "vor4x")] let fut = InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::LowToHigh).unwrap(); @@ -300,8 +300,7 @@ impl InputPinAsync { pub async fn wait_for_low(&mut self) { // Unwrap okay, checked pin in constructor. #[cfg(feature = "vor1x")] - let fut = - InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow); + let fut = InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow); #[cfg(feature = "vor4x")] let fut = InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow).unwrap(); @@ -315,7 +314,7 @@ impl InputPinAsync { pub async fn wait_for_falling_edge(&mut self) { // Unwrap okay, checked pin in constructor. #[cfg(feature = "vor1x")] - InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow).await; + InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow).await; #[cfg(feature = "vor4x")] InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::HighToLow) .unwrap() @@ -326,14 +325,14 @@ impl InputPinAsync { pub async fn wait_for_rising_edge(&mut self) { // Unwrap okay, checked pin in constructor. #[cfg(feature = "vor1x")] - InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh).await; + InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::LowToHigh).await; } /// Asynchronously wait until the pin sees any edge (either rising or falling). pub async fn wait_for_any_edge(&mut self) { // Unwrap okay, checked pin in constructor. #[cfg(feature = "vor1x")] - InputPinFuture::new_with_input_pin(&mut self.pin, self.irq, InterruptEdge::BothEdges).await; + InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::BothEdges).await; #[cfg(feature = "vor4x")] InputPinFuture::new_with_input_pin(&mut self.pin, InterruptEdge::BothEdges) .unwrap() diff --git a/vorago-shared-hal/src/gpio/ll.rs b/vorago-shared-hal/src/gpio/ll.rs index 0389cb2..b42cbb7 100644 --- a/vorago-shared-hal/src/gpio/ll.rs +++ b/vorago-shared-hal/src/gpio/ll.rs @@ -384,6 +384,16 @@ impl LowLevelGpio { self.gpio.write_tog_out(self.mask_32()); } + #[inline] + pub fn clear_edge_event(&mut self) { + // Clear any pending edge events. + let mask = self.mask_32(); + self.gpio.modify_edge_status(|mut val| { + val &= !mask; + val + }); + } + #[cfg(feature = "vor1x")] pub fn enable_interrupt(&mut self, irq_cfg: crate::InterruptConfig) { if irq_cfg.route { diff --git a/vorago-shared-hal/src/gpio/mod.rs b/vorago-shared-hal/src/gpio/mod.rs index 286b22b..cdf1a22 100644 --- a/vorago-shared-hal/src/gpio/mod.rs +++ b/vorago-shared-hal/src/gpio/mod.rs @@ -162,6 +162,11 @@ impl Input { self.0.configure_delay(delay_1, delay_2); } + #[inline] + pub fn clear_edge_event(&mut self) { + self.0.clear_edge_event(); + } + #[inline] pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClockSelect) { self.0.configure_filter_type(filter, clksel); diff --git a/vorago-shared-hal/src/gpio/regs.rs b/vorago-shared-hal/src/gpio/regs.rs index e0ae9db..556b3e1 100644 --- a/vorago-shared-hal/src/gpio/regs.rs +++ b/vorago-shared-hal/src/gpio/regs.rs @@ -58,7 +58,6 @@ pub struct Gpio { /// Read-only register which shows enabled and active interrupts. Called IRQ_end by Vorago. #[mmio(PureRead)] irq_status: u32, - #[mmio(PureRead)] edge_status: u32, #[cfg(feature = "vor1x")] diff --git a/vorago-shared-hal/src/lib.rs b/vorago-shared-hal/src/lib.rs index 36d316e..b188c7d 100644 --- a/vorago-shared-hal/src/lib.rs +++ b/vorago-shared-hal/src/lib.rs @@ -137,7 +137,7 @@ impl Port { /// # Safety /// /// Circumvents ownership and safety guarantees by the HAL. - pub unsafe fn steal_gpio(&self) -> gpio::regs::MmioGpio<'static> { + pub unsafe fn steal_regs(&self) -> gpio::regs::MmioGpio<'static> { gpio::regs::Gpio::new_mmio(*self) } }