19
19
#include "error.h"
20
20
#include "gpio_api.h"
21
21
22
- // The chip is capable of 4 external interrupts.
23
- #define CHANNEL_NUM 4
22
+ // The chip is capable of 42 GPIO interrupts.
23
+ // PIO0_0..PIO0_11, PIO1_0..PIO1_11, PIO2_0..PIO2_11, PIO3_0..PIO3_5
24
+ #define CHANNEL_NUM 42
24
25
25
26
static uint32_t channel_ids [CHANNEL_NUM ] = {0 };
26
27
static gpio_irq_handler irq_handler ;
27
- static PinName pin_names [CHANNEL_NUM ] = {};
28
- static uint8_t trigger_events [CHANNEL_NUM ] = {};
29
28
30
- static inline void handle_interrupt_in (uint32_t channel ) {
29
+ static inline int numofbits (uint32_t bits )
30
+ {
31
+ // Count number of bits
32
+ bits = (bits & 0x55555555 ) + (bits >> 1 & 0x55555555 );
33
+ bits = (bits & 0x33333333 ) + (bits >> 2 & 0x33333333 );
34
+ bits = (bits & 0x0f0f0f0f ) + (bits >> 4 & 0x0f0f0f0f );
35
+ bits = (bits & 0x00ff00ff ) + (bits >> 8 & 0x00ff00ff );
36
+ return (bits & 0x0000ffff ) + (bits >>16 & 0x0000ffff );
37
+ }
38
+
39
+ static inline void handle_interrupt_in (uint32_t port ) {
31
40
// Find out whether the interrupt has been triggered by a high or low value...
32
41
// As the LPC1114 doesn't have a specific register for this, we'll just have to read
33
42
// the level of the pin as if it were just a normal input...
34
-
43
+
44
+ uint32_t channel ;
45
+
35
46
// Get the number of the pin being used and the port typedef
36
- LPC_GPIO_TypeDef * port_reg = ((LPC_GPIO_TypeDef * ) (LPC_GPIO0_BASE + (((pin_names [channel ] & 0xF000 ) >> PORT_SHIFT ) * 0x10000 )));
37
- uint8_t pin_num = (pin_names [channel ] & (0x0f << PIN_SHIFT )) >> PIN_SHIFT ;
38
- uint8_t trigger_event = trigger_events [channel ];
39
-
40
- if (trigger_event == 1 )
41
- irq_handler (channel_ids [channel ], IRQ_RISE );
42
- else if (trigger_event == 2 )
43
- irq_handler (channel_ids [channel ], IRQ_FALL );
44
- else {
45
- // In order to get an idea of which kind of event it is,
46
- // We need to read the logic level of the pin...
47
-
48
- uint8_t logic = (port_reg -> DATA & (1 << pin_num )) >> pin_num ;
49
-
50
- if (logic == 1 )
47
+ LPC_GPIO_TypeDef * port_reg = ((LPC_GPIO_TypeDef * ) (LPC_GPIO0_BASE + (port * 0x10000 )));
48
+
49
+ // Get index of function table from Mask Interrupt Status register
50
+ channel = numofbits (port_reg -> MIS - 1 );
51
+
52
+ if (port_reg -> MIS & port_reg -> IBE ) {
53
+ // both edge, read the level of pin
54
+ if ((port_reg -> DATA & port_reg -> MIS ) != 0 )
51
55
irq_handler (channel_ids [channel ], IRQ_RISE );
52
56
else
53
57
irq_handler (channel_ids [channel ], IRQ_FALL );
54
58
}
59
+ else if (port_reg -> MIS & port_reg -> IEV ) {
60
+ irq_handler (channel_ids [channel ], IRQ_RISE );
61
+ }
62
+ else {
63
+ irq_handler (channel_ids [channel ], IRQ_FALL );
64
+ }
55
65
56
66
// Clear the interrupt...
57
- port_reg -> IC |= 1 << pin_num ;
67
+ port_reg -> IC = port_reg -> MIS ;
58
68
}
59
69
60
70
void gpio_irq0 (void ) {handle_interrupt_in (0 );}
@@ -63,48 +73,51 @@ void gpio_irq2(void) {handle_interrupt_in(2);}
63
73
void gpio_irq3 (void ) {handle_interrupt_in (3 );}
64
74
65
75
int gpio_irq_init (gpio_irq_t * obj , PinName pin , gpio_irq_handler handler , uint32_t id ) {
76
+ int channel ;
77
+ uint32_t port_num ;
78
+
66
79
if (pin == NC ) return -1 ;
67
80
68
81
// Firstly, we'll put some data in *obj so we can keep track of stuff.
69
82
obj -> pin = pin ;
70
-
71
- // Set the handler to be the pointer at the top...
72
- irq_handler = handler ;
73
-
83
+
84
+ // Set the handler to be the pointer at the top...
85
+ irq_handler = handler ;
86
+
74
87
// Which port are we using?
75
- int channel ;
76
- uint32_t port_reg = (LPC_GPIO0_BASE + (((pin & 0xF000 ) >> PORT_SHIFT ) * 0x10000 ));
77
-
78
- switch (port_reg ) {
79
- case LPC_GPIO0_BASE :
88
+ port_num = ((pin & 0xF000 ) >> PORT_SHIFT );
89
+
90
+ switch (port_num ) {
91
+ case 0 :
80
92
NVIC_SetVector (EINT0_IRQn , (uint32_t )gpio_irq0 );
81
93
NVIC_EnableIRQ (EINT0_IRQn );
82
- channel = 0 ;
83
94
break ;
84
- case LPC_GPIO1_BASE :
95
+ case 1 :
85
96
NVIC_SetVector (EINT1_IRQn , (uint32_t )gpio_irq1 );
86
97
NVIC_EnableIRQ (EINT1_IRQn );
87
- channel = 1 ;
88
98
break ;
89
- case LPC_GPIO2_BASE :
99
+ case 2 :
90
100
NVIC_SetVector (EINT2_IRQn , (uint32_t )gpio_irq2 );
91
101
NVIC_EnableIRQ (EINT2_IRQn );
92
- channel = 2 ;
93
102
break ;
94
- case LPC_GPIO3_BASE :
103
+ case 3 :
95
104
NVIC_SetVector (EINT3_IRQn , (uint32_t )gpio_irq3 );
96
105
NVIC_EnableIRQ (EINT3_IRQn );
97
- channel = 3 ;
98
106
break ;
99
107
default :
100
- channel = -1 ;
101
- error ("Invalid interrupt choice." );
102
- break ;
108
+ return -1 ;
103
109
}
104
-
110
+
111
+ // Generate index of function pointer table
112
+ // PIO0_0 - PIO0_11 : 0..11
113
+ // PIO1_0 - PIO1_11 : 12..23
114
+ // PIO2_0 - PIO2_11 : 24..35
115
+ // PIO3_0 - PIO3_5 : 36..41
116
+ channel = (port_num * 12 ) + ((pin & 0x0F00 ) >> PIN_SHIFT );
117
+
105
118
channel_ids [channel ] = id ;
106
- pin_names [channel ] = pin ;
107
119
obj -> ch = channel ;
120
+
108
121
return 0 ;
109
122
}
110
123
@@ -118,49 +131,46 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
118
131
LPC_GPIO_TypeDef * port_reg = ((LPC_GPIO_TypeDef * ) (LPC_GPIO0_BASE + (((obj -> pin & 0xF000 ) >> PORT_SHIFT ) * 0x10000 )));
119
132
120
133
// Need to get the pin number of the pin, not the value of the enum
121
- uint8_t pin_num = (obj -> pin & ( 0x0f << PIN_SHIFT )) >> PIN_SHIFT ;
134
+ uint32_t pin_num = (1 << (( obj -> pin & 0x0f00 ) >> PIN_SHIFT )) ;
122
135
136
+ // Clear
137
+ port_reg -> IC |= pin_num ;
138
+
139
+ // Make it edge sensitive.
140
+ port_reg -> IS &= ~pin_num ;
123
141
124
- if (trigger_events [ obj -> ch ] != 0 ) {
125
- // We have an event.
126
- // Enable both edge interrupts.
142
+ if ( ( port_reg -> IE & pin_num ) != 0 ) {
143
+ // We have an event.
144
+ // Enable both edge interrupts.
127
145
128
146
if (enable ) {
129
- trigger_events [obj -> ch ] = 3 ;
130
- port_reg -> IBE |= 1 << pin_num ;
131
- port_reg -> IE |= 1 << pin_num ;
147
+ port_reg -> IBE |= pin_num ;
148
+ port_reg -> IE |= pin_num ;
132
149
}
133
150
else {
134
151
// These all need to be opposite, to reenable the other one.
135
- trigger_events [obj -> ch ] = event == IRQ_RISE ? 2 : 1 ;
136
-
137
- port_reg -> IBE &= ~(1 << pin_num );
152
+ port_reg -> IBE &= ~pin_num ;
138
153
139
154
if (event == IRQ_RISE )
140
- port_reg -> IEV &= ~( 1 << pin_num ) ;
155
+ port_reg -> IEV &= ~pin_num ;
141
156
else
142
- port_reg -> IEV |= 1 << pin_num ;
157
+ port_reg -> IEV |= pin_num ;
143
158
144
- port_reg -> IE |= 1 << pin_num ;
159
+ port_reg -> IE |= pin_num ;
145
160
}
146
161
}
147
162
else {
148
- if (enable ) {
149
- trigger_events [obj -> ch ] = event == IRQ_RISE ? 1 : 2 ;
150
- port_reg -> IE |= 1 << pin_num ;
151
- }
152
163
// One edge
153
- port_reg -> IBE &= ~( 1 << pin_num ) ;
164
+ port_reg -> IBE &= ~pin_num ;
154
165
// Rising/falling?
155
166
if (event == IRQ_RISE )
156
- port_reg -> IEV |= 1 << pin_num ;
167
+ port_reg -> IEV |= pin_num ;
157
168
else
158
- port_reg -> IEV &= ~(1 << pin_num );
169
+ port_reg -> IEV &= ~pin_num ;
170
+
171
+ if (enable ) {
172
+ port_reg -> IE |= pin_num ;
173
+ }
159
174
}
160
175
161
- // Clear
162
- port_reg -> IC |= 1 << pin_num ;
163
-
164
- // Make it edge sensitive.
165
- port_reg -> IS &= ~(1 << pin_num );
166
176
}
0 commit comments