1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2015 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.
19 #include "gpio_irq_api.h"
20 #include "mbed_error.h"
22 #define CHANNEL_NUM 160
24 static uint32_t channel_ids
[CHANNEL_NUM
] = {0};
25 static gpio_irq_handler irq_handler
;
27 #define IRQ_DISABLED (0)
28 #define IRQ_RAISING_EDGE PORT_PCR_IRQC(9)
29 #define IRQ_FALLING_EDGE PORT_PCR_IRQC(10)
30 #define IRQ_EITHER_EDGE PORT_PCR_IRQC(11)
32 static void handle_interrupt_in(PORT_Type
*port
, int ch_base
) {
36 while ((isfr
= port
->ISFR
) != 0) {
37 pin
= 31 - __CLZ(isfr
);
38 uint32_t id
= channel_ids
[ch_base
+ pin
];
43 GPIO_Type
*gpio
= PTA
;
44 gpio_irq_event event
= IRQ_NONE
;
45 uint32_t port_num
= (port
- PORTA
) >> 12;
47 switch (port
->PCR
[pin
] & PORT_PCR_IRQC_MASK
) {
48 case IRQ_RAISING_EDGE
:
51 case IRQ_FALLING_EDGE
:
55 gpio
+= (port_num
* 0x40);
56 event
= (gpio
->PDIR
& (1 << pin
)) ? (IRQ_RISE
) : (IRQ_FALL
);
59 if (event
!= IRQ_NONE
) {
60 irq_handler(id
, event
);
62 port
->ISFR
= 1 << pin
;
66 void gpio_irqA(void) {
67 handle_interrupt_in(PORTA
, 0);
72 handle_interrupt_in(PORTB
, 32);
77 handle_interrupt_in(PORTC
, 64);
82 handle_interrupt_in(PORTD
, 96);
87 handle_interrupt_in(PORTE
, 128);
91 int gpio_irq_init(gpio_irq_t
*obj
, PinName pin
, gpio_irq_handler handler
, uint32_t id
) {
95 irq_handler
= handler
;
97 obj
->port
= pin
>> PORT_SHIFT
;
98 obj
->pin
= (pin
& 0x7F) >> 2;
100 uint32_t ch_base
, vector
;
106 vector
= (uint32_t)gpio_irqA
;
111 vector
= (uint32_t)gpio_irqB
;
116 vector
= (uint32_t)gpio_irqC
;
120 irq_n
= PORTD_IRQn
; vector
= (uint32_t)gpio_irqD
;
125 vector
= (uint32_t)gpio_irqE
;
129 error("gpio_irq only supported on port A-E.");
132 NVIC_SetVector(irq_n
, vector
);
133 NVIC_EnableIRQ(irq_n
);
135 obj
->ch
= ch_base
+ obj
->pin
;
136 channel_ids
[obj
->ch
] = id
;
141 void gpio_irq_free(gpio_irq_t
*obj
) {
142 channel_ids
[obj
->ch
] = 0;
145 void gpio_irq_set(gpio_irq_t
*obj
, gpio_irq_event event
, uint32_t enable
) {
146 PORT_Type
*port
= (PORT_Type
*)(PORTA_BASE
+ 0x1000 * obj
->port
);
148 uint32_t irq_settings
= IRQ_DISABLED
;
150 switch (port
->PCR
[obj
->pin
] & PORT_PCR_IRQC_MASK
) {
153 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_RAISING_EDGE
) : (IRQ_FALLING_EDGE
);
156 case IRQ_RAISING_EDGE
:
158 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_RAISING_EDGE
) : (IRQ_EITHER_EDGE
);
160 if (event
== IRQ_FALL
)
161 irq_settings
= IRQ_RAISING_EDGE
;
165 case IRQ_FALLING_EDGE
:
167 irq_settings
= (event
== IRQ_FALL
) ? (IRQ_FALLING_EDGE
) : (IRQ_EITHER_EDGE
);
169 if (event
== IRQ_RISE
)
170 irq_settings
= IRQ_FALLING_EDGE
;
174 case IRQ_EITHER_EDGE
:
176 irq_settings
= IRQ_EITHER_EDGE
;
178 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_FALLING_EDGE
) : (IRQ_RAISING_EDGE
);
183 // Interrupt configuration and clear interrupt
184 port
->PCR
[obj
->pin
] = (port
->PCR
[obj
->pin
] & ~PORT_PCR_IRQC_MASK
) | irq_settings
| PORT_PCR_ISF_MASK
;
187 void gpio_irq_enable(gpio_irq_t
*obj
) {
190 NVIC_EnableIRQ(PORTA_IRQn
);
193 NVIC_EnableIRQ(PORTB_IRQn
);
196 NVIC_EnableIRQ(PORTC_IRQn
);
199 NVIC_EnableIRQ(PORTD_IRQn
);
202 NVIC_EnableIRQ(PORTE_IRQn
);
207 void gpio_irq_disable(gpio_irq_t
*obj
) {
210 NVIC_DisableIRQ(PORTA_IRQn
);
213 NVIC_DisableIRQ(PORTB_IRQn
);
216 NVIC_DisableIRQ(PORTC_IRQn
);
219 NVIC_DisableIRQ(PORTD_IRQn
);
222 NVIC_DisableIRQ(PORTE_IRQn
);