diff options
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/exti.c | 234 | ||||
-rw-r--r-- | libmaple/exti.h | 13 | ||||
-rw-r--r-- | libmaple/libmaple_types.h | 4 | ||||
-rw-r--r-- | libmaple/nvic.h | 37 |
4 files changed, 111 insertions, 177 deletions
diff --git a/libmaple/exti.c b/libmaple/exti.c index 5575906..8a54457 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -33,10 +33,32 @@ #include "exti.h" #include "nvic.h" -volatile static voidFuncPtr exti_handlers[NR_EXTI_CHANNELS]; +typedef struct ExtIChannel { + void (*handler)(void); + uint32 irq_line; +} ExtIChannel; + +static ExtIChannel exti_channels[] = { + { .handler = NULL, .irq_line = NVIC_EXTI0 }, // EXTI0 + { .handler = NULL, .irq_line = NVIC_EXTI1 }, // EXTI1 + { .handler = NULL, .irq_line = NVIC_EXTI2 }, // EXTI2 + { .handler = NULL, .irq_line = NVIC_EXTI3 }, // EXTI3 + { .handler = NULL, .irq_line = NVIC_EXTI4 }, // EXTI4 + { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI5 + { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI6 + { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI7 + { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI8 + { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI9 + { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI10 + { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI11 + { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI12 + { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI13 + { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI14 + { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI15 +}; static inline void clear_pending(int bit) { - REG_SET(EXTI_PR, BIT(bit)); + __set_bits(EXTI_PR, BIT(bit)); /* 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. */ @@ -44,61 +66,39 @@ static inline void clear_pending(int bit) { asm volatile("nop"); } +static inline void dispatch_handler(uint32 channel) { + ASSERT(exti_channels[channel].handler); + if (exti_channels[channel].handler) { + (exti_channels[channel].handler)(); + } +} + /* For EXTI0 through EXTI4, only one handler * is associated with each channel, so we * don't have to keep track of which channel * we came from */ void EXTI0_IRQHandler(void) { - ASSERT(exti_handlers[EXTI0]); - if (exti_handlers[EXTI0]) { - exti_handlers[EXTI0](); - } - - /* Clear pending bit*/ + dispatch_handler(EXTI0); clear_pending(EXTI0); } void EXTI1_IRQHandler(void) { - ASSERT(exti_handlers[EXTI1]); - /* Call registered handler */ - if (exti_handlers[EXTI1]) { - exti_handlers[EXTI1](); - } - - /* Clear pending bit*/ + dispatch_handler(EXTI1); clear_pending(EXTI1); } void EXTI2_IRQHandler(void) { - ASSERT(exti_handlers[EXTI2]); - /* Call registered handler */ - if (exti_handlers[EXTI2]) { - exti_handlers[EXTI2](); - } - - /* Clear pending bit*/ + dispatch_handler(EXTI2); clear_pending(EXTI2); } void EXTI3_IRQHandler(void) { - ASSERT(exti_handlers[EXTI3]); - /* Call registered handler */ - if (exti_handlers[EXTI3]) { - exti_handlers[EXTI3](); - } - - /* Clear pending bit*/ + dispatch_handler(EXTI3); clear_pending(EXTI3); } void EXTI4_IRQHandler(void) { - ASSERT(exti_handlers[EXTI4]); - /* Call registered handler */ - if (exti_handlers[EXTI4]) { - exti_handlers[EXTI4](); - } - - /* Clear pending bit*/ + dispatch_handler(EXTI4); clear_pending(EXTI4); } @@ -112,8 +112,7 @@ void EXTI9_5_IRQHandler(void) { /* Dispatch every handler if the pending bit is set */ for (i = 0; i < 5; i++) { if (pending & 0x1) { - ASSERT(exti_handlers[EXTI5 + i]); - exti_handlers[EXTI5 + i](); + dispatch_handler(EXTI5 + i); clear_pending(EXTI5 + i); } pending >>= 1; @@ -130,8 +129,7 @@ void EXTI15_10_IRQHandler(void) { /* Dispatch every handler if the pending bit is set */ for (i = 0; i < 6; i++) { if (pending & 0x1) { - ASSERT(exti_handlers[EXTI10 + i]); - exti_handlers[EXTI10 + i](); + dispatch_handler(EXTI10 + i); clear_pending(EXTI10 + i); } pending >>= 1; @@ -139,147 +137,73 @@ void EXTI15_10_IRQHandler(void) { } -void exti_attach_interrupt(uint8 channel, uint8 port, voidFuncPtr handler, uint8 mode) { - ASSERT(channel < NR_EXTI_CHANNELS); - ASSERT(port < NR_EXTI_PORTS); - ASSERT(mode < NR_EXTI_MODES); - ASSERT(EXTI0 == 0); - ASSERT(handler); +/** + * @brief Register a handler to run upon external interrupt + * @param port source port of pin (eg EXTI_CONFIG_PORTA) + * @param pin pin number on the source port + * @param handler function handler to execute + * @param mode type of transition to trigger on + */ +void exti_attach_interrupt(uint32 port, + uint32 pin, + voidFuncPtr handler, + uint32 mode) { + static uint32 afio_regs[] = { + AFIO_EXTICR1, // EXT0-3 + AFIO_EXTICR2, // EXT4-7 + AFIO_EXTICR3, // EXT8-11 + AFIO_EXTICR4, // EXT12-15 + }; /* Note: All of the following code assumes that EXTI0 = 0 */ + ASSERT(EXTI0 == 0); + ASSERT(handler); - /* Map port to the correct EXTI channel */ - switch (channel) { - case EXTI0: - case EXTI1: - case EXTI2: - case EXTI3: - REG_SET_MASK(AFIO_EXTICR1, BIT_MASK_SHIFT(port, channel*4)); - break; - - case EXTI4: - case EXTI5: - case EXTI6: - case EXTI7: - REG_SET_MASK(AFIO_EXTICR2, BIT_MASK_SHIFT(port, (channel-4)*4)); - break; - - case EXTI8: - case EXTI9: - case EXTI10: - case EXTI11: - REG_SET_MASK(AFIO_EXTICR3, BIT_MASK_SHIFT(port, (channel-8)*4)); - break; + uint32 channel = pin; - case EXTI12: - case EXTI13: - case EXTI14: - case EXTI15: - REG_SET_MASK(AFIO_EXTICR4, BIT_MASK_SHIFT(port, (channel-12)*4)); - break; - } + /* map port to channel */ + __write(afio_regs[pin/4], (port << ((pin % 4) * 4))); /* Unmask appropriate interrupt line */ - REG_SET_BIT(EXTI_IMR, channel); + __set_bits(EXTI_IMR, BIT(channel)); /* Set trigger mode */ switch (mode) { case EXTI_RISING: - REG_SET_BIT(EXTI_RTSR, channel); + __set_bits(EXTI_RTSR, BIT(channel)); break; case EXTI_FALLING: - REG_SET_BIT(EXTI_FTSR, channel); + __set_bits(EXTI_FTSR, BIT(channel)); break; case EXTI_RISING_FALLING: - REG_SET_BIT(EXTI_RTSR, channel); - REG_SET_BIT(EXTI_FTSR, channel); + __set_bits(EXTI_RTSR, BIT(channel)); + __set_bits(EXTI_FTSR, BIT(channel)); break; } /* Configure the enable interrupt bits for the NVIC */ - switch (channel) { - case EXTI0: - case EXTI1: - case EXTI2: - case EXTI3: - case EXTI4: - REG_SET(NVIC_ISER0, BIT(channel + 6)); - break; - - /* EXTI5-9 map to the same isr */ - case EXTI5: - case EXTI6: - case EXTI7: - case EXTI8: - case EXTI9: - REG_SET(NVIC_ISER0, BIT(23)); - break; - - /* EXTI10-15 map to the same isr */ - case EXTI10: - case EXTI11: - case EXTI12: - case EXTI13: - case EXTI14: - case EXTI15: - REG_SET(NVIC_ISER1, BIT(8)); - break; - } + nvic_irq_enable(exti_channels[channel].irq_line); /* Register the handler */ - exti_handlers[channel] = handler; + exti_channels[channel].handler = handler; } -void exti_detach_interrupt(uint8 channel) { +/** + * @brief Unregister an external interrupt handler + * @param channel channel to disable (eg EXTI0) + */ +void exti_detach_interrupt(uint32 channel) { ASSERT(channel < NR_EXTI_CHANNELS); ASSERT(EXTI0 == 0); - /* Is this interrupt actually on? */ - ASSERT((REG_GET(EXTI_IMR) >> channel) & 0x01); - - /* Clear EXTI_IMR line */ - REG_CLEAR_BIT(EXTI_IMR, channel); - - /* Clear triggers */ - REG_CLEAR_BIT(EXTI_FTSR, channel); - REG_CLEAR_BIT(EXTI_RTSR, channel); - - /* Turn off the associated interrupt */ - switch (channel) { - case EXTI0: - case EXTI1: - case EXTI2: - case EXTI3: - case EXTI4: - REG_SET(NVIC_ICER0, BIT(channel + 6)); - break; - case EXTI5: - case EXTI6: - case EXTI7: - case EXTI8: - case EXTI9: - /* Are there any other channels enabled? - * If so, don't disable the interrupt handler */ - if (GET_BITS(REG_GET(EXTI_IMR), 5, 9) == 0) { - REG_SET(NVIC_ICER0, BIT(23)); - } - break; - case EXTI10: - case EXTI11: - case EXTI12: - case EXTI13: - case EXTI14: - case EXTI15: - /* Are there any other channels enabled? - * If so, don't disable the interrupt handler */ - if (GET_BITS(REG_GET(EXTI_IMR), 10, 15) == 0) { - REG_SET(NVIC_ICER1, BIT(8)); - } - break; - } - /* Clear handler function pointer */ - exti_handlers[channel] = 0; + __clear_bits(EXTI_IMR, BIT(channel)); + __clear_bits(EXTI_FTSR, BIT(channel)); + __clear_bits(EXTI_RTSR, BIT(channel)); + + nvic_irq_disable(exti_channels[channel].irq_line); + + exti_channels[channel].handler = NULL; } diff --git a/libmaple/exti.h b/libmaple/exti.h index 2832e24..97cb4aa 100644 --- a/libmaple/exti.h +++ b/libmaple/exti.h @@ -100,6 +100,10 @@ #define NR_EXTI_CHANNELS 16 #define NR_EXTI_PORTS NR_GPIO_PORTS // board specific +#define EXTI_RISING 0 +#define EXTI_FALLING 1 +#define EXTI_RISING_FALLING 2 + #define EXTI_IMR 0x40010400 // Interrupt mask register #define EXTI_EMR (EXTI_IMR + 0x04) // Event mask register #define EXTI_RTSR (EXTI_IMR + 0x08) // Rising trigger selection register @@ -113,10 +117,6 @@ #define AFIO_EXTICR3 (AFIO_EVCR + 0x10) #define AFIO_EXTICR4 (AFIO_EVCR + 0x14) -#define EXTI_RISING 0 -#define EXTI_FALLING 1 -#define EXTI_RISING_FALLING 2 - #define EXTI0 0 #define EXTI1 1 #define EXTI2 2 @@ -142,13 +142,12 @@ #define EXTI_CONFIG_PORTF 5 // Native only #define EXTI_CONFIG_PORTG 6 // Native only - #ifdef __cplusplus extern "C"{ #endif -void exti_attach_interrupt(uint8, uint8, voidFuncPtr, uint8); -void exti_detach_interrupt(uint8); +void exti_attach_interrupt(uint32, uint32, voidFuncPtr, uint32); +void exti_detach_interrupt(uint32); #ifdef __cplusplus } // extern "C" diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h index d49f95a..da3c241 100644 --- a/libmaple/libmaple_types.h +++ b/libmaple/libmaple_types.h @@ -45,5 +45,9 @@ typedef void (*voidFuncPtr)(void); #define __io volatile +#ifndef NULL +#define NULL 0 +#endif + #endif diff --git a/libmaple/nvic.h b/libmaple/nvic.h index 3286357..ab56f0e 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -31,8 +31,6 @@ #define NVIC_INT_USBHP 19 #define NVIC_INT_USBLP 20 -#define NVIC_EXTI1_OFFSET (NVIC_ISER0 + 0x07) -#define NVIC_EXTI9_5_OFFSET (NVIC_ISER0 + 0x17) /* NVIC Interrupt Enable registers */ #define NVIC_ISER0 0xE000E100 @@ -57,19 +55,28 @@ extern "C"{ #endif enum { - NVIC_TIMER1 = 27, - NVIC_TIMER2 = 28, - NVIC_TIMER3 = 29, - NVIC_TIMER4 = 30, - NVIC_TIMER5 = 50, // high density only (Maple Native) - NVIC_TIMER6 = 54, // high density only (Maple Native) - NVIC_TIMER7 = 55, // high density only (Maple Native) - NVIC_TIMER8 = 46, // high density only (Maple Native) - NVIC_USART1 = 37, - NVIC_USART2 = 38, - NVIC_USART3 = 39, - NVIC_USART4 = 52, // high density only (Maple Native) - NVIC_USART5 = 53, // high density only (Maple Native) + NVIC_TIMER1 = 27, + NVIC_TIMER2 = 28, + NVIC_TIMER3 = 29, + NVIC_TIMER4 = 30, + NVIC_TIMER5 = 50, // high density only (Maple Native) + NVIC_TIMER6 = 54, // high density only (Maple Native) + NVIC_TIMER7 = 55, // high density only (Maple Native) + NVIC_TIMER8 = 46, // high density only (Maple Native) + + NVIC_USART1 = 37, + NVIC_USART2 = 38, + NVIC_USART3 = 39, + NVIC_USART4 = 52, // high density only (Maple Native) + NVIC_USART5 = 53, // high density only (Maple Native) + + NVIC_EXTI0 = 6, + NVIC_EXTI1 = 7, + NVIC_EXTI2 = 8, + NVIC_EXTI3 = 9, + NVIC_EXTI4 = 10, + NVIC_EXTI9_5 = 23, + NVIC_EXTI15_10 = 40, }; |