diff --git a/e310x-hal/CHANGELOG.md b/e310x-hal/CHANGELOG.md index f367300..96e1ab2 100644 --- a/e310x-hal/CHANGELOG.md +++ b/e310x-hal/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Update `e310x` dependency and adapt code +- Add interrupt managing methods to `e310x-hal::gpio` module ## [v0.12.0] - 2024-12-10 diff --git a/e310x-hal/src/device.rs b/e310x-hal/src/device.rs index da0a63f..fb78b4d 100644 --- a/e310x-hal/src/device.rs +++ b/e310x-hal/src/device.rs @@ -1,7 +1,7 @@ //! Device resources available in FE310-G000 and FE310-G002 chip packages use crate::core::CorePeripherals; -use crate::gpio::{gpio0::*, GpioExt, Unknown}; +use crate::gpio::{gpio0::*, EventType, GpioExt, Unknown}; use e310x::{ Aonclk, Backup, Gpio0, Otp, Peripherals, Pmu, Prci, Pwm0, Pwm1, Pwm2, Qspi0, Qspi1, Rtc, Uart0, Wdog, @@ -92,6 +92,117 @@ pub struct DeviceGpioPins { pub pin23: Pin23, } +impl DeviceGpioPins { + /// Enables the specified interrupt event for all the GPIO pins. + /// + /// # Note + /// + /// This function does not enable the interrupts in the PLIC, it only sets the + /// interrupt enable bits in the GPIO peripheral. You must call the + /// [`enable_exti()`](super::gpio::gpio0::Pin0::enable_exti) method of every pin + /// to enable their interrupt in the PLIC. + pub fn enable_interrupts(&mut self, event: EventType) { + let gpio = unsafe { Gpio0::steal() }; + + match event { + EventType::High => { + unsafe { gpio.high_ie().write(|w| w.bits(0xFFFFFFFF)) }; + } + EventType::Low => { + unsafe { gpio.low_ie().write(|w| w.bits(0xFFFFFFFF)) }; + } + EventType::BothLevels => unsafe { + gpio.high_ie().write(|w| w.bits(0xFFFFFFFF)); + gpio.low_ie().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::Rise => { + unsafe { gpio.rise_ie().write(|w| w.bits(0xFFFFFFFF)) }; + } + EventType::Fall => { + unsafe { gpio.fall_ie().write(|w| w.bits(0xFFFFFFFF)) }; + } + EventType::BothEdges => unsafe { + gpio.rise_ie().write(|w| w.bits(0xFFFFFFFF)); + gpio.fall_ie().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::All => unsafe { + gpio.high_ie().write(|w| w.bits(0xFFFFFFFF)); + gpio.low_ie().write(|w| w.bits(0xFFFFFFFF)); + gpio.rise_ie().write(|w| w.bits(0xFFFFFFFF)); + gpio.fall_ie().write(|w| w.bits(0xFFFFFFFF)); + }, + } + } + + /// Disables the specified interrupt event for all the GPIO pins. + pub fn disable_interrupts(&mut self, event: EventType) { + let gpio = unsafe { Gpio0::steal() }; + + match event { + EventType::High => unsafe { + gpio.high_ie().write(|w| w.bits(0x00000000)); + }, + EventType::Low => unsafe { + gpio.low_ie().write(|w| w.bits(0x00000000)); + }, + EventType::BothLevels => unsafe { + gpio.high_ie().write(|w| w.bits(0x00000000)); + gpio.low_ie().write(|w| w.bits(0x00000000)); + }, + EventType::Rise => unsafe { + gpio.rise_ie().write(|w| w.bits(0x00000000)); + }, + EventType::Fall => unsafe { + gpio.fall_ie().write(|w| w.bits(0x00000000)); + }, + EventType::BothEdges => unsafe { + gpio.rise_ie().write(|w| w.bits(0x00000000)); + gpio.fall_ie().write(|w| w.bits(0x00000000)); + }, + EventType::All => unsafe { + gpio.high_ie().write(|w| w.bits(0x00000000)); + gpio.low_ie().write(|w| w.bits(0x00000000)); + gpio.rise_ie().write(|w| w.bits(0x00000000)); + gpio.fall_ie().write(|w| w.bits(0x00000000)); + }, + } + } + + /// Clears the specified interrupt event pending flag for all the GPIO pins. + pub fn clear_interrupts(&mut self, event: EventType) { + let gpio = unsafe { Gpio0::steal() }; + + match event { + EventType::High => unsafe { + gpio.high_ip().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::Low => unsafe { + gpio.low_ip().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::BothLevels => unsafe { + gpio.high_ip().write(|w| w.bits(0xFFFFFFFF)); + gpio.low_ip().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::Rise => unsafe { + gpio.rise_ip().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::Fall => unsafe { + gpio.fall_ip().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::BothEdges => unsafe { + gpio.rise_ip().write(|w| w.bits(0xFFFFFFFF)); + gpio.fall_ip().write(|w| w.bits(0xFFFFFFFF)); + }, + EventType::All => unsafe { + gpio.high_ip().write(|w| w.bits(0xFFFFFFFF)); + gpio.low_ip().write(|w| w.bits(0xFFFFFFFF)); + gpio.rise_ip().write(|w| w.bits(0xFFFFFFFF)); + gpio.fall_ip().write(|w| w.bits(0xFFFFFFFF)); + }, + } + } +} + impl From for DeviceGpioPins { fn from(gpio: Gpio0) -> Self { let parts = gpio.split(); diff --git a/e310x-hal/src/gpio.rs b/e310x-hal/src/gpio.rs index db94e90..9c6ca7e 100644 --- a/e310x-hal/src/gpio.rs +++ b/e310x-hal/src/gpio.rs @@ -4,6 +4,40 @@ use core::marker::PhantomData; use portable_atomic::{AtomicU32, Ordering}; +/// Event Type for GPIO interrupts. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum EventType { + /// High level event + High, + /// Low level event + Low, + /// Rising edge event + Rise, + /// Falling edge event + Fall, + /// Both levels event + /// + /// # Note + /// + /// In the methods that check if an interrupt is enabled or pending, + /// this event type works like an **any** operator between `High` and `Low` events. + BothLevels, + /// Both edges event + /// + /// # Note + /// + /// In the methods that check if an interrupt is enabled or pending, + /// this event type works like an **any** operator between `Rise` and `Fall` events. + BothEdges, + /// All events + /// + /// # Note + /// + /// In the methods that check if an interrupt is enabled or pending, + /// this event type works like an **any** operator between all event types. + All, +} + /// GpioExt trait extends the GPIO0 peripheral. pub trait GpioExt { /// The parts to split the GPIO into. @@ -141,7 +175,7 @@ trait PeripheralAccess { macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, [ - $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+ + $($PXi:ident: ($pxi:ident, $i:expr, $handle:ident, $MODE:ty),)+ ]) => { /// GPIO pub mod $gpiox { @@ -149,9 +183,9 @@ macro_rules! gpio { use core::convert::Infallible; use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin, ErrorType}; - use e310x::$GPIOX; + use e310x::{$GPIOX, Plic, interrupt::{ExternalInterrupt, Priority}}; use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, - NoInvert, Output, PullUp, Regular, PinIndex, PeripheralAccess}; + NoInvert, Output, PullUp, Regular, PinIndex, PeripheralAccess, EventType}; /// GPIO parts for fine grained permission control. pub struct Parts { @@ -276,6 +310,252 @@ macro_rules! gpio { $GPIOX::set_iof_en(Self::INDEX, false); $PXi { _mode: PhantomData } } + + /// Enables the external interrupt source for the pin. + /// + /// # Note + /// + /// This function enables the external interrupt source in the PLIC, + /// but does not enable the PLIC peripheral itself. For more details, + /// refer to the [`e310x::Plic`] documentation. + /// + /// # Safety + /// + /// Enabling an interrupt source can break mask-based critical sections. + pub unsafe fn enable_exti(&mut self, plic: &Plic) { + let ctx = plic.ctx0(); + ctx.enables().enable(ExternalInterrupt::$handle); + } + + /// Disables the external interrupt source for the pin. + pub fn disable_exti(&mut self, plic: &Plic) { + let ctx = plic.ctx0(); + ctx.enables().disable(ExternalInterrupt::$handle); + } + + /// Returns whether the external interrupt source for the pin is enabled. + pub fn is_exti_enabled(&self, plic: &Plic) -> bool { + let ctx = plic.ctx0(); + ctx.enables().is_enabled(ExternalInterrupt::$handle) + } + + /// Sets the external interrupt source priority. + /// + /// # Safety + /// + /// Changing the priority level can break priority-based critical sections. + pub unsafe fn set_exti_priority(&mut self, plic: &Plic, priority: Priority) { + let priorities = plic.priorities(); + priorities.set_priority(ExternalInterrupt::$handle, priority); + } + + /// Returns the external interrupt source priority. + pub fn get_exti_priority(&self, plic: &Plic) -> Priority { + let priorities = plic.priorities(); + priorities.get_priority(ExternalInterrupt::$handle) + } + + /// Enables the selected interrupts for the pin in the interrupt enable registers + /// + /// # Note + /// + /// This function does not enable the interrupt in the PLIC, it only sets the + /// interrupt enable bit in the GPIO peripheral. You must call + /// [`enable_exti()`](Self::enable_exti) to enable the interrupt in + /// the PLIC. + pub fn enable_interrupt(&mut self, event: EventType) { + let gpio_block = $GPIOX::peripheral(); + let pin_mask = 1 << $i; + + match event { + EventType::High => { + unsafe { gpio_block.high_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); } + } + EventType::Low => { + unsafe { gpio_block.low_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); } + } + EventType::BothLevels => { + unsafe { + gpio_block.high_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + gpio_block.low_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + } + } + EventType::Rise => { + unsafe { gpio_block.rise_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); } + } + EventType::Fall => { + unsafe { gpio_block.fall_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); } + } + EventType::BothEdges => { + unsafe { + gpio_block.rise_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + gpio_block.fall_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + } + } + EventType::All => { + unsafe { + gpio_block.high_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + gpio_block.low_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + gpio_block.rise_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + gpio_block.fall_ie().modify(|r, w| w.bits(r.bits() | pin_mask)); + } + } + } + } + + /// Disables the selected interrupts for the pin in the interrupt enable registers + pub fn disable_interrupt(&mut self, event: EventType) { + let gpio_block = $GPIOX::peripheral(); + let pin_mask = 1 << $i; + + match event { + EventType::High => { + unsafe { gpio_block.high_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); } + } + EventType::Low => { + unsafe { gpio_block.low_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); } + } + EventType::BothLevels => { + unsafe { + gpio_block.high_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + gpio_block.low_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + } + } + EventType::Rise => { + unsafe { gpio_block.rise_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); } + } + EventType::Fall => { + unsafe { gpio_block.fall_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); } + } + EventType::BothEdges => { + unsafe { + gpio_block.rise_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + gpio_block.fall_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + } + } + EventType::All => { + unsafe { + gpio_block.high_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + gpio_block.low_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + gpio_block.rise_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + gpio_block.fall_ie().modify(|r, w| w.bits(r.bits() & !pin_mask)); + } + } + } + } + + /// Clears pending interrupts for the selected pin interrupts. + pub fn clear_interrupt(&mut self, event: EventType) { + let gpio_block = $GPIOX::peripheral(); + let pin_mask = 1 << $i; + + match event { + EventType::High => { + unsafe { gpio_block.high_ip().write(|w| w.bits(pin_mask)); } + } + EventType::Low => { + unsafe { gpio_block.low_ip().write(|w| w.bits(pin_mask)); } + } + EventType::BothLevels => { + unsafe { + gpio_block.high_ip().write(|w| w.bits(pin_mask)); + gpio_block.low_ip().write(|w| w.bits(pin_mask)); + } + } + EventType::Rise => { + unsafe { gpio_block.rise_ip().write(|w| w.bits(pin_mask)); } + } + EventType::Fall => { + unsafe { gpio_block.fall_ip().write(|w| w.bits(pin_mask)); } + } + EventType::BothEdges => { + unsafe { + gpio_block.rise_ip().write(|w| w.bits(pin_mask)); + gpio_block.fall_ip().write(|w| w.bits(pin_mask)); + } + } + EventType::All => { + unsafe { + gpio_block.high_ip().write(|w| w.bits(pin_mask)); + gpio_block.low_ip().write(|w| w.bits(pin_mask)); + gpio_block.rise_ip().write(|w| w.bits(pin_mask)); + gpio_block.fall_ip().write(|w| w.bits(pin_mask)); + } + } + } + } + + /// Returns true if the interrupt for the pin is enabled. + /// + /// # Note + /// + /// [EventType::BothEdges] will return true if either the + /// rising or falling edge interrupts are enabled, + /// [EventType::BothLevels] will return true if either the + /// high or low level interrupts are enabled + /// and [EventType::All] will return true if any of the + /// interrupts are enabled. + pub fn is_interrupt_enabled(&self, event: EventType) -> bool { + let gpio_block = $GPIOX::peripheral(); + let pin_mask = 1 << $i; + + match event { + EventType::High => gpio_block.high_ie().read().bits() & pin_mask != 0, + EventType::Low => gpio_block.low_ie().read().bits() & pin_mask != 0, + EventType::BothLevels => { + (gpio_block.high_ie().read().bits() & pin_mask != 0) || + (gpio_block.low_ie().read().bits() & pin_mask != 0) + } + EventType::Rise => gpio_block.rise_ie().read().bits() & pin_mask != 0, + EventType::Fall => gpio_block.fall_ie().read().bits() & pin_mask != 0, + EventType::BothEdges => { + (gpio_block.rise_ie().read().bits() & pin_mask != 0) || + (gpio_block.fall_ie().read().bits() & pin_mask != 0) + } + EventType::All => { + (gpio_block.high_ie().read().bits() & pin_mask != 0) || + (gpio_block.low_ie().read().bits() & pin_mask != 0) || + (gpio_block.rise_ie().read().bits() & pin_mask != 0) || + (gpio_block.fall_ie().read().bits() & pin_mask != 0) + } + } + } + + /// Returns true if the interrupt for the pin is pending. + /// + /// # Note + /// + /// [EventType::BothEdges] will return true if either the + /// rising or falling edge interrupts are pending, + /// [EventType::BothLevels] will return true if either the + /// high or low level interrupts are pending + /// and [EventType::All] will return true if any of the + /// interrupts are pending. + pub fn is_interrupt_pending(&self, event: EventType) -> bool { + let gpio_block = $GPIOX::peripheral(); + let pin_mask = 1 << $i; + + match event { + EventType::High => gpio_block.high_ip().read().bits() & pin_mask != 0, + EventType::Low => gpio_block.low_ip().read().bits() & pin_mask != 0, + EventType::BothLevels => { + (gpio_block.high_ip().read().bits() & pin_mask != 0) || + (gpio_block.low_ip().read().bits() & pin_mask != 0) + } + EventType::Rise => gpio_block.rise_ip().read().bits() & pin_mask != 0, + EventType::Fall => gpio_block.fall_ip().read().bits() & pin_mask != 0, + EventType::BothEdges => { + (gpio_block.rise_ip().read().bits() & pin_mask != 0) || + (gpio_block.fall_ip().read().bits() & pin_mask != 0) + } + EventType::All => { + (gpio_block.high_ip().read().bits() & pin_mask != 0) || + (gpio_block.low_ip().read().bits() & pin_mask != 0) || + (gpio_block.rise_ip().read().bits() & pin_mask != 0) || + (gpio_block.fall_ip().read().bits() & pin_mask != 0) + } + } + } } impl ErrorType for $PXi> { @@ -338,36 +618,36 @@ macro_rules! gpio { // * bootloader may reconfigure some GPIOs // * we do not enforce any specific state in `split()` gpio!(Gpio0, gpio0, [ - Pin0: (pin0, 0, Unknown), - Pin1: (pin1, 1, Unknown), - Pin2: (pin2, 2, Unknown), - Pin3: (pin3, 3, Unknown), - Pin4: (pin4, 4, Unknown), - Pin5: (pin5, 5, Unknown), - Pin6: (pin6, 6, Unknown), - Pin7: (pin7, 7, Unknown), - Pin8: (pin8, 8, Unknown), - Pin9: (pin9, 9, Unknown), - Pin10: (pin10, 10, Unknown), - Pin11: (pin11, 11, Unknown), - Pin12: (pin12, 12, Unknown), - Pin13: (pin13, 13, Unknown), - Pin14: (pin14, 14, Unknown), - Pin15: (pin15, 15, Unknown), - Pin16: (pin16, 16, Unknown), - Pin17: (pin17, 17, Unknown), - Pin18: (pin18, 18, Unknown), - Pin19: (pin19, 19, Unknown), - Pin20: (pin20, 20, Unknown), - Pin21: (pin21, 21, Unknown), - Pin22: (pin22, 22, Unknown), - Pin23: (pin23, 23, Unknown), - Pin24: (pin24, 24, Unknown), - Pin25: (pin25, 25, Unknown), - Pin26: (pin26, 26, Unknown), - Pin27: (pin27, 27, Unknown), - Pin28: (pin28, 28, Unknown), - Pin29: (pin29, 29, Unknown), - Pin30: (pin30, 30, Unknown), - Pin31: (pin31, 31, Unknown), + Pin0: (pin0, 0, GPIO0, Unknown), + Pin1: (pin1, 1, GPIO1, Unknown), + Pin2: (pin2, 2, GPIO2, Unknown), + Pin3: (pin3, 3, GPIO3, Unknown), + Pin4: (pin4, 4, GPIO4, Unknown), + Pin5: (pin5, 5, GPIO5, Unknown), + Pin6: (pin6, 6, GPIO6, Unknown), + Pin7: (pin7, 7, GPIO7, Unknown), + Pin8: (pin8, 8, GPIO8, Unknown), + Pin9: (pin9, 9, GPIO9, Unknown), + Pin10: (pin10, 10, GPIO10, Unknown), + Pin11: (pin11, 11, GPIO11, Unknown), + Pin12: (pin12, 12, GPIO12, Unknown), + Pin13: (pin13, 13, GPIO13, Unknown), + Pin14: (pin14, 14, GPIO14, Unknown), + Pin15: (pin15, 15, GPIO15, Unknown), + Pin16: (pin16, 16, GPIO16, Unknown), + Pin17: (pin17, 17, GPIO17, Unknown), + Pin18: (pin18, 18, GPIO18, Unknown), + Pin19: (pin19, 19, GPIO19, Unknown), + Pin20: (pin20, 20, GPIO20, Unknown), + Pin21: (pin21, 21, GPIO21, Unknown), + Pin22: (pin22, 22, GPIO22, Unknown), + Pin23: (pin23, 23, GPIO23, Unknown), + Pin24: (pin24, 24, GPIO24, Unknown), + Pin25: (pin25, 25, GPIO25, Unknown), + Pin26: (pin26, 26, GPIO26, Unknown), + Pin27: (pin27, 27, GPIO27, Unknown), + Pin28: (pin28, 28, GPIO28, Unknown), + Pin29: (pin29, 29, GPIO29, Unknown), + Pin30: (pin30, 30, GPIO30, Unknown), + Pin31: (pin31, 31, GPIO31, Unknown), ]); diff --git a/hifive1-examples/examples/button_interrupt.rs b/hifive1-examples/examples/button_interrupt.rs index 487f1b1..68dc022 100644 --- a/hifive1-examples/examples/button_interrupt.rs +++ b/hifive1-examples/examples/button_interrupt.rs @@ -2,28 +2,41 @@ #![no_main] #![no_std] +use core::cell::RefCell; +use critical_section::Mutex; use hifive1::{ clock, - hal::DeviceResources, - hal::{e310x::Gpio0, prelude::*}, + hal::{ + gpio::{gpio0, EventType, Input, PullUp}, + prelude::*, + DeviceResources, + }, pin, sprintln, stdout, Led, }; extern crate panic_halt; +static BUTTON: Mutex>>>> = Mutex::new(RefCell::new(None)); + /* Handler for the GPIO9 interrupt */ #[riscv_rt::external_interrupt(ExternalInterrupt::GPIO9)] fn gpio9_handler() { sprintln!("GPIO9 interrupt!"); - // Clear the GPIO pending interrupt - let gpio_block = unsafe { Gpio0::steal() }; - let _prev_fall = gpio_block.fall_ip().read().pin9().bit_is_set(); - let _prev_rise = gpio_block.rise_ip().read().pin9().bit_is_set(); - // Clear the interrupt by writing 1 to the pending bit - gpio_block.fall_ip().write(|w| w.pin9().set_bit()); - gpio_block.rise_ip().write(|w| w.pin9().set_bit()); - let _post_fall = gpio_block.fall_ip().read().pin9().bit_is_set(); - let _post_rise = gpio_block.rise_ip().read().pin9().bit_is_set(); - let _ok = _prev_fall || _prev_rise; // Ensure we cleared the interrupt + // Take the button + critical_section::with(|cs| { + let mut button_ref = BUTTON.borrow_ref_mut(cs); + let button = button_ref.as_mut().unwrap(); + + // Check the interrupt source + if button.is_interrupt_pending(EventType::Rise) { + sprintln!("Rising Edge"); + } + if button.is_interrupt_pending(EventType::Fall) { + sprintln!("Falling Edge"); + } + + // Clear the interrupt + button.clear_interrupt(EventType::BothEdges); + }); } #[riscv_rt::entry] @@ -31,11 +44,15 @@ fn main() -> ! { let dr = DeviceResources::take().unwrap(); let cp = dr.core_peripherals; let p = dr.peripherals; - let pins = dr.pins; + let mut pins = dr.pins; // Configure clocks let clocks = clock::configure(p.PRCI, p.AONCLK, 320.mhz().into()); + // Disable and clear all GPIO interrupts + pins.disable_interrupts(EventType::All); + pins.clear_interrupts(EventType::All); + // Configure UART for stdout stdout::configure( p.UART0, @@ -46,47 +63,60 @@ fn main() -> ! { ); sprintln!("Configuring GPIOs..."); + // Configure button pin (GPIO9) as pull-up input let mut button = pins.pin9.into_pull_up_input(); // Configure blue LED pin (GPIO21) as inverted output let mut led = pin!(pins, led_blue).into_inverted_output(); sprintln!("Configuring external interrupts..."); - // Set button interrupt source priority + + // Make sure interrupts are disabled + riscv::interrupt::disable(); + + // Reset PLIC interrupts and set priority threshold let plic = cp.plic; let priorities = plic.priorities(); + let ctx = plic.ctx0(); priorities.reset::(); - unsafe { priorities.set_priority(ExternalInterrupt::GPIO9, Priority::P1) }; + unsafe { + ctx.enables().disable_all::(); + ctx.threshold().set_threshold(Priority::P0); + } // Enable GPIO9 interrupt for both edges - let gpio_block = unsafe { Gpio0::steal() }; + button.enable_interrupt(EventType::BothEdges); unsafe { - // Clear pending interrupts from previous states - gpio_block.low_ie().write(|w| w.bits(0x00000000)); - gpio_block.high_ie().write(|w| w.bits(0x00000000)); - gpio_block.fall_ie().write(|w| w.bits(0x00000000)); - gpio_block.rise_ie().write(|w| w.bits(0x00000000)); - gpio_block.low_ip().write(|w| w.bits(0xffffffff)); - gpio_block.high_ip().write(|w| w.bits(0xffffffff)); - gpio_block.fall_ip().write(|w| w.bits(0xffffffff)); - gpio_block.rise_ip().write(|w| w.bits(0xffffffff)); + button.set_exti_priority(&plic, Priority::P1); + button.enable_exti(&plic); } - gpio_block.fall_ie().write(|w| w.pin9().set_bit()); - gpio_block.rise_ie().write(|w| w.pin9().set_bit()); + + // Store button pin in a shared resource + critical_section::with(|cs| { + BUTTON.borrow(cs).replace(Some(button)); + }); sprintln!("Enabling external interrupts..."); - // Enable GPIO9 interrupt in PLIC - let ctx = plic.ctx0(); + + // Enable global interrupts unsafe { - ctx.enables().disable_all::(); - ctx.threshold().set_threshold(Priority::P0); - ctx.enables().enable(ExternalInterrupt::GPIO9); riscv::interrupt::enable(); plic.enable(); } loop { - if button.is_low().unwrap() { + // Check if the button is low + let mut button_state = false; + critical_section::with(|cs| { + button_state = BUTTON + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .is_low() + .unwrap(); + }); + + if button_state { sprintln!("Button pressed"); led.on(); } else {