/** @file exti.c * Module handling EXTernal Interrupt lines * * The module provides functions to configure the exti lines to generate events * or interrupts */ //--includes-------------------------------------------------------------------- #include "exti.h" #include "exti_regs.h" #include "nvic.h" #include "afio.h" //--local definitions----------------------------------------------------------- //--local variables------------------------------------------------------------- static volatile struct EXTI* regs = (struct EXTI*)EXTI_BASE_ADDRESS; static ExtiCallback callbacks[19]; //--public functions------------------------------------------------------------ void exti_configure(enum ExtiLine line_mask, enum GpioPort port, enum ExtiConfig config_mask, ExtiCallback callback) { exti_reset(line_mask); afio_map_exti(line_mask, port); //configure edge detections if (config_mask & EXTI_CONFIG_RISING_EDGE) { regs->RTSR.word |= line_mask; } else { regs->RTSR.word &= ~line_mask; } if (config_mask & EXTI_CONFIG_FALLING_EDGE) { regs->FTSR.word |= line_mask; } else { regs->FTSR.word &= ~line_mask; } //reconfigure events/irqs regs->EMR.word |= line_mask; if (callback) { //register callbacks for each line selected for (uint8_t i = 0; i < 16; ++i) { if (line_mask & (0x1 << i)) { callbacks[i] = callback; } } //enable interrupts lines in nvic for (uint8_t i = 0; i < 5; ++i) { if (line_mask & (0x1 << i)) { nvic_enable(NVIC_IRQ_EXTI0 + i); } } if (line_mask & 0x3e0) { nvic_enable(NVIC_IRQ_EXTI9_5); } if (line_mask & 0x7c00) { nvic_enable(NVIC_IRQ_EXTI15_10); } //enable irqs in last to avoid triggers during config regs->IMR.word |= line_mask; } } void exti_reset(enum ExtiLine line_mask) { //disable events/irqs regs->IMR.word &= ~line_mask; regs->EMR.word &= ~line_mask; //clear any pending bits regs->PR.word |= line_mask; //disable interrupts lines in nvic for (uint8_t i = 0; i < 5; ++i) { if (line_mask & (0x1 << i)) { nvic_disable(NVIC_IRQ_EXTI0 + i); } } if (line_mask & 0x3e0) { nvic_disable(NVIC_IRQ_EXTI9_5); } if (line_mask & 0x7c00) { nvic_disable(NVIC_IRQ_EXTI15_10); } afio_map_exti(0xFFFF, 0x0); } void exti_configure_specific(enum ExtiLineSpecific line_mask, enum ExtiConfig config_mask, ExtiCallback callback) { //reset is identical to normal lines exti_reset_specific(line_mask); //configure edge detections if (config_mask & EXTI_CONFIG_RISING_EDGE) { regs->RTSR.word |= line_mask; } else { regs->RTSR.word &= ~line_mask; } if (config_mask & EXTI_CONFIG_FALLING_EDGE) { regs->FTSR.word |= line_mask; } else { regs->FTSR.word &= ~line_mask; } //reconfigure events/irqs regs->EMR.word |= line_mask; if (callback) { //register callbacks for each line selected for (uint8_t i = 0; i < 16; ++i) { if (line_mask & (0x1 << i)) { callbacks[i] = callback; } } //enable interrupts lines in nvic if (line_mask & EXTI_LINE_PVD) { nvic_enable(NVIC_IRQ_PVD); } if (line_mask & EXTI_LINE_RTC) { nvic_enable(NVIC_IRQ_RTC_ALARM); } if (line_mask & EXTI_LINE_USB) { nvic_enable(NVIC_IRQ_USB_WAKEUP); } //enable irqs in last to avoid triggers during config regs->IMR.word |= line_mask; } } void exti_reset_specific(enum ExtiLineSpecific line_mask) { //disable events/irqs regs->IMR.word &= ~line_mask; regs->EMR.word &= ~line_mask; //clear any pending bits regs->PR.word |= line_mask; //disable interrupts lines in nvic if (line_mask & EXTI_LINE_PVD) { nvic_disable(NVIC_IRQ_PVD); } if (line_mask & EXTI_LINE_RTC) { nvic_disable(NVIC_IRQ_RTC_ALARM); } if (line_mask & EXTI_LINE_USB) { nvic_disable(NVIC_IRQ_USB_WAKEUP); } } void exti_reset_peripheral(void) { //reset peripheral config regs->IMR.word = 0; regs->EMR.word = 0; regs->RTSR.word = 0; regs->FTSR.word = 0; regs->SWIER.word = 0; regs->PR.word = 0; //disable interrupts in nvic for (uint8_t i = 0; i < 5; ++i) { nvic_enable(NVIC_IRQ_EXTI0 + i); } nvic_enable(NVIC_IRQ_EXTI9_5); nvic_enable(NVIC_IRQ_EXTI15_10); nvic_disable(NVIC_IRQ_PVD); nvic_disable(NVIC_IRQ_RTC_ALARM); nvic_disable(NVIC_IRQ_USB_WAKEUP); afio_map_exti(0xFFFF, 0x0); } //--local functions------------------------------------------------------------- //--ISRs------------------------------------------------------------------------ void hdr_exti0(void) { nvic_clear_pending(NVIC_IRQ_EXTI0); regs->PR.PR0 = 1; callbacks[0](); } void hdr_exti1(void) { nvic_clear_pending(NVIC_IRQ_EXTI1); regs->PR.PR1 = 1; callbacks[1](); } void hdr_exti2(void) { nvic_clear_pending(NVIC_IRQ_EXTI2); regs->PR.PR2 = 1; callbacks[2](); } void hdr_exti3(void) { nvic_clear_pending(NVIC_IRQ_EXTI3); regs->PR.PR3 = 1; callbacks[3](); } void hdr_exti4(void) { nvic_clear_pending(NVIC_IRQ_EXTI4); regs->PR.PR4 = 1; callbacks[4](); } void hdr_exti9_5(void) { nvic_clear_pending(NVIC_IRQ_EXTI9_5); for (uint8_t i = 5; i < 10; ++i) { if (regs->PR.word & (0x1 << i)) { regs->PR.word |= 0x1 << i; callbacks[i](); } } } void hdr_exti15_10(void) { nvic_clear_pending(NVIC_IRQ_EXTI15_10); for (uint8_t i = 10; i < 16; ++i) { if (regs->PR.word & (0x1 << i)) { regs->PR.word |= 0x1 << i; callbacks[i](); } } } void hdr_pvd(void) { nvic_clear_pending(NVIC_IRQ_PVD); regs->PR.PR16 = 1; callbacks[16](); } void hdr_rtc_alarm(void) { nvic_clear_pending(NVIC_IRQ_RTC_ALARM); regs->PR.PR17 = 1; callbacks[17](); } void hdr_usb_wakeup(void) { nvic_clear_pending(NVIC_IRQ_USB_WAKEUP); regs->PR.PR18 = 1; callbacks[18](); }