Implement exti's control functions
This commit is contained in:
parent
a99b4ad0de
commit
c7deded9b2
267
drivers/exti.c
Normal file
267
drivers/exti.c
Normal file
@ -0,0 +1,267 @@
|
||||
/** @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 GpioPort port,
|
||||
enum ExtiConfig config_mask, ExtiCallback callback)
|
||||
{
|
||||
exti_reset(line_mask);
|
||||
|
||||
#warning "configure ports mapping"
|
||||
|
||||
//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_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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#warning "reset afio lines"
|
||||
}
|
||||
|
||||
//--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]();
|
||||
}
|
||||
|
||||
108
drivers/exti.h
Normal file
108
drivers/exti.h
Normal file
@ -0,0 +1,108 @@
|
||||
/** @file exti.h
|
||||
* Module handling EXTernal Interrupt lines
|
||||
*
|
||||
* The module provides functions to configure the exti lines to generate events
|
||||
* or interrupts
|
||||
*/
|
||||
|
||||
#ifndef _EXTI_H_
|
||||
#define _EXTI_H_
|
||||
|
||||
//--includes--------------------------------------------------------------------
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
|
||||
//--type definitions------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Available exti lines. These lines correspond to gpios
|
||||
*/
|
||||
enum ExtiLine {
|
||||
EXTI_LINE_0 = (0x1 << 0),
|
||||
EXTI_LINE_1 = (0x1 << 1),
|
||||
EXTI_LINE_2 = (0x1 << 2),
|
||||
EXTI_LINE_3 = (0x1 << 3),
|
||||
EXTI_LINE_4 = (0x1 << 4),
|
||||
EXTI_LINE_5 = (0x1 << 5),
|
||||
EXTI_LINE_6 = (0x1 << 6),
|
||||
EXTI_LINE_7 = (0x1 << 7),
|
||||
EXTI_LINE_8 = (0x1 << 8),
|
||||
EXTI_LINE_9 = (0x1 << 9),
|
||||
EXTI_LINE_10 = (0x1 << 10),
|
||||
EXTI_LINE_11 = (0x1 << 11),
|
||||
EXTI_LINE_12 = (0x1 << 12),
|
||||
EXTI_LINE_13 = (0x1 << 13),
|
||||
EXTI_LINE_14 = (0x1 << 14),
|
||||
EXTI_LINE_15 = (0x1 << 15),
|
||||
};
|
||||
|
||||
/**
|
||||
* Available exti lines. These lines correspond to specific peripherals
|
||||
*/
|
||||
enum ExtiLineSpecific {
|
||||
EXTI_LINE_PVD = (0x1 << 16),
|
||||
EXTI_LINE_RTC = (0x1 << 17),
|
||||
EXTI_LINE_USB = (0x1 << 18),
|
||||
};
|
||||
|
||||
/**
|
||||
* Available configurations for exti lines. These configurations apply to both
|
||||
* regular and specific lines and can be used together on a single line
|
||||
*/
|
||||
enum ExtiConfig {
|
||||
EXTI_CONFIG_RISING_EDGE,
|
||||
EXTI_CONFIG_FALLING_EDGE,
|
||||
};
|
||||
|
||||
typedef void (*ExtiCallback)(void);
|
||||
|
||||
|
||||
//--functions-------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Configure lines on a single GPIO port. The ExtiLine enum can be used as a
|
||||
* mask to configure multiple lines at the same time. Every line can only be
|
||||
* configured for a single port, reconfiguring it will override the previous
|
||||
* configuration. Each line is linked to the pins of the same id (ex : pin 1 for
|
||||
* exti 1). When possible, it is recommanded to use the lowest id possible for
|
||||
* better performance. The ExtiConfig enum can be used as mask. If no callback
|
||||
* is specified, the interrupt won't be enabled, but an event will still be sent
|
||||
* to wake the cpu up
|
||||
*/
|
||||
void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
|
||||
enum ExtiConfig config_mask, ExtiCallback callback);
|
||||
|
||||
/**
|
||||
* Resets lines. The ExtiLine enum can be used as a mask to configure multiple
|
||||
* lines at the same time
|
||||
*/
|
||||
void exti_reset(enum ExtiLine line_mask);
|
||||
|
||||
/**
|
||||
* Configure lines for specific, non-gpio peripherals. The ExtiLineSpecific enum
|
||||
* can be used as a mask to configure multiple lines at the same time. The
|
||||
* ExtiConfig enum can be used as mask. If no callback is specified, the
|
||||
* interrupt won't be enabled, but an event will still be sent to wake the cpu
|
||||
* up
|
||||
*/
|
||||
void exti_configure_specific(enum ExtiLineSpecific line_mask,
|
||||
enum ExtiConfig config_mask, ExtiCallback callback);
|
||||
|
||||
/**
|
||||
* Resets lines for specific, non-gpio peripherals. The ExtiLineSpecific enum
|
||||
* can be used as a mask to configure multiple lines at the same time.
|
||||
*/
|
||||
void exti_reset_specific(enum ExtiLineSpecific line_mask);
|
||||
|
||||
/**
|
||||
* Resets all lines. The exti peripheral is returned to its reset configuration
|
||||
*/
|
||||
void exti_reset_peripheral(void);
|
||||
|
||||
|
||||
#endif //_EXTI_H_
|
||||
|
||||
Loading…
Reference in New Issue
Block a user