Skip to content

Commit 699c178

Browse files
committed
Increased KLxxZs interrupt handling speed
Instead of checking one bit at a time use a simple binary search algorithm. Speed increase is roughly 250% (bit more for KL46).
1 parent 9413ed9 commit 699c178

File tree

3 files changed

+126
-110
lines changed

3 files changed

+126
-110
lines changed

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KLXX/TARGET_KL05Z/gpio_irq_api.c

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -30,40 +30,45 @@ static gpio_irq_handler irq_handler;
3030
#define IRQ_FALLING_EDGE PORT_PCR_IRQC(10)
3131
#define IRQ_EITHER_EDGE PORT_PCR_IRQC(11)
3232

33+
const uint32_t search_bits[] = {0x0000FFFF, 0x000000FF, 0x0000000F, 0x00000003, 0x00000001};
34+
3335
static void handle_interrupt_in(PORT_Type *port, int ch_base) {
34-
uint32_t mask = 0, i;
35-
36-
for (i = 0; i < 32; i++) {
37-
uint32_t pmask = (1 << i);
38-
if (port->ISFR & pmask) {
39-
mask |= pmask;
40-
uint32_t id = channel_ids[ch_base + i];
41-
if (id == 0) {
42-
continue;
43-
}
36+
uint32_t isfr;
37+
uint8_t location;
38+
39+
while((isfr = port->ISFR) != 0) {
40+
location = 0;
41+
for (int i = 0; i < 5; i++) {
42+
if (!(isfr & (search_bits[i] << location)))
43+
location += 1 << (4 - i);
44+
}
45+
46+
uint32_t id = channel_ids[ch_base + location];
47+
if (id == 0) {
48+
continue;
49+
}
4450

45-
FGPIO_Type *gpio;
46-
gpio_irq_event event = IRQ_NONE;
47-
switch (port->PCR[i] & PORT_PCR_IRQC_MASK) {
48-
case IRQ_RAISING_EDGE:
49-
event = IRQ_RISE;
50-
break;
51-
52-
case IRQ_FALLING_EDGE:
53-
event = IRQ_FALL;
54-
break;
55-
56-
case IRQ_EITHER_EDGE:
57-
gpio = (port == PORTA) ? (FPTA) : (FPTB);
58-
event = (gpio->PDIR & pmask) ? (IRQ_RISE) : (IRQ_FALL);
59-
break;
60-
}
61-
if (event != IRQ_NONE) {
62-
irq_handler(id, event);
63-
}
51+
FGPIO_Type *gpio;
52+
gpio_irq_event event = IRQ_NONE;
53+
switch (port->PCR[location] & PORT_PCR_IRQC_MASK) {
54+
case IRQ_RAISING_EDGE:
55+
event = IRQ_RISE;
56+
break;
57+
58+
case IRQ_FALLING_EDGE:
59+
event = IRQ_FALL;
60+
break;
61+
62+
case IRQ_EITHER_EDGE:
63+
gpio = (port == PORTA) ? (FPTA) : (FPTB);
64+
event = (gpio->PDIR & (1 << location)) ? (IRQ_RISE) : (IRQ_FALL);
65+
break;
6466
}
67+
if (event != IRQ_NONE) {
68+
irq_handler(id, event);
69+
}
70+
port->ISFR = 1 << location;
6571
}
66-
port->ISFR = mask;
6772
}
6873

6974
/* IRQ only on PORTA and PORTB */
@@ -86,21 +91,21 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32
8691
uint32_t ch_base, vector;
8792
IRQn_Type irq_n;
8893
switch (obj->port) {
89-
case PortA:
90-
ch_base = 0;
91-
irq_n = PORTA_IRQn;
92-
vector = (uint32_t)gpio_irqA;
93-
break;
94-
95-
case PortB:
96-
ch_base = 32;
97-
irq_n = PORTB_IRQn;
98-
vector = (uint32_t)gpio_irqB;
99-
break;
100-
101-
default:
102-
error("gpio_irq only supported on Port A and B");
103-
break;
94+
case PortA:
95+
ch_base = 0;
96+
irq_n = PORTA_IRQn;
97+
vector = (uint32_t)gpio_irqA;
98+
break;
99+
100+
case PortB:
101+
ch_base = 32;
102+
irq_n = PORTB_IRQn;
103+
vector = (uint32_t)gpio_irqB;
104+
break;
105+
106+
default:
107+
error("gpio_irq only supported on Port A and B");
108+
break;
104109
}
105110
NVIC_SetVector(irq_n, vector);
106111
NVIC_EnableIRQ(irq_n);

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KLXX/TARGET_KL25Z/gpio_irq_api.c

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,40 +30,45 @@ static gpio_irq_handler irq_handler;
3030
#define IRQ_FALLING_EDGE PORT_PCR_IRQC(10)
3131
#define IRQ_EITHER_EDGE PORT_PCR_IRQC(11)
3232

33+
const uint32_t search_bits[] = {0x0000FFFF, 0x000000FF, 0x0000000F, 0x00000003, 0x00000001};
34+
3335
static void handle_interrupt_in(PORT_Type *port, int ch_base) {
34-
uint32_t mask = 0, i;
35-
36-
for (i = 0; i < 32; i++) {
37-
uint32_t pmask = (1 << i);
38-
if (port->ISFR & pmask) {
39-
mask |= pmask;
40-
uint32_t id = channel_ids[ch_base + i];
41-
if (id == 0) {
42-
continue;
43-
}
36+
uint32_t isfr;
37+
uint8_t location;
38+
39+
while((isfr = port->ISFR) != 0) {
40+
location = 0;
41+
for (int i = 0; i < 5; i++) {
42+
if (!(isfr & (search_bits[i] << location)))
43+
location += 1 << (4 - i);
44+
}
45+
46+
uint32_t id = channel_ids[ch_base + location];
47+
if (id == 0) {
48+
continue;
49+
}
4450

45-
FGPIO_Type *gpio;
46-
gpio_irq_event event = IRQ_NONE;
47-
switch (port->PCR[i] & PORT_PCR_IRQC_MASK) {
48-
case IRQ_RAISING_EDGE:
49-
event = IRQ_RISE;
50-
break;
51-
52-
case IRQ_FALLING_EDGE:
53-
event = IRQ_FALL;
54-
break;
55-
56-
case IRQ_EITHER_EDGE:
57-
gpio = (port == PORTA) ? (FPTA) : (FPTD);
58-
event = (gpio->PDIR & pmask) ? (IRQ_RISE) : (IRQ_FALL);
59-
break;
60-
}
61-
if (event != IRQ_NONE) {
62-
irq_handler(id, event);
63-
}
51+
FGPIO_Type *gpio;
52+
gpio_irq_event event = IRQ_NONE;
53+
switch (port->PCR[location] & PORT_PCR_IRQC_MASK) {
54+
case IRQ_RAISING_EDGE:
55+
event = IRQ_RISE;
56+
break;
57+
58+
case IRQ_FALLING_EDGE:
59+
event = IRQ_FALL;
60+
break;
61+
62+
case IRQ_EITHER_EDGE:
63+
gpio = (port == PORTA) ? (FPTA) : (FPTD);
64+
event = (gpio->PDIR & (1 << location)) ? (IRQ_RISE) : (IRQ_FALL);
65+
break;
66+
}
67+
if (event != IRQ_NONE) {
68+
irq_handler(id, event);
6469
}
70+
port->ISFR = 1 << location;
6571
}
66-
port->ISFR = mask;
6772
}
6873

6974
void gpio_irqA(void) {handle_interrupt_in(PORTA, 0);}

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KLXX/TARGET_KL46Z/gpio_irq_api.c

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,45 +30,51 @@ static gpio_irq_handler irq_handler;
3030
#define IRQ_FALLING_EDGE PORT_PCR_IRQC(10)
3131
#define IRQ_EITHER_EDGE PORT_PCR_IRQC(11)
3232

33+
const uint32_t search_bits[] = {0x0000FFFF, 0x000000FF, 0x0000000F, 0x00000003, 0x00000001};
34+
3335
static void handle_interrupt_in(PORT_Type *port, int ch_base) {
34-
uint32_t mask = 0, i;
35-
36-
for (i = 0; i < 32; i++) {
37-
uint32_t pmask = (1 << i);
38-
if (port->ISFR & pmask) {
39-
mask |= pmask;
40-
uint32_t id = channel_ids[ch_base + i];
41-
if (id == 0) {
42-
continue;
43-
}
36+
uint32_t isfr;
37+
uint8_t location;
38+
39+
while((isfr = port->ISFR) != 0) {
40+
location = 0;
41+
for (int i = 0; i < 5; i++) {
42+
if (!(isfr & (search_bits[i] << location)))
43+
location += 1 << (4 - i);
44+
}
45+
46+
uint32_t id = channel_ids[ch_base + location];
47+
if (id == 0) {
48+
continue;
49+
}
4450

45-
FGPIO_Type *gpio;
46-
gpio_irq_event event = IRQ_NONE;
47-
switch (port->PCR[i] & PORT_PCR_IRQC_MASK) {
48-
case IRQ_RAISING_EDGE:
49-
event = IRQ_RISE;
50-
break;
51-
52-
case IRQ_FALLING_EDGE:
53-
event = IRQ_FALL;
54-
break;
55-
56-
case IRQ_EITHER_EDGE:
57-
if (port == PORTA) {
58-
gpio = FPTA;
59-
} else if (port == PORTC) {
60-
gpio = FPTC;
61-
} else {
62-
gpio = FPTD;
63-
}
64-
event = (gpio->PDIR & pmask) ? (IRQ_RISE) : (IRQ_FALL);
65-
break;
66-
}
67-
if (event != IRQ_NONE)
68-
irq_handler(id, event);
51+
FGPIO_Type *gpio;
52+
gpio_irq_event event = IRQ_NONE;
53+
switch (port->PCR[location] & PORT_PCR_IRQC_MASK) {
54+
case IRQ_RAISING_EDGE:
55+
event = IRQ_RISE;
56+
break;
57+
58+
case IRQ_FALLING_EDGE:
59+
event = IRQ_FALL;
60+
break;
61+
62+
case IRQ_EITHER_EDGE:
63+
if (port == PORTA) {
64+
gpio = FPTA;
65+
} else if (port == PORTC) {
66+
gpio = FPTC;
67+
} else {
68+
gpio = FPTD;
69+
}
70+
event = (gpio->PDIR & (1<<location)) ? (IRQ_RISE) : (IRQ_FALL);
71+
break;
72+
}
73+
if (event != IRQ_NONE) {
74+
irq_handler(id, event);
6975
}
76+
port->ISFR = 1 << location;
7077
}
71-
port->ISFR = mask;
7278
}
7379

7480
void gpio_irqA(void) {

0 commit comments

Comments
 (0)