Skip to content

Commit 1ff64de

Browse files
committed
Fixed gpio_irq_api bugs
Corrected improper implementation of channel_ids[] usage. Revemod redundant arrays e.g. pin_names[] and trigger_events[]
1 parent 463bf47 commit 1ff64de

File tree

1 file changed

+78
-68
lines changed

1 file changed

+78
-68
lines changed

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX/gpio_irq_api.c

Lines changed: 78 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -19,42 +19,52 @@
1919
#include "error.h"
2020
#include "gpio_api.h"
2121

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
2425

2526
static uint32_t channel_ids[CHANNEL_NUM] = {0};
2627
static gpio_irq_handler irq_handler;
27-
static PinName pin_names[CHANNEL_NUM] = {};
28-
static uint8_t trigger_events[CHANNEL_NUM] = {};
2928

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) {
3140
// Find out whether the interrupt has been triggered by a high or low value...
3241
// As the LPC1114 doesn't have a specific register for this, we'll just have to read
3342
// the level of the pin as if it were just a normal input...
34-
43+
44+
uint32_t channel;
45+
3546
// 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)
5155
irq_handler(channel_ids[channel], IRQ_RISE);
5256
else
5357
irq_handler(channel_ids[channel], IRQ_FALL);
5458
}
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+
}
5565

5666
// Clear the interrupt...
57-
port_reg->IC |= 1 << pin_num;
67+
port_reg->IC = port_reg->MIS;
5868
}
5969

6070
void gpio_irq0(void) {handle_interrupt_in(0);}
@@ -63,48 +73,51 @@ void gpio_irq2(void) {handle_interrupt_in(2);}
6373
void gpio_irq3(void) {handle_interrupt_in(3);}
6474

6575
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+
6679
if (pin == NC) return -1;
6780

6881
// Firstly, we'll put some data in *obj so we can keep track of stuff.
6982
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+
7487
// 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:
8092
NVIC_SetVector(EINT0_IRQn, (uint32_t)gpio_irq0);
8193
NVIC_EnableIRQ(EINT0_IRQn);
82-
channel = 0;
8394
break;
84-
case LPC_GPIO1_BASE:
95+
case 1:
8596
NVIC_SetVector(EINT1_IRQn, (uint32_t)gpio_irq1);
8697
NVIC_EnableIRQ(EINT1_IRQn);
87-
channel = 1;
8898
break;
89-
case LPC_GPIO2_BASE:
99+
case 2:
90100
NVIC_SetVector(EINT2_IRQn, (uint32_t)gpio_irq2);
91101
NVIC_EnableIRQ(EINT2_IRQn);
92-
channel = 2;
93102
break;
94-
case LPC_GPIO3_BASE:
103+
case 3:
95104
NVIC_SetVector(EINT3_IRQn, (uint32_t)gpio_irq3);
96105
NVIC_EnableIRQ(EINT3_IRQn);
97-
channel = 3;
98106
break;
99107
default:
100-
channel = -1;
101-
error("Invalid interrupt choice.");
102-
break;
108+
return -1;
103109
}
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+
105118
channel_ids[channel] = id;
106-
pin_names[channel] = pin;
107119
obj->ch = channel;
120+
108121
return 0;
109122
}
110123

@@ -118,49 +131,46 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
118131
LPC_GPIO_TypeDef *port_reg = ((LPC_GPIO_TypeDef *) (LPC_GPIO0_BASE + (((obj->pin & 0xF000) >> PORT_SHIFT) * 0x10000)));
119132

120133
// 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));
122135

136+
// Clear
137+
port_reg->IC |= pin_num;
138+
139+
// Make it edge sensitive.
140+
port_reg->IS &= ~pin_num;
123141

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.
127145

128146
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;
132149
}
133150
else {
134151
// 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;
138153

139154
if (event == IRQ_RISE)
140-
port_reg->IEV &= ~(1 << pin_num);
155+
port_reg->IEV &= ~pin_num;
141156
else
142-
port_reg->IEV |= 1 << pin_num;
157+
port_reg->IEV |= pin_num;
143158

144-
port_reg->IE |= 1 << pin_num;
159+
port_reg->IE |= pin_num;
145160
}
146161
}
147162
else {
148-
if (enable) {
149-
trigger_events[obj->ch] = event == IRQ_RISE ? 1 : 2;
150-
port_reg->IE |= 1 << pin_num;
151-
}
152163
// One edge
153-
port_reg->IBE &= ~(1 << pin_num);
164+
port_reg->IBE &= ~pin_num;
154165
// Rising/falling?
155166
if (event == IRQ_RISE)
156-
port_reg->IEV |= 1 << pin_num;
167+
port_reg->IEV |= pin_num;
157168
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+
}
159174
}
160175

161-
// Clear
162-
port_reg->IC |= 1 << pin_num;
163-
164-
// Make it edge sensitive.
165-
port_reg->IS &= ~(1 << pin_num);
166176
}

0 commit comments

Comments
 (0)