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 96
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
:
65 } else if (port
== PORTC
) {
70 event
= (gpio
->PDIR
& (1<<location
)) ? (IRQ_RISE
) : (IRQ_FALL
);
73 if (event
!= IRQ_NONE
) {
74 irq_handler(id
, event
);
76 port
->ISFR
= 1 << location
;
80 void gpio_irqA(void) {
81 handle_interrupt_in(PORTA
, 0);
84 /* PORTC and PORTD share same vector */
85 void gpio_irqCD(void) {
86 if ((SIM
->SCGC5
& SIM_SCGC5_PORTC_MASK
) && (PORTC
->ISFR
)) {
87 handle_interrupt_in(PORTC
, 32);
88 } else if ((SIM
->SCGC5
& SIM_SCGC5_PORTD_MASK
) && (PORTD
->ISFR
)) {
89 handle_interrupt_in(PORTD
, 64);
93 int gpio_irq_init(gpio_irq_t
*obj
, PinName pin
, gpio_irq_handler handler
, uint32_t id
) {
97 irq_handler
= handler
;
99 obj
->port
= pin
>> PORT_SHIFT
;
100 obj
->pin
= (pin
& 0x7F) >> 2;
102 uint32_t ch_base
, vector
;
106 ch_base
= 0; irq_n
= PORTA_IRQn
; vector
= (uint32_t)gpio_irqA
;
110 ch_base
= 32; irq_n
= PORTC_PORTD_IRQn
; vector
= (uint32_t)gpio_irqCD
;
114 ch_base
= 64; irq_n
= PORTC_PORTD_IRQn
; vector
= (uint32_t)gpio_irqCD
;
118 error("gpio_irq only supported on port A,C and D");
121 NVIC_SetVector(irq_n
, vector
);
122 NVIC_EnableIRQ(irq_n
);
124 obj
->ch
= ch_base
+ obj
->pin
;
125 channel_ids
[obj
->ch
] = id
;
130 void gpio_irq_free(gpio_irq_t
*obj
) {
131 channel_ids
[obj
->ch
] = 0;
134 void gpio_irq_set(gpio_irq_t
*obj
, gpio_irq_event event
, uint32_t enable
) {
135 PORT_Type
*port
= (PORT_Type
*)(PORTA_BASE
+ 0x1000 * obj
->port
);
137 uint32_t irq_settings
= IRQ_DISABLED
;
139 switch (port
->PCR
[obj
->pin
] & PORT_PCR_IRQC_MASK
) {
142 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_RAISING_EDGE
) : (IRQ_FALLING_EDGE
);
146 case IRQ_RAISING_EDGE
:
148 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_RAISING_EDGE
) : (IRQ_EITHER_EDGE
);
150 if (event
== IRQ_FALL
)
151 irq_settings
= IRQ_RAISING_EDGE
;
155 case IRQ_FALLING_EDGE
:
157 irq_settings
= (event
== IRQ_FALL
) ? (IRQ_FALLING_EDGE
) : (IRQ_EITHER_EDGE
);
159 if (event
== IRQ_RISE
)
160 irq_settings
= IRQ_FALLING_EDGE
;
164 case IRQ_EITHER_EDGE
:
166 irq_settings
= IRQ_EITHER_EDGE
;
168 irq_settings
= (event
== IRQ_RISE
) ? (IRQ_FALLING_EDGE
) : (IRQ_RAISING_EDGE
);
173 // Interrupt configuration and clear interrupt
174 port
->PCR
[obj
->pin
] = (port
->PCR
[obj
->pin
] & ~PORT_PCR_IRQC_MASK
) | irq_settings
| PORT_PCR_ISF_MASK
;
177 void gpio_irq_enable(gpio_irq_t
*obj
) {
178 if (obj
->port
== PortA
) {
179 NVIC_EnableIRQ(PORTA_IRQn
);
181 NVIC_EnableIRQ(PORTC_PORTD_IRQn
);
185 void gpio_irq_disable(gpio_irq_t
*obj
) {
186 if (obj
->port
== PortA
) {
187 NVIC_DisableIRQ(PORTA_IRQn
);
189 NVIC_DisableIRQ(PORTC_PORTD_IRQn
);