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
271 lines
5.5 KiB
C
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]();
|
|
}
|
|
|