use crate::gpio::Pin;
use crate::pac;
use crate::syscfg::Syscfg;
pub struct PinSrc;
pub struct InternalSrc;
pub trait ExtiConfigured {}
impl ExtiConfigured for InternalSrc {}
const PA_SS_CODE: u8 = 0b000;
const PB_SS_CODE: u8 = 0b001;
const PC_SS_CODE: u8 = 0b010;
const PF_SS_CODE: u8 = 0b101;
const fn ss_code(port: char) -> u8 {
match port {
'A' => PA_SS_CODE,
'B' => PB_SS_CODE,
'C' => PC_SS_CODE,
'F' => PF_SS_CODE,
_ => unreachable!(),
}
}
pub trait ExtiPin: ExtiConfigured {
const SS_CODE: u8;
}
macro_rules! exti_pin {
() => {};
( $(#[$cfg:meta])? $p:literal $n:literal $(, $($rest:tt)*)? ) => {
$(#[$cfg])?
#[doc = concat!("`P", $p, stringify!($n), "` on EXTI line ", stringify!($n), ".")]
impl<MODE> ExtiPin for Pin<$p, $n, MODE> {
const SS_CODE: u8 = ss_code($p);
}
$(#[$cfg])?
impl<MODE> ExtiConfigured for Pin<$p, $n, MODE> {}
$( exti_pin! { $($rest)* } )?
};
}
exti_pin! {
'A' 0, 'A' 1, 'A' 2, 'A' 3, 'A' 4, 'A' 5, 'A' 6, 'A' 7,
#[cfg(pads_ge_24)] 'A' 8,
'A' 9, 'A' 10,
#[cfg(pads_ge_lqfp32)] 'A' 11,
#[cfg(pads_ge_lqfp32)] 'A' 12,
'A' 13, 'A' 14,
#[cfg(pads_ge_28)] 'A' 15,
#[cfg(pads_ge_24)] 'B' 0,
'B' 1,
#[cfg(pads_ge_qfn32)] 'B' 2,
#[cfg(pads_ge_28)] 'B' 3,
#[cfg(pads_ge_28)] 'B' 4,
#[cfg(pads_ge_28)] 'B' 5,
#[cfg(pads_ge_24)] 'B' 6,
#[cfg(pads_ge_24)] 'B' 7,
#[cfg(pads_ge_qfn32)] 'B' 8,
#[cfg(pads_ge_48)] 'B' 9,
#[cfg(pads_ge_48)] 'B' 10,
#[cfg(pads_ge_48)] 'B' 11,
#[cfg(pads_ge_48)] 'B' 12,
#[cfg(pads_ge_48)] 'B' 13,
#[cfg(pads_ge_48)] 'B' 14,
#[cfg(pads_ge_48)] 'B' 15,
#[cfg(pads_ge_48)] 'C' 13,
#[cfg(pads_ge_48)] 'C' 14,
#[cfg(pads_ge_48)] 'C' 15,
'F' 0, 'F' 1,
#[cfg(pads_ge_48)] 'F' 6,
#[cfg(pads_ge_48)] 'F' 7,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EdgeTrigger {
None,
Rising,
Falling,
Both,
}
pub struct ExtiLine<const N: u8, SRC> {
src: SRC,
}
impl<const N: u8, SRC> ExtiLine<N, SRC> {
#[allow(clippy::unused_self)]
fn reg(&self) -> &pac::exti::RegisterBlock {
unsafe { &*pac::Exti::ptr() }
}
}
impl<const N: u8> ExtiLine<N, PinSrc> {
pub fn source<const P: char, MODE>(
self,
syscfg: &mut Syscfg,
pin: Pin<P, N, MODE>,
) -> ExtiLine<N, Pin<P, N, MODE>>
where
Pin<P, N, MODE>: ExtiPin,
{
syscfg.set_extiss(N, <Pin<P, N, MODE> as ExtiPin>::SS_CODE);
ExtiLine { src: pin }
}
}
impl<const N: u8, SRC> ExtiLine<N, SRC>
where
SRC: ExtiConfigured,
{
const MASK: u32 = 1 << N;
const fn with_bit(bits: u32, on: bool) -> u32 {
if on {
bits | Self::MASK
} else {
bits & !Self::MASK
}
}
fn set_rten(&mut self, on: bool) {
self.reg()
.rten()
.modify(|r, w| unsafe { w.bits(Self::with_bit(r.bits(), on)) });
}
fn set_ften(&mut self, on: bool) {
self.reg()
.ften()
.modify(|r, w| unsafe { w.bits(Self::with_bit(r.bits(), on)) });
}
fn set_inten(&mut self, on: bool) {
self.reg()
.inten()
.modify(|r, w| unsafe { w.bits(Self::with_bit(r.bits(), on)) });
}
fn set_even(&mut self, on: bool) {
self.reg()
.even()
.modify(|r, w| unsafe { w.bits(Self::with_bit(r.bits(), on)) });
}
pub fn edge(&mut self, edge: EdgeTrigger) {
let (rising, falling) = match edge {
EdgeTrigger::None => (false, false),
EdgeTrigger::Rising => (true, false),
EdgeTrigger::Falling => (false, true),
EdgeTrigger::Both => (true, true),
};
self.set_rten(rising);
self.set_ften(falling);
}
pub fn listen(&mut self) {
self.set_inten(true);
}
pub fn unlisten(&mut self) {
self.set_inten(false);
}
pub fn is_listening(&self) -> bool {
self.reg().inten().read().bits() & Self::MASK != 0
}
pub fn listen_event(&mut self) {
self.set_even(true);
}
pub fn unlisten_event(&mut self) {
self.set_even(false);
}
pub fn is_listening_event(&self) -> bool {
self.reg().even().read().bits() & Self::MASK != 0
}
pub fn pend(&mut self) {
self.reg()
.swiev()
.modify(|r, w| unsafe { w.bits(Self::with_bit(r.bits(), true)) });
}
pub fn is_pending(&self) -> bool {
self.reg().pd().read().bits() & Self::MASK != 0
}
pub fn clear_interrupt(&mut self) {
self.reg().pd().write(|w| unsafe { w.bits(Self::MASK) });
}
}
impl<const P: char, const N: u8, MODE> ExtiLine<N, Pin<P, N, MODE>> {
pub fn pin(&self) -> &Pin<P, N, MODE> {
&self.src
}
pub fn pin_mut(&mut self) -> &mut Pin<P, N, MODE> {
&mut self.src
}
pub fn release(mut self) -> (ExtiLine<N, PinSrc>, Pin<P, N, MODE>)
where
Pin<P, N, MODE>: ExtiConfigured,
{
self.edge(EdgeTrigger::None);
self.unlisten();
self.unlisten_event();
self.clear_interrupt();
(ExtiLine { src: PinSrc }, self.src)
}
}
#[allow(missing_docs)]
pub struct ExtiLines {
pub line0: ExtiLine<0, PinSrc>,
pub line1: ExtiLine<1, PinSrc>,
pub line2: ExtiLine<2, PinSrc>,
pub line3: ExtiLine<3, PinSrc>,
pub line4: ExtiLine<4, PinSrc>,
pub line5: ExtiLine<5, PinSrc>,
pub line6: ExtiLine<6, PinSrc>,
pub line7: ExtiLine<7, PinSrc>,
pub line8: ExtiLine<8, PinSrc>,
pub line9: ExtiLine<9, PinSrc>,
pub line10: ExtiLine<10, PinSrc>,
pub line11: ExtiLine<11, PinSrc>,
pub line12: ExtiLine<12, PinSrc>,
pub line13: ExtiLine<13, PinSrc>,
pub line14: ExtiLine<14, PinSrc>,
pub line15: ExtiLine<15, PinSrc>,
pub line16: ExtiLine<16, InternalSrc>,
pub line17: ExtiLine<17, InternalSrc>,
pub line19: ExtiLine<19, InternalSrc>,
pub line21: ExtiLine<21, InternalSrc>,
pub line25: ExtiLine<25, InternalSrc>,
}
pub trait ExtiExt {
type Lines;
fn split(self) -> Self::Lines;
}
impl ExtiExt for pac::Exti {
type Lines = ExtiLines;
fn split(self) -> Self::Lines {
ExtiLines {
line0: ExtiLine { src: PinSrc },
line1: ExtiLine { src: PinSrc },
line2: ExtiLine { src: PinSrc },
line3: ExtiLine { src: PinSrc },
line4: ExtiLine { src: PinSrc },
line5: ExtiLine { src: PinSrc },
line6: ExtiLine { src: PinSrc },
line7: ExtiLine { src: PinSrc },
line8: ExtiLine { src: PinSrc },
line9: ExtiLine { src: PinSrc },
line10: ExtiLine { src: PinSrc },
line11: ExtiLine { src: PinSrc },
line12: ExtiLine { src: PinSrc },
line13: ExtiLine { src: PinSrc },
line14: ExtiLine { src: PinSrc },
line15: ExtiLine { src: PinSrc },
line16: ExtiLine { src: InternalSrc },
line17: ExtiLine { src: InternalSrc },
line19: ExtiLine { src: InternalSrc },
line21: ExtiLine { src: InternalSrc },
line25: ExtiLine { src: InternalSrc },
}
}
}