stm32f1xx_HBL/drv/exti.c
Steins7 5e4d87474a Fix major reg bitfield issue
A while back, macros had to be put in place to avoid letting the
compiler directly use the bitfields. This was necessary because the
compiler used strb instruction which only write bytes. On the AHB bus,
byte writes are transformed into word writes by repeating the byte,
which caused mayhem in the registers. After a lot of research, turns out
the packed attribute stops the compiler from does optimal (word) writes
and isn't needed anyway. Removing them fixes the issue
2024-07-10 23:16:49 +02:00

271 lines
5.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"
#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]();
}