use super::{cpu_regs, exticr_regs};
use crate::gpio::{Input, Pin as GpioPin, PinNumber};
use crate::pac::EXTI;
use crate::pac::exti::regs::Lines;
pub enum TriggerEdge {
Falling,
Rising,
Any,
}
pub(super) fn configure_exti_pin(pin: PinNumber, port: PinNumber, trigger_edge: TriggerEdge) {
critical_section::with(|_| {
let pin_num = pin as usize;
exticr_regs()
.exticr(pin_num / 4)
.modify(|w| w.set_exti(pin_num % 4, port as _));
let (rising, falling) = match trigger_edge {
TriggerEdge::Falling => (false, true),
TriggerEdge::Rising => (true, false),
TriggerEdge::Any => (true, true),
};
EXTI.rtsr(0).modify(|w| w.set_line(pin_num, rising));
EXTI.ftsr(0).modify(|w| w.set_line(pin_num, falling));
clear_exti_pending(pin);
});
}
pub enum InterruptState {
Enabled,
Disabled,
}
impl From<InterruptState> for bool {
fn from(state: InterruptState) -> bool {
matches!(state, InterruptState::Enabled)
}
}
pub(super) fn set_exti_interrupt_enabled(pin: PinNumber, state: InterruptState) {
critical_section::with(|_| {
let pin = pin as usize;
cpu_regs().imr(0).modify(|w| w.set_line(pin, state.into()));
});
}
pub(super) fn configure_and_enable_exti(pin: &Input, trigger_edge: TriggerEdge) {
let pin_num = pin.pin.pin.pin();
let port_num = pin.pin.pin.port();
critical_section::with(|_| {
configure_exti_pin(pin_num, port_num, trigger_edge);
set_exti_interrupt_enabled(pin_num, InterruptState::Enabled);
});
}
macro_rules! cfg_has_rpr_fpr {
($($tokens:tt)*) => {
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6))]
$($tokens)*
};
}
macro_rules! cfg_no_rpr_fpr {
($($tokens:tt)*) => {
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6)))]
$($tokens)*
};
}
pub(super) fn clear_exti_pending_mask(mask: u32) {
cfg_no_rpr_fpr! {
EXTI.pr(0).write_value(Lines(mask));
}
cfg_has_rpr_fpr!({
EXTI.rpr(0).write_value(Lines(mask));
EXTI.fpr(0).write_value(Lines(mask));
})
}
pub(super) fn clear_exti_pending(pin: PinNumber) {
let mask = 1u32 << pin;
critical_section::with(|_| {
clear_exti_pending_mask(mask);
});
}
pub(super) fn is_exti_pending(pin: PinNumber) -> bool {
let pin = pin as usize;
cfg_no_rpr_fpr! {
return EXTI.pr(0).read().line(pin);
}
cfg_has_rpr_fpr! {
return EXTI.rpr(0).read().line(pin) || EXTI.fpr(0).read().line(pin);
}
}