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.
19 #include "gpio_irq_api.h"
21 #include "mbed_error.h"
23 #define CHANNEL_NUM 64
25 static uint32_t channel_ids
[CHANNEL_NUM
] = {0};
26 static gpio_irq_handler irq_handler
;
28 #define IRQ_DISABLED (0)
29 #define IRQ_RAISING_EDGE PORT_PCR_IRQC(9)
30 #define IRQ_FALLING_EDGE PORT_PCR_IRQC(10)
31 #define IRQ_EITHER_EDGE PORT_PCR_IRQC(11)
33 const uint32_t search_bits
[] = {0x0000FFFF, 0x000000FF, 0x0000000F, 0x00000003, 0x00000001};
35 static void handle_interrupt_in(PORT_Type
*port
, int ch_base
) {
39 while((isfr
= port
->ISFR
) != 0) {
41 for (int i
= 0; i
< 5; i
++) {
42 if (!(isfr
& (search_bits
[i
] << location
)))
43 location
+= 1 << (4 - i
);
46 uint32_t id
= channel_ids
[ch_base
+ location
];
52 gpio_irq_event event
= IRQ_NONE
;
53 switch (port
->PCR
[location
] & PORT_PCR_IRQC_MASK
) {
54 case IRQ_RAISING_EDGE
:
58 case IRQ_FALLING_EDGE
:
63 gpio
= (port
== PORTA
) ? (FPTA
) : (FPTD
);
64 event
= (gpio
->PDIR
& (1 << location
)) ? (IRQ_RISE
) : (IRQ_FALL
);
67 if (event
!= IRQ_NONE
) {
68 irq_handler(id
, event
);
70 port
->ISFR
= 1 << location
;
74 void gpio_irqA(void) {handle_interrupt_in(PORTA
, 0);}
75 void gpio_irqD(void) {handle_interrupt_in(PORTD
, 32);}
77 int gpio_irq_init(gpio_irq_t
*obj
, PinName pin
, gpio_irq_handler handler
, uint32_t id
) {
78 if (pin
== NC
) return -1;
80 irq_handler
= handler
;
82 obj
->port
= pin
>> PORT_SHIFT
;
83 obj
->pin
= (pin
& 0x7F) >> 2;
85 uint32_t ch_base
, vector
;
89 ch_base
= 0; irq_n
= PORTA_IRQn
; vector
= (uint32_t)gpio_irqA
;
93 ch_base
= 32; irq_n
= PORTD_IRQn
; vector
= (uint32_t)gpio_irqD
;
97 error("gpio_irq only supported on port A and D");
100 NVIC_SetVector(irq_n
, vector
);
101 NVIC_EnableIRQ(irq_n
);
103 obj
->ch
= ch_base
+ obj
->pin
;
104 channel_ids
[obj
->ch
] = id
;
109 void gpio_irq_free(gpio_irq_t
*obj
) {
110 channel_ids
[obj
->ch
] = 0;
113 void gpio_irq_set(gpio_irq_t
*obj
, gpio_irq_event event
, uint32_t enable
) {
114 PORT_Type
*port
= (PORT_Type
*)(PORTA_BASE
+ 0x1000 * obj
->port
);
116 uint32_t irq_settings
= IRQ_DISABLED
;
118 switch (port
->PCR
[obj
->pin
] & PORT_PCR_IRQC_MASK
) {
121 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_RAISING_EDGE
) : (IRQ_FALLING_EDGE
);
125 case IRQ_RAISING_EDGE
:
127 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_RAISING_EDGE
) : (IRQ_EITHER_EDGE
);
129 if (event
== IRQ_FALL
)
130 irq_settings
= IRQ_RAISING_EDGE
;
134 case IRQ_FALLING_EDGE
:
136 irq_settings
= (event
== IRQ_FALL
) ? (IRQ_FALLING_EDGE
) : (IRQ_EITHER_EDGE
);
138 if (event
== IRQ_RISE
)
139 irq_settings
= IRQ_FALLING_EDGE
;
143 case IRQ_EITHER_EDGE
:
145 irq_settings
= IRQ_EITHER_EDGE
;
147 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_FALLING_EDGE
) : (IRQ_RAISING_EDGE
);
152 // Interrupt configuration and clear interrupt
153 port
->PCR
[obj
->pin
] = (port
->PCR
[obj
->pin
] & ~PORT_PCR_IRQC_MASK
) | irq_settings
| PORT_PCR_ISF_MASK
;
156 void gpio_irq_enable(gpio_irq_t
*obj
) {
157 if (obj
->port
== PortA
) {
158 NVIC_EnableIRQ(PORTA_IRQn
);
159 } else if (obj
->port
== PortD
) {
160 NVIC_EnableIRQ(PORTD_IRQn
);
164 void gpio_irq_disable(gpio_irq_t
*obj
) {
165 if (obj
->port
== PortA
) {
166 NVIC_DisableIRQ(PORTA_IRQn
);
167 } else if (obj
->port
== PortD
) {
168 NVIC_DisableIRQ(PORTD_IRQn
);