]> git.gir.st - tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/gpio_irq_api.c
Merge commit '4d116a04e94cf0d19317d5b44e4fa9f34a3e5594'
[tmk_keyboard.git] / tmk_core / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC176X / gpio_irq_api.c
1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2013 ARM Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <stddef.h>
17
18 #include "gpio_irq_api.h"
19 #include "mbed_error.h"
20 #include "cmsis.h"
21
22 #define CHANNEL_NUM 48
23
24 static uint32_t channel_ids[CHANNEL_NUM] = {0};
25 static gpio_irq_handler irq_handler;
26
27 static void handle_interrupt_in(void) {
28 // Read in all current interrupt registers. We do this once as the
29 // GPIO interrupt registers are on the APB bus, and this is slow.
30 uint32_t rise0 = LPC_GPIOINT->IO0IntStatR;
31 uint32_t fall0 = LPC_GPIOINT->IO0IntStatF;
32 uint32_t rise2 = LPC_GPIOINT->IO2IntStatR;
33 uint32_t fall2 = LPC_GPIOINT->IO2IntStatF;
34 uint8_t bitloc;
35
36 while(rise0 > 0) { //Continue as long as there are interrupts pending
37 bitloc = 31 - __CLZ(rise0); //CLZ returns number of leading zeros, 31 minus that is location of first pending interrupt
38 if (channel_ids[bitloc] != 0)
39 irq_handler(channel_ids[bitloc], IRQ_RISE); //Run that interrupt
40
41 //Both clear the interrupt with clear register, and remove it from our local copy of the interrupt pending register
42 LPC_GPIOINT->IO0IntClr = 1 << bitloc;
43 rise0 -= 1<<bitloc;
44 }
45
46 while(fall0 > 0) { //Continue as long as there are interrupts pending
47 bitloc = 31 - __CLZ(fall0); //CLZ returns number of leading zeros, 31 minus that is location of first pending interrupt
48 if (channel_ids[bitloc] != 0)
49 irq_handler(channel_ids[bitloc], IRQ_FALL); //Run that interrupt
50
51 //Both clear the interrupt with clear register, and remove it from our local copy of the interrupt pending register
52 LPC_GPIOINT->IO0IntClr = 1 << bitloc;
53 fall0 -= 1<<bitloc;
54 }
55
56 //Same for port 2, only we need to watch the channel_index
57 while(rise2 > 0) { //Continue as long as there are interrupts pending
58 bitloc = 31 - __CLZ(rise2); //CLZ returns number of leading zeros, 31 minus that is location of first pending interrupt
59
60 if (bitloc < 16) //Not sure if this is actually needed
61 if (channel_ids[bitloc+32] != 0)
62 irq_handler(channel_ids[bitloc+32], IRQ_RISE); //Run that interrupt
63
64 //Both clear the interrupt with clear register, and remove it from our local copy of the interrupt pending register
65 LPC_GPIOINT->IO2IntClr = 1 << bitloc;
66 rise2 -= 1<<bitloc;
67 }
68
69 while(fall2 > 0) { //Continue as long as there are interrupts pending
70 bitloc = 31 - __CLZ(fall2); //CLZ returns number of leading zeros, 31 minus that is location of first pending interrupt
71
72 if (bitloc < 16) //Not sure if this is actually needed
73 if (channel_ids[bitloc+32] != 0)
74 irq_handler(channel_ids[bitloc+32], IRQ_FALL); //Run that interrupt
75
76 //Both clear the interrupt with clear register, and remove it from our local copy of the interrupt pending register
77 LPC_GPIOINT->IO2IntClr = 1 << bitloc;
78 fall2 -= 1<<bitloc;
79 }
80 }
81
82 int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
83 if (pin == NC) return -1;
84
85 irq_handler = handler;
86
87 obj->port = (int)pin & ~0x1F;
88 obj->pin = (int)pin & 0x1F;
89
90 // Interrupts available only on GPIO0 and GPIO2
91 if (obj->port != LPC_GPIO0_BASE && obj->port != LPC_GPIO2_BASE) {
92 error("pins on this port cannot generate interrupts");
93 }
94
95 // put us in the interrupt table
96 int index = (obj->port == LPC_GPIO0_BASE) ? obj->pin : obj->pin + 32;
97 channel_ids[index] = id;
98 obj->ch = index;
99
100 NVIC_SetVector(EINT3_IRQn, (uint32_t)handle_interrupt_in);
101 NVIC_EnableIRQ(EINT3_IRQn);
102 return 0;
103 }
104
105 void gpio_irq_free(gpio_irq_t *obj) {
106 channel_ids[obj->ch] = 0;
107 }
108
109 void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
110 // ensure nothing is pending
111 switch (obj->port) {
112 case LPC_GPIO0_BASE: LPC_GPIOINT->IO0IntClr = 1 << obj->pin; break;
113 case LPC_GPIO2_BASE: LPC_GPIOINT->IO2IntClr = 1 << obj->pin; break;
114 }
115
116 // enable the pin interrupt
117 if (event == IRQ_RISE) {
118 switch (obj->port) {
119 case LPC_GPIO0_BASE:
120 if (enable) {
121 LPC_GPIOINT->IO0IntEnR |= 1 << obj->pin;
122 } else {
123 LPC_GPIOINT->IO0IntEnR &= ~(1 << obj->pin);
124 }
125 break;
126 case LPC_GPIO2_BASE:
127 if (enable) {
128 LPC_GPIOINT->IO2IntEnR |= 1 << obj->pin;
129 } else {
130 LPC_GPIOINT->IO2IntEnR &= ~(1 << obj->pin);
131 }
132 break;
133 }
134 } else {
135 switch (obj->port) {
136 case LPC_GPIO0_BASE:
137 if (enable) {
138 LPC_GPIOINT->IO0IntEnF |= 1 << obj->pin;
139 } else {
140 LPC_GPIOINT->IO0IntEnF &= ~(1 << obj->pin);
141 }
142 break;
143 case LPC_GPIO2_BASE:
144 if (enable) {
145 LPC_GPIOINT->IO2IntEnF |= 1 << obj->pin;
146 } else {
147 LPC_GPIOINT->IO2IntEnF &= ~(1 << obj->pin);
148 }
149 break;
150 }
151 }
152 }
153
154 void gpio_irq_enable(gpio_irq_t *obj) {
155 NVIC_EnableIRQ(EINT3_IRQn);
156 }
157
158 void gpio_irq_disable(gpio_irq_t *obj) {
159 NVIC_DisableIRQ(EINT3_IRQn);
160 }
161
Imprint / Impressum