diff options
author | Perry Hung <iperry@gmail.com> | 2010-09-22 03:17:45 -0400 |
---|---|---|
committer | Perry Hung <iperry@gmail.com> | 2010-09-22 03:17:45 -0400 |
commit | c13e850abe053edaa1aad6ef7b928c6bf9288cb3 (patch) | |
tree | fb8cbe016ce5d45210e311f45511ccabc437db8a /libmaple | |
parent | 89cd6296ea10658c87b6dddf75a46308437dbb17 (diff) | |
download | librambutan-c13e850abe053edaa1aad6ef7b928c6bf9288cb3.tar.gz librambutan-c13e850abe053edaa1aad6ef7b928c6bf9288cb3.zip |
Enable external interrupts on all Maple GPIOs.
Extend the wirish attachInterrupt() and detachInterrupt() interface to
work with all GPIOs.
Note: The STM32 external interrupt lines are multiplexed between GPIO
ports. While any GPIO can be used as an external interrupt, not all of
them can be used at the same time. Each EXTI[n] line selects between
PA[n], PB[n], PC[n], etc. For example, line EXTI5 can be used with STM32
pins PA5, PB5, or PC5, but not all at the same time. See table:
EXTI Line Maple Pin STM32 Pin
0 D2 PA0
0 D27 PB0
0 D15 PC0
1 D3 PA1
1 D28 PB1
1 D16 PC1
2 D1 PA2
2 D17 PC2
2 D25 PD2
3 D0 PA3
3 D18 PC3
4 D10 PA4
4 D19 PC4
5 D13 PA5
5 D4 PB5
5 D20 PC5
6 D12 PA6
6 D5 PB6
6 D35 PC6
7 D11 PA7
7 D9 PB7
7 D36 PC7
8 D6 PA8
8 D14 PB8
8 D37 PC8
9 D7 PA9
9 D24 PB9
9 D38 PC9 (BUT)
10 D8 PA10
10 D29 PB10
10 D26 PC10
11 D30 PB11
12 D31 PB12
13 D32 PB13
13 D21 PC13
14 D33 PB14
14 D22 PC14
15 D34 PB15
15 D23 PC15
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, }; |