/* mbed Microcontroller Library * Copyright (c) 2018 GigaDevice Semiconductor Inc. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "cmsis.h" #include "gpio_irq_api.h" #include "pinmap.h" #include "mbed_error.h" #define EDGE_NONE (0) #define EDGE_RISE (1) #define EDGE_FALL (2) extern uint32_t gpio_clock_enable(uint32_t port_idx); static gpio_irq_handler irq_handler; typedef struct { uint32_t exti_idx; uint32_t exti_gpiox; /* base address of gpio */ uint32_t exti_pinx; /* pin number */ } gpio_exti_info_struct; /* EXTI0...EXTI15 */ static gpio_exti_info_struct exti_info_array[16] = {0}; /** handle EXTI interrupt in EXTI0 to EXTI15 * @param irq_index the line of EXTI(0~15) */ static void exti_handle_interrupt(uint32_t irq_index) { gpio_exti_info_struct *gpio_exti = &exti_info_array[irq_index]; /* get the port and pin of EXTI */ uint32_t gpio = (uint32_t)(gpio_exti->exti_gpiox); uint32_t pin = (uint32_t)(1 << (gpio_exti->exti_pinx)); /* clear interrupt flag */ if (exti_interrupt_flag_get((exti_line_enum)pin) != RESET) { exti_interrupt_flag_clear((exti_line_enum)pin); /* check which edge has generated the irq */ if ((GPIO_ISTAT(gpio) & pin) == 0) { irq_handler(gpio_exti->exti_idx, IRQ_FALL); } else { irq_handler(gpio_exti->exti_idx, IRQ_RISE); } } } /* EXTI0 interrupt handler */ static void gpio_irq_exti0(void) { exti_handle_interrupt(0); } /* EXTI1 interrupt handler */ static void gpio_irq_exti1(void) { exti_handle_interrupt(1); } /* EXTI2 interrupt handler */ static void gpio_irq_exti2(void) { exti_handle_interrupt(2); } /* EXTI3 interrupt handler */ static void gpio_irq_exti3(void) { exti_handle_interrupt(3); } /* EXTI4 interrupt handler */ static void gpio_irq_exti4(void) { exti_handle_interrupt(4); } /* EXTI5 interrupt handler */ static void gpio_irq_exti5(void) { exti_handle_interrupt(5); } /* EXTI6 interrupt handler */ static void gpio_irq_exti6(void) { exti_handle_interrupt(6); } /* EXTI7 interrupt handler */ static void gpio_irq_exti7(void) { exti_handle_interrupt(7); } /* EXTI8 interrupt handler */ static void gpio_irq_exti8(void) { exti_handle_interrupt(8); } /* EXTI9 interrupt handler */ static void gpio_irq_exti9(void) { exti_handle_interrupt(9); } /* EXTI10 interrupt handler */ static void gpio_irq_exti10(void) { exti_handle_interrupt(10); } /* EXTI11 interrupt handler */ static void gpio_irq_exti11(void) { exti_handle_interrupt(11); } /* EXTI12 interrupt handler */ static void gpio_irq_exti12(void) { exti_handle_interrupt(12); } /* EXTI13 interrupt handler */ static void gpio_irq_exti13(void) { exti_handle_interrupt(13); } /* EXTI14 interrupt handler */ static void gpio_irq_exti14(void) { exti_handle_interrupt(14); } /* EXTI15 interrupt handler */ static void gpio_irq_exti15(void) { exti_handle_interrupt(15); } /** Initialize the GPIO IRQ pin * * @param obj The GPIO object to initialize * @param pin The GPIO pin name * @param handler The handler to be attached to GPIO IRQ * @param id The object ID (id != 0, 0 is reserved) * @return -1 if pin is NC, 0 otherwise */ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) { uint32_t vector = 0; gpio_exti_info_struct *gpio_exti; if (pin == NC) { return -1; } /* Enable AF Clock */ rcu_periph_clock_enable(RCU_AF); uint32_t port_index = GD_PORT_GET(pin); uint32_t pin_index = GD_PIN_GET(pin); /* Enable GPIO clock */ uint32_t gpio_add = gpio_clock_enable(port_index); /* fill EXTI information according to pin_index . eg. use PORTE_9 as EXTI interrupt, the irq type is EXTI5_9_IRQn */ if (pin_index == 0) { vector = (uint32_t)&gpio_irq_exti0; obj->irq_index = 0; obj->irq_n = EXTI0_IRQn; } else if (pin_index == 1) { vector = (uint32_t)&gpio_irq_exti1; obj->irq_index = 1; obj->irq_n = EXTI1_IRQn; } else if (pin_index == 2) { vector = (uint32_t)&gpio_irq_exti2; obj->irq_index = 2; obj->irq_n = EXTI2_IRQn; } else if (pin_index == 3) { vector = (uint32_t)&gpio_irq_exti3; obj->irq_index = 3; obj->irq_n = EXTI3_IRQn; } else if (pin_index == 4) { vector = (uint32_t)&gpio_irq_exti4; obj->irq_index = 4; obj->irq_n = EXTI4_IRQn; } else if (pin_index == 5) { vector = (uint32_t)&gpio_irq_exti5; obj->irq_index = 5; obj->irq_n = EXTI5_9_IRQn; } else if (pin_index == 6) { vector = (uint32_t)&gpio_irq_exti6; obj->irq_index = 6; obj->irq_n = EXTI5_9_IRQn; } else if (pin_index == 7) { vector = (uint32_t)&gpio_irq_exti7; obj->irq_index = 7; obj->irq_n = EXTI5_9_IRQn; } else if (pin_index == 8) { vector = (uint32_t)&gpio_irq_exti8; obj->irq_index = 8; obj->irq_n = EXTI5_9_IRQn; } else if (pin_index == 9) { vector = (uint32_t)&gpio_irq_exti9; obj->irq_index = 9; obj->irq_n = EXTI5_9_IRQn; } else if (pin_index == 10) { vector = (uint32_t)&gpio_irq_exti10; obj->irq_index = 10; obj->irq_n = EXTI10_15_IRQn; } else if (pin_index == 11) { vector = (uint32_t)&gpio_irq_exti11; obj->irq_index = 11; obj->irq_n = EXTI10_15_IRQn; } else if (pin_index == 12) { vector = (uint32_t)&gpio_irq_exti12; obj->irq_index = 12; obj->irq_n = EXTI10_15_IRQn; } else if (pin_index == 13) { vector = (uint32_t)&gpio_irq_exti13; obj->irq_index = 13; obj->irq_n = EXTI10_15_IRQn; } else if (pin_index == 14) { vector = (uint32_t)&gpio_irq_exti14; obj->irq_index = 14; obj->irq_n = EXTI10_15_IRQn; } else if (pin_index == 15) { vector = (uint32_t)&gpio_irq_exti15; obj->irq_index = 15; obj->irq_n = EXTI10_15_IRQn; } else { error("pin not supported for interrupt in.\n"); return -1; } /* Save informations for future use */ obj->event = EDGE_NONE; obj->pin = pin; gpio_exti = &exti_info_array[obj->irq_index]; gpio_exti->exti_idx = id; gpio_exti->exti_gpiox = gpio_add; gpio_exti->exti_pinx = pin_index; irq_handler = handler; /* Enable EXTI interrupt */ NVIC_SetVector(obj->irq_n, vector); gpio_irq_enable(obj); return 0; } /** Release the GPIO IRQ PIN * * @param obj The gpio object */ void gpio_irq_free(gpio_irq_t *obj) { gpio_exti_info_struct *gpio_exti = &exti_info_array[obj->irq_index]; /* Disable EXTI interrupt */ gpio_irq_disable(obj); /* Reset struct of exti information */ gpio_exti->exti_idx = 0; gpio_exti->exti_gpiox = 0; gpio_exti->exti_pinx = 0; } /** Enable/disable pin IRQ event * * @param obj The GPIO object * @param event The GPIO IRQ event * @param enable The enable flag */ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) { if (event == IRQ_RISE) { if (enable) { exti_init((exti_line_enum)(1 << GD_PIN_GET(obj->pin)), EXTI_INTERRUPT, EXTI_TRIG_RISING); /* Clear interrupt enable bit, rising/falling bit */ } else { EXTI_INTEN &= ~(uint32_t)(exti_line_enum)(1 << GD_PIN_GET(obj->pin)); EXTI_RTEN &= ~(uint32_t)(exti_line_enum)(1 << GD_PIN_GET(obj->pin)); EXTI_FTEN &= ~(uint32_t)(exti_line_enum)(1 << GD_PIN_GET(obj->pin)); } } if (event == IRQ_FALL) { if (enable) { exti_init((exti_line_enum)(1 << (GD_PIN_GET(obj->pin))), EXTI_INTERRUPT, EXTI_TRIG_FALLING); /* Clear interrupt enable bit, rising/falling bit */ } else { EXTI_INTEN &= ~(uint32_t)(exti_line_enum)(1 << GD_PIN_GET(obj->pin)); EXTI_RTEN &= ~(uint32_t)(exti_line_enum)(1 << GD_PIN_GET(obj->pin)); EXTI_FTEN &= ~(uint32_t)(exti_line_enum)(1 << GD_PIN_GET(obj->pin)); } } } /** Enable GPIO IRQ * * This is target dependent, as it might enable the entire port or just a pin * @param obj The GPIO object */ void gpio_irq_enable(gpio_irq_t *obj) { /* Select EXTI Source */ gpio_exti_source_select(GD_PORT_GET(obj->pin), GD_PIN_GET(obj->pin)); exti_interrupt_enable((exti_line_enum)(1 << GD_PIN_GET(obj->pin))); NVIC_EnableIRQ(obj->irq_n); } /** Disable GPIO IRQ * * This is target dependent, as it might disable the entire port or just a pin * @param obj The GPIO object */ void gpio_irq_disable(gpio_irq_t *obj) { /* Clear EXTI line configuration */ exti_interrupt_disable((exti_line_enum)(1 << GD_PIN_GET(obj->pin))); NVIC_DisableIRQ(obj->irq_n); NVIC_ClearPendingIRQ(obj->irq_n); obj->event = EDGE_NONE; }