271 lines
5.6 KiB
C
271 lines
5.6 KiB
C
/** @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);
|
|
reg_set(regs->PR, EXTI_PR_PR0);
|
|
callbacks[0]();
|
|
}
|
|
|
|
void hdr_exti1(void)
|
|
{
|
|
nvic_clear_pending(NVIC_IRQ_EXTI1);
|
|
reg_set(regs->PR, EXTI_PR_PR1);
|
|
callbacks[1]();
|
|
}
|
|
|
|
void hdr_exti2(void)
|
|
{
|
|
nvic_clear_pending(NVIC_IRQ_EXTI2);
|
|
reg_set(regs->PR, EXTI_PR_PR2);
|
|
callbacks[2]();
|
|
}
|
|
|
|
void hdr_exti3(void)
|
|
{
|
|
nvic_clear_pending(NVIC_IRQ_EXTI3);
|
|
reg_set(regs->PR, EXTI_PR_PR3);
|
|
callbacks[3]();
|
|
}
|
|
|
|
void hdr_exti4(void)
|
|
{
|
|
nvic_clear_pending(NVIC_IRQ_EXTI4);
|
|
reg_set(regs->PR, EXTI_PR_PR4);
|
|
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);
|
|
reg_set(regs->PR, EXTI_PR_PR16);
|
|
callbacks[16]();
|
|
}
|
|
|
|
void hdr_rtc_alarm(void)
|
|
{
|
|
nvic_clear_pending(NVIC_IRQ_RTC_ALARM);
|
|
reg_set(regs->PR, EXTI_PR_PR17);
|
|
callbacks[17]();
|
|
}
|
|
|
|
void hdr_usb_wakeup(void)
|
|
{
|
|
nvic_clear_pending(NVIC_IRQ_USB_WAKEUP);
|
|
reg_set(regs->PR, EXTI_PR_PR18);
|
|
callbacks[18]();
|
|
}
|
|
|