From dbd4c7dfeac3ddda8cf4742b1b34018deb6dd359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Fri, 1 Oct 2021 14:17:51 +0200 Subject: [PATCH] Implements interrupts for GPIO pins. --- rp2040-hal/src/gpio/mod.rs | 13 +++++ rp2040-hal/src/gpio/pin.rs | 40 ++++++++++++++- rp2040-hal/src/gpio/reg.rs | 99 +++++++++++++++++++++++++++++++++++++- 3 files changed, 148 insertions(+), 4 deletions(-) diff --git a/rp2040-hal/src/gpio/mod.rs b/rp2040-hal/src/gpio/mod.rs index f91af1e..7d543ea 100644 --- a/rp2040-hal/src/gpio/mod.rs +++ b/rp2040-hal/src/gpio/mod.rs @@ -63,6 +63,19 @@ pub enum OutputSlewRate { Fast, } +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +/// Interrupt kind +pub enum Interrupt { + /// While low + LevelLow, + /// While high + LevelHigh, + /// On falling edge + EdgeLow, + /// On rising edge + EdgeHigh, +} + #[derive(Clone, Copy, Eq, PartialEq, Debug)] /// Interrupt override state. pub enum InterruptOverride { diff --git a/rp2040-hal/src/gpio/pin.rs b/rp2040-hal/src/gpio/pin.rs index edf6054..566704d 100644 --- a/rp2040-hal/src/gpio/pin.rs +++ b/rp2040-hal/src/gpio/pin.rs @@ -94,8 +94,8 @@ //! [`AnyKind`]: crate::typelevel#anykind-trait-pattern use super::dynpin::{DynDisabled, DynInput, DynOutput, DynPinId, DynPinMode}; use super::{ - InputOverride, InterruptOverride, OutputDriveStrength, OutputEnableOverride, OutputOverride, - OutputSlewRate, + InputOverride, Interrupt, InterruptOverride, OutputDriveStrength, OutputEnableOverride, + OutputOverride, OutputSlewRate, }; use crate::gpio::reg::RegisterInterface; use crate::typelevel::{Is, NoneT, Sealed}; @@ -547,6 +547,42 @@ where self.regs.write_slew_rate(rate) } + /// Clear interrupt. + #[inline] + pub fn clear_interrupt(&mut self, interrupt: Interrupt) { + self.regs.clear_interrupt(interrupt); + } + + /// Interrupt status. + #[inline] + pub fn interrupt_status(&self, interrupt: Interrupt) -> bool { + self.regs.interrupt_status(interrupt) + } + + /// Is interrupt enabled. + #[inline] + pub fn is_interrupt_enabled(&self, interrupt: Interrupt) -> bool { + self.regs.is_interrupt_enabled(interrupt) + } + + /// Enable or disable interrupt. + #[inline] + pub fn set_interrupt_enabled(&self, interrupt: Interrupt, enabled: bool) { + self.regs.set_interrupt_enabled(interrupt, enabled); + } + + /// Is interrupt forced. + #[inline] + pub fn is_interrupt_forced(&self, interrupt: Interrupt) -> bool { + self.regs.is_interrupt_forced(interrupt) + } + + /// Force or release interrupt. + #[inline] + pub fn set_interrupt_forced(&self, interrupt: Interrupt, forced: bool) { + self.regs.set_interrupt_forced(interrupt, forced); + } + /// Set the interrupt override. #[inline] pub fn set_interrupt_override(&mut self, override_value: InterruptOverride) { diff --git a/rp2040-hal/src/gpio/reg.rs b/rp2040-hal/src/gpio/reg.rs index 451959d..6a5ac78 100644 --- a/rp2040-hal/src/gpio/reg.rs +++ b/rp2040-hal/src/gpio/reg.rs @@ -1,8 +1,8 @@ // Based heavily on and in some places copied from `atsamd-hal` gpio::v2 use super::dynpin::{DynGroup, DynPinId}; use super::{ - InputOverride, InterruptOverride, OutputDriveStrength, OutputEnableOverride, OutputOverride, - OutputSlewRate, + InputOverride, Interrupt, InterruptOverride, OutputDriveStrength, OutputEnableOverride, + OutputOverride, OutputSlewRate, }; use crate::gpio::dynpin::{DynDisabled, DynFunction, DynInput, DynOutput, DynPinMode}; use crate::pac; @@ -255,6 +255,101 @@ pub(super) unsafe trait RegisterInterface { } } + /// Clear interrupt. + #[inline] + fn clear_interrupt(&self, interrupt: Interrupt) { + let num = self.id().num as usize; + unsafe { + let io = &(*pac::IO_BANK0::ptr()); + let reg = (&io.intr0).as_ptr().add(num / 8); + let bit_in_reg = num % 8 * 4 + interrupt as usize; + *reg |= 1 << bit_in_reg; + } + } + + /// Interrupt status. + #[inline] + fn interrupt_status(&self, interrupt: Interrupt) -> bool { + let num = self.id().num as usize; + unsafe { + let cpuid = *(pac::SIO::ptr() as *const u32); + let io = &(*pac::IO_BANK0::ptr()); + let reg = (&io.proc0_ints0) + .as_ptr() + .add(num / 8 + cpuid as usize * 12); + let bit_in_reg = num % 8 * 4 + interrupt as usize; + (*reg & (1 << bit_in_reg)) != 0 + } + } + + /// Is interrupt enabled. + #[inline] + fn is_interrupt_enabled(&self, interrupt: Interrupt) -> bool { + let num = self.id().num as usize; + unsafe { + let cpuid = *(pac::SIO::ptr() as *const u32); + let io = &(*pac::IO_BANK0::ptr()); + let reg = (&io.proc0_inte0) + .as_ptr() + .add(num / 8 + cpuid as usize * 12); + let bit_in_reg = num % 8 * 4 + interrupt as usize; + (*reg & (1 << bit_in_reg)) != 0 + } + } + + /// Enable or disable interrupt. + #[inline] + fn set_interrupt_enabled(&self, interrupt: Interrupt, enabled: bool) { + let num = self.id().num as usize; + unsafe { + let cpuid = *(pac::SIO::ptr() as *const u32); + let io = &(*pac::IO_BANK0::ptr()); + let reg = (&io.proc0_inte0) + .as_ptr() + .add(num / 8 + cpuid as usize * 12); + let bit_in_reg = num % 8 * 4 + interrupt as usize; + if enabled { + *reg |= 1 << bit_in_reg; + } else { + *reg &= !(1 << bit_in_reg); + } + } + } + + /// Is interrupt forced. + #[inline] + fn is_interrupt_forced(&self, interrupt: Interrupt) -> bool { + let num = self.id().num as usize; + unsafe { + let cpuid = *(pac::SIO::ptr() as *const u32); + let io = &(*pac::IO_BANK0::ptr()); + let reg = (&io.proc0_intf0) + .as_ptr() + .add(num / 8 + cpuid as usize * 12); + let bit_in_reg = num % 8 * 4 + interrupt as usize; + (*reg & (1 << bit_in_reg)) != 0 + } + } + + /// Force or release interrupt. + #[inline] + fn set_interrupt_forced(&self, interrupt: Interrupt, forced: bool) { + let num = self.id().num as usize; + unsafe { + let cpuid = *(pac::SIO::ptr() as *const u32); + let io = &(*pac::IO_BANK0::ptr()); + let reg = (&io.proc0_intf0) + .as_ptr() + .add(num / 8 + cpuid as usize * 12); + let bit_in_reg = num % 8 * 4 + interrupt as usize; + if forced { + *reg |= 1 << bit_in_reg; + } else { + *reg &= !(1 << bit_in_reg); + } + } + } + /// Set the interrupt override. #[inline] fn set_interrupt_override(&self, override_value: InterruptOverride) {