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 <stddef.h>
00017 #include "cmsis.h"
00018 #include "gpio_irq_api.h"
00019 #include "error.h"
00020 
00021 #define CHANNEL_NUM    8
00022 #define LPC_GPIO_X LPC_GPIO_PIN_INT
00023 #define PININT_IRQ 0
00024 
00025 static uint32_t channel_ids[CHANNEL_NUM] = {0};
00026 static gpio_irq_handler irq_handler;
00027 
00028 static inline void handle_interrupt_in(uint32_t channel) {
00029     uint32_t ch_bit = (1 << channel);
00030     // Return immediately if:
00031     //   * The interrupt was already served
00032     //   * There is no user handler
00033     //   * It is a level interrupt, not an edge interrupt
00034     if ( ((LPC_GPIO_X->IST & ch_bit) == 0) ||
00035          (channel_ids[channel] == 0      ) ||
00036          (LPC_GPIO_X->ISEL & ch_bit      ) ) return;
00037 
00038     if ((LPC_GPIO_X->IENR & ch_bit) && (LPC_GPIO_X->RISE & ch_bit)) {
00039         irq_handler(channel_ids[channel], IRQ_RISE);
00040         LPC_GPIO_X->RISE = ch_bit;
00041     }
00042     if ((LPC_GPIO_X->IENF & ch_bit) && (LPC_GPIO_X->FALL & ch_bit)) {
00043         irq_handler(channel_ids[channel], IRQ_FALL);
00044     }
00045     LPC_GPIO_X->IST = ch_bit;
00046 }
00047 
00048 void gpio_irq0(void) {handle_interrupt_in(0);}
00049 void gpio_irq1(void) {handle_interrupt_in(1);}
00050 void gpio_irq2(void) {handle_interrupt_in(2);}
00051 void gpio_irq3(void) {handle_interrupt_in(3);}
00052 void gpio_irq4(void) {handle_interrupt_in(4);}
00053 void gpio_irq5(void) {handle_interrupt_in(5);}
00054 void gpio_irq6(void) {handle_interrupt_in(6);}
00055 void gpio_irq7(void) {handle_interrupt_in(7);}
00056 
00057 int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
00058     if (pin == NC) return -1;
00059     
00060     irq_handler = handler;
00061     
00062     int found_free_channel = 0;
00063     int i = 0;
00064     for (i=0; i<CHANNEL_NUM; i++) {
00065         if (channel_ids[i] == 0) {
00066             channel_ids[i] = id;
00067             obj->ch = i;
00068             found_free_channel = 1;
00069             break;
00070         }
00071     }
00072     if (!found_free_channel) return -1;
00073     
00074     /* Enable AHB clock to the GPIO domain. */
00075     LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
00076     
00077     /* Enable AHB clock to the FlexInt, GroupedInt domain. */
00078     LPC_SYSCON->SYSAHBCLKCTRL |= ((1<<19) | (1<<23) | (1<<24));
00079     
00080     /* To select a pin for any of the eight pin interrupts, write the pin number
00081      * as 0 to 23 for pins PIO0_0 to PIO0_23 and 24 to 55.
00082      * @see: mbed_capi/PinNames.h
00083      */
00084     LPC_SYSCON->PINTSEL[obj->ch] = (pin >> 5) ? (pin - 8) : (pin);
00085     
00086     // Interrupt Wake-Up Enable
00087     LPC_SYSCON->STARTERP0 |= 1 << obj->ch;
00088     
00089     void (*channels_irq)(void) = NULL;
00090     switch (obj->ch) {
00091         case 0: channels_irq = &gpio_irq0; break;
00092         case 1: channels_irq = &gpio_irq1; break;
00093         case 2: channels_irq = &gpio_irq2; break;
00094         case 3: channels_irq = &gpio_irq3; break;
00095         case 4: channels_irq = &gpio_irq4; break;
00096         case 5: channels_irq = &gpio_irq5; break;
00097         case 6: channels_irq = &gpio_irq6; break;
00098         case 7: channels_irq = &gpio_irq7; break;
00099     }
00100     NVIC_SetVector((IRQn_Type )(PININT_IRQ + obj->ch), (uint32_t)channels_irq);
00101     NVIC_EnableIRQ((IRQn_Type )(PININT_IRQ + obj->ch));
00102     
00103     return 0;
00104 }
00105 
00106 void gpio_irq_free(gpio_irq_t *obj) {
00107     channel_ids[obj->ch] = 0;
00108     LPC_SYSCON->STARTERP0 &= ~(1 << obj->ch);
00109 }
00110 
00111 void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
00112     unsigned int ch_bit = (1 << obj->ch);
00113     
00114     // Clear interrupt
00115     if (!(LPC_GPIO_X->ISEL & ch_bit))
00116         LPC_GPIO_X->IST = ch_bit;
00117     
00118     // Edge trigger
00119     LPC_GPIO_X->ISEL &= ~ch_bit;
00120     if (event == IRQ_RISE) {
00121         if (enable) {
00122             LPC_GPIO_X->IENR |= ch_bit;
00123         } else {
00124             LPC_GPIO_X->IENR &= ~ch_bit;
00125         }
00126     } else {
00127         if (enable) {
00128             LPC_GPIO_X->IENF |= ch_bit;
00129         } else {
00130             LPC_GPIO_X->IENF &= ~ch_bit;
00131         }
00132     }
00133 }