1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2013 ARM Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "gpio_irq_api.h"
19 #include "mbed_error.h"
22 #define CHANNEL_NUM 48
24 static uint32_t channel_ids
[CHANNEL_NUM
] = {0};
25 static gpio_irq_handler irq_handler
;
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
;
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
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
;
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
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
;
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
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
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
;
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
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
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
;
82 int gpio_irq_init(gpio_irq_t
*obj
, PinName pin
, gpio_irq_handler handler
, uint32_t id
) {
83 if (pin
== NC
) return -1;
85 irq_handler
= handler
;
87 obj
->port
= (int)pin
& ~0x1F;
88 obj
->pin
= (int)pin
& 0x1F;
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");
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
;
100 NVIC_SetVector(EINT3_IRQn
, (uint32_t)handle_interrupt_in
);
101 NVIC_EnableIRQ(EINT3_IRQn
);
105 void gpio_irq_free(gpio_irq_t
*obj
) {
106 channel_ids
[obj
->ch
] = 0;
109 void gpio_irq_set(gpio_irq_t
*obj
, gpio_irq_event event
, uint32_t enable
) {
110 // ensure nothing is pending
112 case LPC_GPIO0_BASE
: LPC_GPIOINT
->IO0IntClr
= 1 << obj
->pin
; break;
113 case LPC_GPIO2_BASE
: LPC_GPIOINT
->IO2IntClr
= 1 << obj
->pin
; break;
116 // enable the pin interrupt
117 if (event
== IRQ_RISE
) {
121 LPC_GPIOINT
->IO0IntEnR
|= 1 << obj
->pin
;
123 LPC_GPIOINT
->IO0IntEnR
&= ~(1 << obj
->pin
);
128 LPC_GPIOINT
->IO2IntEnR
|= 1 << obj
->pin
;
130 LPC_GPIOINT
->IO2IntEnR
&= ~(1 << obj
->pin
);
138 LPC_GPIOINT
->IO0IntEnF
|= 1 << obj
->pin
;
140 LPC_GPIOINT
->IO0IntEnF
&= ~(1 << obj
->pin
);
145 LPC_GPIOINT
->IO2IntEnF
|= 1 << obj
->pin
;
147 LPC_GPIOINT
->IO2IntEnF
&= ~(1 << obj
->pin
);
154 void gpio_irq_enable(gpio_irq_t
*obj
) {
155 NVIC_EnableIRQ(EINT3_IRQn
);
158 void gpio_irq_disable(gpio_irq_t
*obj
) {
159 NVIC_DisableIRQ(EINT3_IRQn
);