use cortexm4f::support::atomic;
use enum_primitive::cast::FromPrimitive;
use enum_primitive::enum_from_primitive;
use kernel::platform::chip::ClockInterface;
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadWrite};
use kernel::utilities::StaticRef;
use crate::gpio;
use crate::syscfg;
#[repr(C)]
struct ExtiRegisters {
imr: ReadWrite<u32, IMR::Register>,
emr: ReadWrite<u32, EMR::Register>,
rtsr: ReadWrite<u32, RTSR::Register>,
ftsr: ReadWrite<u32, FTSR::Register>,
swier: ReadWrite<u32, SWIER::Register>,
pr: ReadWrite<u32, PR::Register>,
}
register_bitfields![u32,
IMR [
MR0 OFFSET(0) NUMBITS(1) [],
MR1 OFFSET(1) NUMBITS(1) [],
MR2 OFFSET(2) NUMBITS(1) [],
MR3 OFFSET(3) NUMBITS(1) [],
MR4 OFFSET(4) NUMBITS(1) [],
MR5 OFFSET(5) NUMBITS(1) [],
MR6 OFFSET(6) NUMBITS(1) [],
MR7 OFFSET(7) NUMBITS(1) [],
MR8 OFFSET(8) NUMBITS(1) [],
MR9 OFFSET(9) NUMBITS(1) [],
MR10 OFFSET(10) NUMBITS(1) [],
MR11 OFFSET(11) NUMBITS(1) [],
MR12 OFFSET(12) NUMBITS(1) [],
MR13 OFFSET(13) NUMBITS(1) [],
MR14 OFFSET(14) NUMBITS(1) [],
MR15 OFFSET(15) NUMBITS(1) [],
MR16 OFFSET(16) NUMBITS(1) [],
MR17 OFFSET(17) NUMBITS(1) [],
MR18 OFFSET(18) NUMBITS(1) [],
MR19 OFFSET(19) NUMBITS(1) [],
MR20 OFFSET(20) NUMBITS(1) [],
MR21 OFFSET(21) NUMBITS(1) [],
MR22 OFFSET(22) NUMBITS(1) []
],
EMR [
MR0 OFFSET(0) NUMBITS(1) [],
MR1 OFFSET(1) NUMBITS(1) [],
MR2 OFFSET(2) NUMBITS(1) [],
MR3 OFFSET(3) NUMBITS(1) [],
MR4 OFFSET(4) NUMBITS(1) [],
MR5 OFFSET(5) NUMBITS(1) [],
MR6 OFFSET(6) NUMBITS(1) [],
MR7 OFFSET(7) NUMBITS(1) [],
MR8 OFFSET(8) NUMBITS(1) [],
MR9 OFFSET(9) NUMBITS(1) [],
MR10 OFFSET(10) NUMBITS(1) [],
MR11 OFFSET(11) NUMBITS(1) [],
MR12 OFFSET(12) NUMBITS(1) [],
MR13 OFFSET(13) NUMBITS(1) [],
MR14 OFFSET(14) NUMBITS(1) [],
MR15 OFFSET(15) NUMBITS(1) [],
MR16 OFFSET(16) NUMBITS(1) [],
MR17 OFFSET(17) NUMBITS(1) [],
MR18 OFFSET(18) NUMBITS(1) [],
MR19 OFFSET(19) NUMBITS(1) [],
MR20 OFFSET(20) NUMBITS(1) [],
MR21 OFFSET(21) NUMBITS(1) [],
MR22 OFFSET(22) NUMBITS(1) []
],
RTSR [
TR0 OFFSET(0) NUMBITS(1) [],
TR1 OFFSET(1) NUMBITS(1) [],
TR2 OFFSET(2) NUMBITS(1) [],
TR3 OFFSET(3) NUMBITS(1) [],
TR4 OFFSET(4) NUMBITS(1) [],
TR5 OFFSET(5) NUMBITS(1) [],
TR6 OFFSET(6) NUMBITS(1) [],
TR7 OFFSET(7) NUMBITS(1) [],
TR8 OFFSET(8) NUMBITS(1) [],
TR9 OFFSET(9) NUMBITS(1) [],
TR10 OFFSET(10) NUMBITS(1) [],
TR11 OFFSET(11) NUMBITS(1) [],
TR12 OFFSET(12) NUMBITS(1) [],
TR13 OFFSET(13) NUMBITS(1) [],
TR14 OFFSET(14) NUMBITS(1) [],
TR15 OFFSET(15) NUMBITS(1) [],
TR16 OFFSET(16) NUMBITS(1) [],
TR17 OFFSET(17) NUMBITS(1) [],
TR18 OFFSET(18) NUMBITS(1) [],
TR19 OFFSET(19) NUMBITS(1) [],
TR20 OFFSET(20) NUMBITS(1) [],
TR21 OFFSET(21) NUMBITS(1) [],
TR22 OFFSET(22) NUMBITS(1) []
],
FTSR [
TR0 OFFSET(0) NUMBITS(1) [],
TR1 OFFSET(1) NUMBITS(1) [],
TR2 OFFSET(2) NUMBITS(1) [],
TR3 OFFSET(3) NUMBITS(1) [],
TR4 OFFSET(4) NUMBITS(1) [],
TR5 OFFSET(5) NUMBITS(1) [],
TR6 OFFSET(6) NUMBITS(1) [],
TR7 OFFSET(7) NUMBITS(1) [],
TR8 OFFSET(8) NUMBITS(1) [],
TR9 OFFSET(9) NUMBITS(1) [],
TR10 OFFSET(10) NUMBITS(1) [],
TR11 OFFSET(11) NUMBITS(1) [],
TR12 OFFSET(12) NUMBITS(1) [],
TR13 OFFSET(13) NUMBITS(1) [],
TR14 OFFSET(14) NUMBITS(1) [],
TR15 OFFSET(15) NUMBITS(1) [],
TR16 OFFSET(16) NUMBITS(1) [],
TR17 OFFSET(17) NUMBITS(1) [],
TR18 OFFSET(18) NUMBITS(1) [],
TR19 OFFSET(19) NUMBITS(1) [],
TR20 OFFSET(20) NUMBITS(1) [],
TR21 OFFSET(21) NUMBITS(1) [],
TR22 OFFSET(22) NUMBITS(1) []
],
SWIER [
SWIER0 OFFSET(0) NUMBITS(1) [],
SWIER1 OFFSET(1) NUMBITS(1) [],
SWIER2 OFFSET(2) NUMBITS(1) [],
SWIER3 OFFSET(3) NUMBITS(1) [],
SWIER4 OFFSET(4) NUMBITS(1) [],
SWIER5 OFFSET(5) NUMBITS(1) [],
SWIER6 OFFSET(6) NUMBITS(1) [],
SWIER7 OFFSET(7) NUMBITS(1) [],
SWIER8 OFFSET(8) NUMBITS(1) [],
SWIER9 OFFSET(9) NUMBITS(1) [],
SWIER10 OFFSET(10) NUMBITS(1) [],
SWIER11 OFFSET(11) NUMBITS(1) [],
SWIER12 OFFSET(12) NUMBITS(1) [],
SWIER13 OFFSET(13) NUMBITS(1) [],
SWIER14 OFFSET(14) NUMBITS(1) [],
SWIER15 OFFSET(15) NUMBITS(1) [],
SWIER16 OFFSET(16) NUMBITS(1) [],
SWIER17 OFFSET(17) NUMBITS(1) [],
SWIER18 OFFSET(18) NUMBITS(1) [],
SWIER19 OFFSET(19) NUMBITS(1) [],
SWIER20 OFFSET(20) NUMBITS(1) [],
SWIER21 OFFSET(21) NUMBITS(1) [],
SWIER22 OFFSET(22) NUMBITS(1) []
],
PR [
PR0 OFFSET(0) NUMBITS(1) [],
PR1 OFFSET(1) NUMBITS(1) [],
PR2 OFFSET(2) NUMBITS(1) [],
PR3 OFFSET(3) NUMBITS(1) [],
PR4 OFFSET(4) NUMBITS(1) [],
PR5 OFFSET(5) NUMBITS(1) [],
PR6 OFFSET(6) NUMBITS(1) [],
PR7 OFFSET(7) NUMBITS(1) [],
PR8 OFFSET(8) NUMBITS(1) [],
PR9 OFFSET(9) NUMBITS(1) [],
PR10 OFFSET(10) NUMBITS(1) [],
PR11 OFFSET(11) NUMBITS(1) [],
PR12 OFFSET(12) NUMBITS(1) [],
PR13 OFFSET(13) NUMBITS(1) [],
PR14 OFFSET(14) NUMBITS(1) [],
PR15 OFFSET(15) NUMBITS(1) [],
PR16 OFFSET(16) NUMBITS(1) [],
PR17 OFFSET(17) NUMBITS(1) [],
PR18 OFFSET(18) NUMBITS(1) [],
PR19 OFFSET(19) NUMBITS(1) [],
PR20 OFFSET(20) NUMBITS(1) [],
PR21 OFFSET(21) NUMBITS(1) [],
PR22 OFFSET(22) NUMBITS(1) []
]
];
const EXTI_BASE: StaticRef<ExtiRegisters> =
unsafe { StaticRef::new(0x40013C00 as *const ExtiRegisters) };
#[no_mangle]
#[used]
pub static mut EXTI_EVENTS: u32 = 0;
enum_from_primitive! {
#[repr(u8)]
#[derive(Copy, Clone)]
pub enum LineId {
Exti0 = 0,
Exti1 = 1,
Exti2 = 2,
Exti3 = 3,
Exti4 = 4,
Exti5 = 5,
Exti6 = 6,
Exti7 = 7,
Exti8 = 8,
Exti9 = 9,
Exti10 = 10,
Exti11 = 11,
Exti12 = 12,
Exti13 = 13,
Exti14 = 14,
Exti15 = 15,
}
}
pub struct Exti<'a> {
registers: StaticRef<ExtiRegisters>,
clock: ExtiClock<'a>,
line_gpiopin_map: [OptionalCell<&'static gpio::Pin<'static>>; 16],
syscfg: &'a syscfg::Syscfg<'a>,
}
impl<'a> Exti<'a> {
pub const fn new(syscfg: &'a syscfg::Syscfg<'a>) -> Self {
Self {
registers: EXTI_BASE,
clock: ExtiClock(syscfg),
line_gpiopin_map: [
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
OptionalCell::empty(),
],
syscfg,
}
}
pub fn is_enabled_clock(&self) -> bool {
self.clock.is_enabled()
}
pub fn enable_clock(&self) {
self.clock.enable();
}
pub fn disable_clock(&self) {
self.clock.disable();
}
pub fn associate_line_gpiopin(&self, lineid: LineId, pin: &'static gpio::Pin<'static>) {
self.line_gpiopin_map[usize::from(lineid as u8)].set(pin);
self.syscfg.configure_interrupt(pin.get_pinid());
pin.set_exti_lineid(lineid);
self.mask_interrupt(lineid);
}
pub fn mask_interrupt(&self, lineid: LineId) {
match lineid {
LineId::Exti0 => self.registers.imr.modify(IMR::MR0::CLEAR),
LineId::Exti1 => self.registers.imr.modify(IMR::MR1::CLEAR),
LineId::Exti2 => self.registers.imr.modify(IMR::MR2::CLEAR),
LineId::Exti3 => self.registers.imr.modify(IMR::MR3::CLEAR),
LineId::Exti4 => self.registers.imr.modify(IMR::MR4::CLEAR),
LineId::Exti5 => self.registers.imr.modify(IMR::MR5::CLEAR),
LineId::Exti6 => self.registers.imr.modify(IMR::MR6::CLEAR),
LineId::Exti7 => self.registers.imr.modify(IMR::MR7::CLEAR),
LineId::Exti8 => self.registers.imr.modify(IMR::MR8::CLEAR),
LineId::Exti9 => self.registers.imr.modify(IMR::MR9::CLEAR),
LineId::Exti10 => self.registers.imr.modify(IMR::MR10::CLEAR),
LineId::Exti11 => self.registers.imr.modify(IMR::MR11::CLEAR),
LineId::Exti12 => self.registers.imr.modify(IMR::MR12::CLEAR),
LineId::Exti13 => self.registers.imr.modify(IMR::MR13::CLEAR),
LineId::Exti14 => self.registers.imr.modify(IMR::MR14::CLEAR),
LineId::Exti15 => self.registers.imr.modify(IMR::MR15::CLEAR),
}
}
pub fn unmask_interrupt(&self, lineid: LineId) {
match lineid {
LineId::Exti0 => self.registers.imr.modify(IMR::MR0::SET),
LineId::Exti1 => self.registers.imr.modify(IMR::MR1::SET),
LineId::Exti2 => self.registers.imr.modify(IMR::MR2::SET),
LineId::Exti3 => self.registers.imr.modify(IMR::MR3::SET),
LineId::Exti4 => self.registers.imr.modify(IMR::MR4::SET),
LineId::Exti5 => self.registers.imr.modify(IMR::MR5::SET),
LineId::Exti6 => self.registers.imr.modify(IMR::MR6::SET),
LineId::Exti7 => self.registers.imr.modify(IMR::MR7::SET),
LineId::Exti8 => self.registers.imr.modify(IMR::MR8::SET),
LineId::Exti9 => self.registers.imr.modify(IMR::MR9::SET),
LineId::Exti10 => self.registers.imr.modify(IMR::MR10::SET),
LineId::Exti11 => self.registers.imr.modify(IMR::MR11::SET),
LineId::Exti12 => self.registers.imr.modify(IMR::MR12::SET),
LineId::Exti13 => self.registers.imr.modify(IMR::MR13::SET),
LineId::Exti14 => self.registers.imr.modify(IMR::MR14::SET),
LineId::Exti15 => self.registers.imr.modify(IMR::MR15::SET),
}
}
pub fn clear_pending(&self, lineid: LineId) {
match lineid {
LineId::Exti0 => self.registers.pr.write(PR::PR0::SET),
LineId::Exti1 => self.registers.pr.write(PR::PR1::SET),
LineId::Exti2 => self.registers.pr.write(PR::PR2::SET),
LineId::Exti3 => self.registers.pr.write(PR::PR3::SET),
LineId::Exti4 => self.registers.pr.write(PR::PR4::SET),
LineId::Exti5 => self.registers.pr.write(PR::PR5::SET),
LineId::Exti6 => self.registers.pr.write(PR::PR6::SET),
LineId::Exti7 => self.registers.pr.write(PR::PR7::SET),
LineId::Exti8 => self.registers.pr.write(PR::PR8::SET),
LineId::Exti9 => self.registers.pr.write(PR::PR9::SET),
LineId::Exti10 => self.registers.pr.write(PR::PR10::SET),
LineId::Exti11 => self.registers.pr.write(PR::PR11::SET),
LineId::Exti12 => self.registers.pr.write(PR::PR12::SET),
LineId::Exti13 => self.registers.pr.write(PR::PR13::SET),
LineId::Exti14 => self.registers.pr.write(PR::PR14::SET),
LineId::Exti15 => self.registers.pr.write(PR::PR15::SET),
}
}
pub fn is_pending(&self, lineid: LineId) -> bool {
let val = match lineid {
LineId::Exti0 => self.registers.pr.read(PR::PR0),
LineId::Exti1 => self.registers.pr.read(PR::PR1),
LineId::Exti2 => self.registers.pr.read(PR::PR2),
LineId::Exti3 => self.registers.pr.read(PR::PR3),
LineId::Exti4 => self.registers.pr.read(PR::PR4),
LineId::Exti5 => self.registers.pr.read(PR::PR5),
LineId::Exti6 => self.registers.pr.read(PR::PR6),
LineId::Exti7 => self.registers.pr.read(PR::PR7),
LineId::Exti8 => self.registers.pr.read(PR::PR8),
LineId::Exti9 => self.registers.pr.read(PR::PR9),
LineId::Exti10 => self.registers.pr.read(PR::PR10),
LineId::Exti11 => self.registers.pr.read(PR::PR11),
LineId::Exti12 => self.registers.pr.read(PR::PR12),
LineId::Exti13 => self.registers.pr.read(PR::PR13),
LineId::Exti14 => self.registers.pr.read(PR::PR14),
LineId::Exti15 => self.registers.pr.read(PR::PR15),
};
val > 0
}
pub fn select_rising_trigger(&self, lineid: LineId) {
match lineid {
LineId::Exti0 => self.registers.rtsr.modify(RTSR::TR0::SET),
LineId::Exti1 => self.registers.rtsr.modify(RTSR::TR1::SET),
LineId::Exti2 => self.registers.rtsr.modify(RTSR::TR2::SET),
LineId::Exti3 => self.registers.rtsr.modify(RTSR::TR3::SET),
LineId::Exti4 => self.registers.rtsr.modify(RTSR::TR4::SET),
LineId::Exti5 => self.registers.rtsr.modify(RTSR::TR5::SET),
LineId::Exti6 => self.registers.rtsr.modify(RTSR::TR6::SET),
LineId::Exti7 => self.registers.rtsr.modify(RTSR::TR7::SET),
LineId::Exti8 => self.registers.rtsr.modify(RTSR::TR8::SET),
LineId::Exti9 => self.registers.rtsr.modify(RTSR::TR9::SET),
LineId::Exti10 => self.registers.rtsr.modify(RTSR::TR10::SET),
LineId::Exti11 => self.registers.rtsr.modify(RTSR::TR11::SET),
LineId::Exti12 => self.registers.rtsr.modify(RTSR::TR12::SET),
LineId::Exti13 => self.registers.rtsr.modify(RTSR::TR13::SET),
LineId::Exti14 => self.registers.rtsr.modify(RTSR::TR14::SET),
LineId::Exti15 => self.registers.rtsr.modify(RTSR::TR15::SET),
}
}
pub fn deselect_rising_trigger(&self, lineid: LineId) {
match lineid {
LineId::Exti0 => self.registers.rtsr.modify(RTSR::TR0::CLEAR),
LineId::Exti1 => self.registers.rtsr.modify(RTSR::TR1::CLEAR),
LineId::Exti2 => self.registers.rtsr.modify(RTSR::TR2::CLEAR),
LineId::Exti3 => self.registers.rtsr.modify(RTSR::TR3::CLEAR),
LineId::Exti4 => self.registers.rtsr.modify(RTSR::TR4::CLEAR),
LineId::Exti5 => self.registers.rtsr.modify(RTSR::TR5::CLEAR),
LineId::Exti6 => self.registers.rtsr.modify(RTSR::TR6::CLEAR),
LineId::Exti7 => self.registers.rtsr.modify(RTSR::TR7::CLEAR),
LineId::Exti8 => self.registers.rtsr.modify(RTSR::TR8::CLEAR),
LineId::Exti9 => self.registers.rtsr.modify(RTSR::TR9::CLEAR),
LineId::Exti10 => self.registers.rtsr.modify(RTSR::TR10::CLEAR),
LineId::Exti11 => self.registers.rtsr.modify(RTSR::TR11::CLEAR),
LineId::Exti12 => self.registers.rtsr.modify(RTSR::TR12::CLEAR),
LineId::Exti13 => self.registers.rtsr.modify(RTSR::TR13::CLEAR),
LineId::Exti14 => self.registers.rtsr.modify(RTSR::TR14::CLEAR),
LineId::Exti15 => self.registers.rtsr.modify(RTSR::TR15::CLEAR),
}
}
pub fn select_falling_trigger(&self, lineid: LineId) {
match lineid {
LineId::Exti0 => self.registers.ftsr.modify(FTSR::TR0::SET),
LineId::Exti1 => self.registers.ftsr.modify(FTSR::TR1::SET),
LineId::Exti2 => self.registers.ftsr.modify(FTSR::TR2::SET),
LineId::Exti3 => self.registers.ftsr.modify(FTSR::TR3::SET),
LineId::Exti4 => self.registers.ftsr.modify(FTSR::TR4::SET),
LineId::Exti5 => self.registers.ftsr.modify(FTSR::TR5::SET),
LineId::Exti6 => self.registers.ftsr.modify(FTSR::TR6::SET),
LineId::Exti7 => self.registers.ftsr.modify(FTSR::TR7::SET),
LineId::Exti8 => self.registers.ftsr.modify(FTSR::TR8::SET),
LineId::Exti9 => self.registers.ftsr.modify(FTSR::TR9::SET),
LineId::Exti10 => self.registers.ftsr.modify(FTSR::TR10::SET),
LineId::Exti11 => self.registers.ftsr.modify(FTSR::TR11::SET),
LineId::Exti12 => self.registers.ftsr.modify(FTSR::TR12::SET),
LineId::Exti13 => self.registers.ftsr.modify(FTSR::TR13::SET),
LineId::Exti14 => self.registers.ftsr.modify(FTSR::TR14::SET),
LineId::Exti15 => self.registers.ftsr.modify(FTSR::TR15::SET),
}
}
pub fn deselect_falling_trigger(&self, lineid: LineId) {
match lineid {
LineId::Exti0 => self.registers.ftsr.modify(FTSR::TR0::CLEAR),
LineId::Exti1 => self.registers.ftsr.modify(FTSR::TR1::CLEAR),
LineId::Exti2 => self.registers.ftsr.modify(FTSR::TR2::CLEAR),
LineId::Exti3 => self.registers.ftsr.modify(FTSR::TR3::CLEAR),
LineId::Exti4 => self.registers.ftsr.modify(FTSR::TR4::CLEAR),
LineId::Exti5 => self.registers.ftsr.modify(FTSR::TR5::CLEAR),
LineId::Exti6 => self.registers.ftsr.modify(FTSR::TR6::CLEAR),
LineId::Exti7 => self.registers.ftsr.modify(FTSR::TR7::CLEAR),
LineId::Exti8 => self.registers.ftsr.modify(FTSR::TR8::CLEAR),
LineId::Exti9 => self.registers.ftsr.modify(FTSR::TR9::CLEAR),
LineId::Exti10 => self.registers.ftsr.modify(FTSR::TR10::CLEAR),
LineId::Exti11 => self.registers.ftsr.modify(FTSR::TR11::CLEAR),
LineId::Exti12 => self.registers.ftsr.modify(FTSR::TR12::CLEAR),
LineId::Exti13 => self.registers.ftsr.modify(FTSR::TR13::CLEAR),
LineId::Exti14 => self.registers.ftsr.modify(FTSR::TR14::CLEAR),
LineId::Exti15 => self.registers.ftsr.modify(FTSR::TR15::CLEAR),
}
}
pub fn handle_interrupt(&self) {
let mut exti_pr: u32 = 0;
unsafe {
atomic(|| {
exti_pr = self.registers.pr.get();
self.registers.pr.set(exti_pr);
});
}
exti_pr |= 0x007fffff;
let mut flagged_bit = 0;
while exti_pr != 0 {
if (exti_pr & 0b1) != 0 {
if let Some(d) = LineId::from_u8(flagged_bit) {
self.line_gpiopin_map[usize::from(d as u8)].map(|pin| pin.handle_interrupt());
}
}
flagged_bit += 1;
exti_pr >>= 1;
}
}
}
struct ExtiClock<'a>(&'a syscfg::Syscfg<'a>);
impl ClockInterface for ExtiClock<'_> {
fn is_enabled(&self) -> bool {
self.0.is_enabled_clock()
}
fn enable(&self) {
self.0.enable_clock();
}
fn disable(&self) {
self.0.disable_clock();
}
}