Implements interrupts for GPIO pins.

This commit is contained in:
Alexander Meißner 2021-10-01 14:17:51 +02:00
parent da89888ccb
commit dbd4c7dfea
3 changed files with 148 additions and 4 deletions

View file

@ -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 {

View file

@ -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) {

View file

@ -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) {