The "specific" lines configuration would not work due to index error in the callback configuration. While fixing the error, simplifying the API by moving the afio calls to the calling context seemed a cleaner way to do things
226 lines
4.5 KiB
C
226 lines
4.5 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"
|
|
|
|
|
|
//--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 ExtiConfig config_mask,
|
|
ExtiCallback callback)
|
|
{
|
|
exti_reset(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 < 19; ++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);
|
|
}
|
|
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(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);
|
|
}
|
|
|
|
//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);
|
|
}
|
|
|
|
//--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]();
|
|
}
|
|
|