use crate::gpio;
use crate::syscfg::Syscfg;
use crate::pac::{self, EXTI};
pub trait ExtiExt {
fn constrain(self) -> ExternalInterrupts;
}
pub struct Exti<E: ExternalInterrupt> {
ei: E,
}
impl<E: ExternalInterrupt> Exti<E> {
pub fn bind<GP>(&mut self, pin: GP, syscfg: &mut Syscfg)
where GP: gpio::GPIOPin + hal::digital::v2::InputPin
{
let exti = unsafe { &(*EXTI::ptr()) };
let group_bits = bits_of_gpio_group(&pin.group());
match self.ei.enumeration() {
ExtIn::EXTI0 => {
syscfg.exticr1()
.modify(|_, w| unsafe { w.exti0().bits(group_bits) });
}
ExtIn::EXTI1 => {
syscfg.exticr1()
.modify(|_, w| unsafe { w.exti1().bits(group_bits) });
}
ExtIn::EXTI2 => {
syscfg.exticr1()
.modify(|_, w| unsafe { w.exti2().bits(group_bits) });
}
ExtIn::EXTI3 => {
syscfg.exticr1()
.modify(|_, w| unsafe { w.exti3().bits(group_bits) });
}
ExtIn::EXTI4 => {
syscfg.exticr2()
.modify(|_, w| unsafe { w.exti4().bits(group_bits) });
}
ExtIn::EXTI13 => {
syscfg.exticr4()
.modify(|_, w| unsafe { w.exti13().bits(group_bits) });
}
}
let offset = pin.index() as u32;
exti.imr1.modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1 << offset)) | (1 << offset))
});
exti.emr1.modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1 << offset)) | (1 << offset))
});
exti.rtsr1.modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1 << offset)) | (1 << offset))
});
}
pub fn unpend(&mut self) {
let mask: bool = true;
let offset: u8 = self.ei.index();
let exti = unsafe { &(*EXTI::ptr()) };
exti.pr1.modify(|r, w| unsafe {
w.bits((r.bits() & !((mask as u32) << offset))
| (((true & mask) as u32) << offset))
});
}
}
#[doc(hidden)]
pub trait ExternalInterrupt: private::Sealed {
#[doc(hidden)]
fn interrupt(&self) -> pac::Interrupt;
#[doc(hidden)]
fn enumeration(&self) -> ExtIn;
#[doc(hidden)]
fn index(&self) -> u8;
}
#[doc(hidden)]
pub enum ExtIn {
EXTI0,
EXTI1,
EXTI2,
EXTI3,
EXTI4,
EXTI13,
}
macro_rules! gen_exti {
([$(($name:ident, $exti:ident, $i: expr),)+]) => {
#[doc(hidden)]
mod private {
#[doc(hidden)]
pub trait Sealed {}
$(
impl Sealed for super::$name {}
)+
}
$(
pub struct $name {
_0: (),
}
impl ExternalInterrupt for $name {
fn interrupt(&self) -> pac::Interrupt {
pac::Interrupt::$exti
}
fn enumeration(&self) -> ExtIn {
ExtIn::$name
}
fn index(&self) -> u8 {
$i
}
}
)+
#[allow(non_snake_case)]
pub struct ExternalInterrupts {
$(
pub $name: Exti<$name>,
)+
}
impl ExtiExt for EXTI {
fn constrain(self) -> ExternalInterrupts {
(
ExternalInterrupts {
$(
$name: Exti { ei: $name { _0: () }} ,
)+
}
)
}
}
}
}
gen_exti!([(EXTI0, EXTI0, 0),
(EXTI1, EXTI1, 1),
(EXTI2, EXTI2_TSC, 2),
(EXTI3, EXTI3, 2),
(EXTI4, EXTI4, 4),
(EXTI13, EXTI15_10, 13),]);
fn bits_of_gpio_group(group: &gpio::Group) -> u8 {
match group {
gpio::Group::A => 0b0000,
gpio::Group::B => 0b0001,
gpio::Group::C => 0b0010,
gpio::Group::D => 0b0011,
gpio::Group::E => 0b0100,
gpio::Group::F => 0b0101,
gpio::Group::G => 0b0110,
}
}