stm32f1xx_HBL/drv/exti.c
Steins7 7ab6622908 Rework exti module to use a simpler API
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
2024-08-04 19:38:24 +02:00

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]();
}