rau cha / mbed-src-I2CWaitFix

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