18
18
#include "gpio_irq_api.h"
19
19
#include "error.h"
20
20
21
+ // The chip is capable of 4 external interrupts.
21
22
#define CHANNEL_NUM 4
22
- #define PININT_IRQ 28+3
23
23
24
24
static uint32_t channel_ids [CHANNEL_NUM ] = {0 };
25
25
static gpio_irq_handler irq_handler ;
26
- #warning TODO(@toyowata): need implimentation
27
- #if 0
28
- static inline void handle_interrupt_in (uint32_t channel ) {
29
- uint32_t ch_bit = (1 << channel );
26
+ static int channel = 0 ;
27
+ static PinName pin_names [CHANNEL_NUM ] = {};
30
28
31
- LPC_GPIO_TypeDef * port_reg = ((LPC_GPIO_TypeDef * ) LPC_GPIO0_BASE + (channel * 0x10000 ));
29
+ static inline void handle_interrupt_in (uint32_t channel ) {
30
+ // Find out whether the interrupt has been triggered by a high or low value...
31
+ // As the LPC1114 doesn't have a specific register for this, we'll just have to read
32
+ // the level of the pin as if it were just a normal input...
32
33
33
- // Return immediately if:
34
- // * The interrupt was already served
35
- // * There is no user handler
36
- // * It is a level interrupt, not an edge interrupt
37
- if ( ((& port_reg -> IST & ch_bit ) == 0 ) ||
38
- (channel_ids [channel ] == 0 ) ||
39
- (& port_reg -> ISEL & ch_bit ) ) return ;
34
+ // Get the number of the pin being used and the port typedef
35
+ uint32_t pin = (pin_names [channel ] & (0x0f << 8 )) >> 8 ;
36
+ LPC_GPIO_TypeDef * port_reg = ((LPC_GPIO_TypeDef * ) (LPC_GPIO0_BASE + (((pin & 0xF000 ) >> PORT_SHIFT ) * 0x10000 )));
37
+ uint32_t logiclevel = port_reg -> DATA ;
38
+ logiclevel &= (uint32_t )(1 << pin ) >> pin ;
40
39
41
- if ((& port_reg -> IENR & ch_bit ) && (& port_reg -> RISE & ch_bit )) {
40
+ if (logiclevel == 1 ) {
41
+ // High, therefore rising edge...
42
42
irq_handler (channel_ids [channel ], IRQ_RISE );
43
- & port_reg -> RISE = ch_bit ;
44
43
}
45
- if ((& port_reg -> IENF & ch_bit ) && (& port_reg -> FALL & ch_bit )) {
44
+ else {
45
+ // Low, therefore falling edge...
46
46
irq_handler (channel_ids [channel ], IRQ_FALL );
47
47
}
48
- & port_reg -> IST = ch_bit ;
49
48
}
50
49
51
50
void gpio_irq0 (void ) {handle_interrupt_in (0 );}
@@ -56,77 +55,75 @@ void gpio_irq3(void) {handle_interrupt_in(3);}
56
55
int gpio_irq_init (gpio_irq_t * obj , PinName pin , gpio_irq_handler handler , uint32_t id ) {
57
56
if (pin == NC ) return -1 ;
58
57
59
- irq_handler = handler ;
60
-
61
- int found_free_channel = 0 ;
62
- int i = 0 ;
63
- for ( i = 0 ; i < CHANNEL_NUM ; i ++ ) {
64
- if ( channel_ids [ i ] == 0 ) {
65
- channel_ids [ i ] = id ;
66
- obj -> ch = i ;
67
- found_free_channel = 1 ;
68
- break ;
58
+ // Firstly, we'll put some data in *obj so we can keep track of stuff.
59
+ obj -> pin = pin ;
60
+
61
+ /*
62
+ If there are any ports or pins that aren't able to handle interrupts, put them here and uncomment.
63
+
64
+ if (pin == ... ||
65
+ pin == ...) {
66
+ error("This pin does not suppor interrupts.") ;
67
+ return -1 ;
69
68
}
69
+ */
70
+
71
+ channel_ids [channel ] = id ;
72
+ pin_names [channel ] = pin ;
73
+ obj -> ch = channel ;
74
+
75
+ // Which port are we using?
76
+ switch (channel ) {
77
+ case 0 :
78
+ NVIC_SetVector (EINT0_IRQn , (uint32_t )gpio_irq0 );
79
+ NVIC_EnableIRQ (EINT0_IRQn );
80
+ break ;
81
+ case 1 :
82
+ NVIC_SetVector (EINT1_IRQn , (uint32_t )gpio_irq1 );
83
+ NVIC_EnableIRQ (EINT1_IRQn );
84
+ break ;
85
+ case 2 :
86
+ NVIC_SetVector (EINT2_IRQn , (uint32_t )gpio_irq2 );
87
+ NVIC_EnableIRQ (EINT2_IRQn );
88
+ break ;
89
+ case 3 :
90
+ NVIC_SetVector (EINT3_IRQn , (uint32_t )gpio_irq3 );
91
+ NVIC_EnableIRQ (EINT3_IRQn );
92
+ break ;
70
93
}
71
- if (!found_free_channel ) return -1 ;
72
-
73
- /* Enable AHB clock to the GPIO domain. */
74
- LPC_SYSCON -> SYSAHBCLKCTRL |= (1 <<6 );
75
-
76
- /* Enable AHB clock to the FlexInt, GroupedInt domain. */
77
- LPC_SYSCON -> SYSAHBCLKCTRL |= ((1 <<19 ) | (1 <<23 ) | (1 <<24 ));
78
-
79
- /* To select a pin for any of the eight pin interrupts, write the pin number
80
- * as 0 to 23 for pins PIO0_0 to PIO0_23 and 24 to 55.
81
- * @see: mbed_capi/PinNames.h
82
- */
83
- LPC_SYSCON -> PINTSEL [obj -> ch ] = (pin >> 5 ) ? (pin - 8 ) : (pin );
84
-
85
- // Interrupt Wake-Up Enable
86
- LPC_SYSCON -> STARTERP0 |= 1 << obj -> ch ;
87
-
88
- void (* channels_irq )(void ) = NULL ;
89
- switch (obj -> ch ) {
90
- case 0 : channels_irq = & gpio_irq0 ; break ;
91
- case 1 : channels_irq = & gpio_irq1 ; break ;
92
- case 2 : channels_irq = & gpio_irq2 ; break ;
93
- case 3 : channels_irq = & gpio_irq3 ; break ;
94
- }
95
- NVIC_SetVector ((IRQn_Type )(PININT_IRQ - obj -> ch )), (uint32_t )channels_irq );
96
- NVIC_EnableIRQ ((IRQn_Type )(PININT_IRQ - obj -> ch ));
97
-
94
+
95
+ channel ++ ;
98
96
return 0 ;
99
97
}
100
98
101
99
void gpio_irq_free (gpio_irq_t * obj ) {
102
100
channel_ids [obj -> ch ] = 0 ;
103
- LPC_SYSCON -> STARTERP0 &= ~(1 << obj -> ch );
104
101
}
105
102
106
103
void gpio_irq_set (gpio_irq_t * obj , gpio_irq_event event , uint32_t enable ) {
107
- unsigned int ch_bit = (1 << obj -> ch );
108
-
109
- LPC_GPIO_TypeDef * port_reg = ((LPC_GPIO_TypeDef * ) LPC_GPIO0_BASE + (obj -> ch * 0x10000 ));
104
+ LPC_GPIO_TypeDef * port_reg = ((LPC_GPIO_TypeDef * ) (LPC_GPIO0_BASE + (((obj -> pin & 0xF000 ) >> PORT_SHIFT ) * 0x10000 )));
110
105
111
- // Clear interrupt
112
- if (!(& port_reg -> ISEL & ch_bit ))
113
- & port_reg -> IST = ch_bit ;
106
+ /*
107
+ Firstly, clear the interrupts for this pin,
108
+ Then, let the registers know whether we're looking for edge detection,
109
+ Enable the interrupt,
110
+ And set it to only respond to interrupts on one edge.
111
+ */
114
112
115
- // Edge trigger
116
- & port_reg -> ISEL &= ~ch_bit ;
117
- if (event == IRQ_RISE ) {
118
- if (enable ) {
119
- & port_reg -> IENR |= ch_bit ;
120
- } else {
121
- & port_reg -> IENR &= ~ch_bit ;
122
- }
123
- } else {
124
- if (enable ) {
125
- & port_reg -> IENF |= ch_bit ;
126
- } else {
127
- & port_reg -> IENF &= ~ch_bit ;
128
- }
129
- }
113
+ // Clear
114
+ port_reg -> IC |= 1 << obj -> pin ;
115
+
116
+ // Edge
117
+ port_reg -> IS &= ~(1 << obj -> pin );
118
+
119
+ // Enable
120
+ if (enable ) port_reg -> IE |= 1 << obj -> pin ;
121
+ else port_reg -> IE &= ~(1 << obj -> pin );
122
+
123
+ // One edge
124
+ port_reg -> IBE &= ~(1 << obj -> pin );
125
+
126
+ // Rising/falling?
127
+ if (event == IRQ_RISE ) port_reg -> IEV |= 1 << obj -> pin ;
128
+ else port_reg -> IEV &= ~(1 << obj -> pin );
130
129
}
131
-
132
- #endif
0 commit comments