fix for mbed lib issue 3 (i2c problem) see also https://mbed.org/users/mbed_official/code/mbed/issues/3 affected implementations: LPC812, LPC11U24, LPC1768, LPC2368, LPC4088

Fork of mbed-src by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers gpio_irq_api.c Source File

gpio_irq_api.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "gpio_irq_api.h"
00017 #include "error.h"
00018 #include <stddef.h>
00019 #include "cmsis.h"
00020 
00021 #define CHANNEL_NUM     48
00022 
00023 static uint32_t channel_ids[CHANNEL_NUM] = {0};
00024 static gpio_irq_handler irq_handler;
00025 
00026 static void handle_interrupt_in(void) {
00027     // Read in all current interrupt registers. We do this once as the
00028     // GPIO interrupt registers are on the APB bus, and this is slow.
00029     uint32_t rise0 = LPC_GPIOINT->IO0IntStatR;
00030     uint32_t fall0 = LPC_GPIOINT->IO0IntStatF;
00031     uint32_t rise2 = LPC_GPIOINT->IO2IntStatR;
00032     uint32_t fall2 = LPC_GPIOINT->IO2IntStatF;
00033     uint32_t mask0 = 0;
00034     uint32_t mask2 = 0;
00035     int i;
00036     
00037     // P0.0-0.31
00038     for (i = 0; i < 32; i++) {
00039         uint32_t pmask = (1 << i);
00040         if (rise0 & pmask) {
00041             mask0 |= pmask;
00042             if (channel_ids[i] != 0)
00043                 irq_handler(channel_ids[i], IRQ_RISE);
00044         }
00045         if (fall0 & pmask) {
00046             mask0 |= pmask;
00047             if (channel_ids[i] != 0)
00048                 irq_handler(channel_ids[i], IRQ_FALL);
00049         }
00050     }
00051     
00052     // P2.0-2.15
00053     for (i = 0; i < 16; i++) {
00054         uint32_t pmask = (1 << i);
00055         int channel_index = i + 32;
00056         if (rise2 & pmask) {
00057             mask2 |= pmask;
00058             if (channel_ids[channel_index] != 0)
00059                 irq_handler(channel_ids[channel_index], IRQ_RISE);
00060         }
00061         if (fall2 & pmask) {
00062             mask2 |= pmask;
00063             if (channel_ids[channel_index] != 0)
00064                 irq_handler(channel_ids[channel_index], IRQ_FALL);
00065         }
00066     }
00067     
00068     // Clear the interrupts we just handled
00069     LPC_GPIOINT->IO0IntClr = mask0;
00070     LPC_GPIOINT->IO2IntClr = mask2;
00071 }
00072 
00073 int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
00074     if (pin == NC) return -1;
00075     
00076     irq_handler = handler;
00077     
00078     obj->port = (int)pin & ~0x1F;
00079     obj->pin = (int)pin & 0x1F;
00080     
00081     // Interrupts available only on GPIO0 and GPIO2
00082     if (obj->port != LPC_GPIO0_BASE && obj->port != LPC_GPIO2_BASE) {
00083         error("pins on this port cannot generate interrupts\n");
00084     }
00085     
00086     // put us in the interrupt table
00087     int index = (obj->port == LPC_GPIO0_BASE) ? obj->pin : obj->pin + 32;
00088     channel_ids[index] = id;
00089     obj->ch = index;
00090     
00091     NVIC_SetVector(EINT3_IRQn , (uint32_t)handle_interrupt_in);
00092     NVIC_EnableIRQ(EINT3_IRQn );
00093     
00094     return 0;
00095 }
00096 
00097 void gpio_irq_free(gpio_irq_t *obj) {
00098     channel_ids[obj->ch] = 0;
00099 }
00100 
00101 void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
00102     // ensure nothing is pending
00103     switch (obj->port) {
00104          case LPC_GPIO0_BASE: LPC_GPIOINT->IO0IntClr = 1 << obj->pin; break;
00105          case LPC_GPIO2_BASE: LPC_GPIOINT->IO2IntClr = 1 << obj->pin; break;
00106     }
00107     
00108     // enable the pin interrupt
00109     if (event == IRQ_RISE) {
00110         switch (obj->port) {
00111             case LPC_GPIO0_BASE:
00112                 if (enable) {
00113                     LPC_GPIOINT->IO0IntEnR |= 1 << obj->pin;
00114                 } else {
00115                     LPC_GPIOINT->IO0IntEnR &= ~(1 << obj->pin);
00116                 }
00117                 break;
00118             case LPC_GPIO2_BASE:
00119                 if (enable) {
00120                     LPC_GPIOINT->IO2IntEnR |= 1 << obj->pin;
00121                 } else {
00122                     LPC_GPIOINT->IO2IntEnR &= ~(1 << obj->pin);
00123                 }
00124                 break;
00125         }
00126     } else {
00127         switch (obj->port) {
00128             case LPC_GPIO0_BASE:
00129                 if (enable) {
00130                     LPC_GPIOINT->IO0IntEnF |= 1 << obj->pin;
00131                 } else {
00132                     LPC_GPIOINT->IO0IntEnF &= ~(1 << obj->pin);
00133                 }
00134                 break;
00135             
00136             case LPC_GPIO2_BASE:
00137                 if (enable) {
00138                     LPC_GPIOINT->IO2IntEnF |= 1 << obj->pin;
00139                 } else {
00140                     LPC_GPIOINT->IO2IntEnF &= ~(1 << obj->pin);
00141                 }
00142                 break;
00143         }
00144     }
00145 }