diff options
author | Marti Bolivar <mbolivar@leaflabs.com> | 2011-08-03 13:42:30 -0400 |
---|---|---|
committer | Marti Bolivar <mbolivar@leaflabs.com> | 2011-08-03 17:34:03 -0400 |
commit | b33e28fae09fea9e68d71cee3db91c0024b4741f (patch) | |
tree | 0f720e25b3bfa71ea549e1b441e2d7ecccb740f6 /libmaple | |
parent | 01bbbf344cb56e5aeb43544dc81ed2733f861ca2 (diff) | |
download | librambutan-b33e28fae09fea9e68d71cee3db91c0024b4741f.tar.gz librambutan-b33e28fae09fea9e68d71cee3db91c0024b4741f.zip |
exti.c: Optimize multiplexed IRQ handlers.
Rewrite existing IRQ handlers in terms of new functions
dispatch_single_exti() and dispatch_extis(). dispatch_single_exti()
handles EXTIs which have a dedicated IRQ line, and thus doesn't have
to check EXTI_PR; it is mostly equivalent to the (now removed)
handle_exti(). dispatch_extis() handles multiple EXTIs sharing an IRQ
line. Using dispatch_extis() instead of calling handle_exti()
multiple times avoids unnecessary I/O to the (volatile) EXTI_BASE->PR
register.
These changes are in the flavor of the timer IRQ optimizations
performed in f5016b15bef56bbdfd187f9b623177ef6dde7ace.
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/exti.c | 91 |
1 files changed, 48 insertions, 43 deletions
diff --git a/libmaple/exti.c b/libmaple/exti.c index 74a5d78..ae4d365 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -29,14 +29,13 @@ * @brief External interrupt control routines */ -#include "libmaple.h" #include "exti.h" +#include "libmaple.h" #include "nvic.h" #include "bitband.h" -static inline void handle_exti(uint32 exti_num); -static inline void clear_pending(uint32 exti_num); -static inline void dispatch_handler(uint32 exti_num); +static inline void dispatch_single_exti(uint32 exti_num); +static inline void dispatch_extis(uint32 start, uint32 stop); /* * Internal state @@ -140,74 +139,80 @@ void exti_detach_interrupt(afio_exti_num num) { */ void __irq_exti0(void) { - handle_exti(AFIO_EXTI_0); + dispatch_single_exti(AFIO_EXTI_0); } void __irq_exti1(void) { - handle_exti(AFIO_EXTI_1); + dispatch_single_exti(AFIO_EXTI_1); } void __irq_exti2(void) { - handle_exti(AFIO_EXTI_2); + dispatch_single_exti(AFIO_EXTI_2); } void __irq_exti3(void) { - handle_exti(AFIO_EXTI_3); + dispatch_single_exti(AFIO_EXTI_3); } void __irq_exti4(void) { - handle_exti(AFIO_EXTI_4); + dispatch_single_exti(AFIO_EXTI_4); } void __irq_exti9_5(void) { - /* Figure out which channel it came from */ - uint32 pending = GET_BITS(EXTI_BASE->PR, 5, 9); - uint32 i; - - /* Dispatch every handler if the pending bit is set */ - for (i = 0; i < 5; i++) { - if (pending & 0x1) { - handle_exti(AFIO_EXTI_5 + i); - } - pending >>= 1; - } + dispatch_extis(5, 9); } void __irq_exti15_10(void) { - /* Figure out which channel it came from */ - uint32 pending = GET_BITS(EXTI_BASE->PR, 10, 15); - uint32 i; - - /* Dispatch every handler if the pending bit is set */ - for (i = 0; i < 6; i++) { - if (pending & 0x1) { - handle_exti(AFIO_EXTI_10 + i); - } - pending >>= 1; - } + dispatch_extis(10, 15); } /* * Auxiliary functions */ -static inline void handle_exti(uint32 exti) { - dispatch_handler(exti); - clear_pending(exti); - /* If the pending bit is cleared as the last instruction in an ISR, - * it won't actually be cleared in time and the ISR will fire again. - * Insert a 2-cycle buffer to allow it to take effect. */ +/* Clear the pending bits for EXTIs whose bits are set in exti_msk. + * + * If a pending bit is cleared as the last instruction in an ISR, it + * won't actually be cleared in time and the ISR will fire again. To + * compensate, this function NOPs for 2 cycles after clearing the + * pending bits to ensure it takes effect. */ +static inline void clear_pending_msk(uint32 exti_msk) { + EXTI_BASE->PR = exti_msk; asm volatile("nop"); asm volatile("nop"); } -static inline void dispatch_handler(uint32 exti_num) { - ASSERT(exti_channels[exti_num].handler); - if (exti_channels[exti_num].handler) { - (exti_channels[exti_num].handler)(); +/* This dispatch routine is for non-multiplexed EXTI lines only; i.e., + * it doesn't check EXTI_PR. */ +static inline void dispatch_single_exti(uint32 exti) { + voidFuncPtr handler = exti_channels[exti].handler; + + if (!handler) { + return; } + + handler(); + clear_pending_msk(BIT(exti)); } -static inline void clear_pending(uint32 exti_num) { - EXTI_BASE->PR = 1 << exti_num; +/* Dispatch routine for EXTIs which share an IRQ. */ +static inline void dispatch_extis(uint32 start, uint32 stop) { + uint32 pr = EXTI_BASE->PR; + uint32 handled_msk = 0; + uint32 exti; + + /* Dispatch user handlers for pending EXTIs. */ + for (exti = start; exti <= stop; exti++) { + uint32 eb = BIT(exti); + if (pr & eb) { + voidFuncPtr handler = exti_channels[exti].handler; + if (handler) { + handler(); + handled_msk |= eb; + } + } + } + + /* Clear the pending bits for handled EXTIs. */ + clear_pending_msk(handled_msk); } |