mbed library sources
Dependents: frdm_kl05z_gpio_test
Fork of mbed-src by
Diff: targets/hal/TARGET_STM/TARGET_NUCLEO_F103RB/gpio_irq_api.c
- Revision:
- 60:142c6c6f5949
- Child:
- 70:c1fbde68b492
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_STM/TARGET_NUCLEO_F103RB/gpio_irq_api.c Tue Dec 17 08:45:10 2013 +0000 @@ -0,0 +1,242 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * 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 <stddef.h> +#include "cmsis.h" + +#include "gpio_irq_api.h" +#include "error.h" + +#define EDGE_NONE (0) +#define EDGE_RISE (1) +#define EDGE_FALL (2) +#define EDGE_BOTH (3) + +#define CHANNEL_NUM (16) + +static uint32_t channel_ids[CHANNEL_NUM] = {0}; + +static gpio_irq_handler irq_handler; + +static void handle_interrupt_in(uint32_t channel) { + if (channel_ids[channel] == 0) return; + + uint32_t exti_line = (uint32_t)(1 << channel); + if (EXTI_GetITStatus(exti_line) != RESET) + { + EXTI_ClearITPendingBit(exti_line); + } + + // Warning: + // On this device we don't know if a rising or falling event occured. + // In case both rise and fall events are set, only the FALL event will be reported. + if (EXTI->FTSR & (uint32_t)(1 << channel)) { + irq_handler(channel_ids[channel], IRQ_FALL); + } + else { + irq_handler(channel_ids[channel], IRQ_RISE); + } +} + +static void gpio_irq0(void) {handle_interrupt_in(0);} +static void gpio_irq1(void) {handle_interrupt_in(1);} +static void gpio_irq2(void) {handle_interrupt_in(2);} +static void gpio_irq3(void) {handle_interrupt_in(3);} +static void gpio_irq4(void) {handle_interrupt_in(4);} +static void gpio_irq5(void) {handle_interrupt_in(5);} +static void gpio_irq6(void) {handle_interrupt_in(6);} +static void gpio_irq7(void) {handle_interrupt_in(7);} +static void gpio_irq8(void) {handle_interrupt_in(8);} +static void gpio_irq9(void) {handle_interrupt_in(9);} +static void gpio_irq10(void) {handle_interrupt_in(10);} +static void gpio_irq11(void) {handle_interrupt_in(11);} +static void gpio_irq12(void) {handle_interrupt_in(12);} +static void gpio_irq13(void) {handle_interrupt_in(13);} +static void gpio_irq14(void) {handle_interrupt_in(14);} +static void gpio_irq15(void) {handle_interrupt_in(15);} + +int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) { + IRQn_Type irq_n = (IRQn_Type)0; + uint32_t vector = 0; + + if (pin == NC) return -1; + + uint32_t pin_number = (uint32_t)pin; + uint32_t pin_index = (pin_number & 0xF); + uint32_t port_index = (pin_number >> 4); + + // Select irq number and vector + switch (pin_index) { + case 0: + irq_n = EXTI0_IRQn; + vector = (uint32_t)&gpio_irq0; + break; + case 1: + irq_n = EXTI1_IRQn; + vector = (uint32_t)&gpio_irq1; + break; + case 2: + irq_n = EXTI2_IRQn; + vector = (uint32_t)&gpio_irq2; + break; + case 3: + irq_n = EXTI3_IRQn; + vector = (uint32_t)&gpio_irq3; + break; + case 4: + irq_n = EXTI4_IRQn; + vector = (uint32_t)&gpio_irq4; + break; + case 5: + irq_n = EXTI9_5_IRQn; + vector = (uint32_t)&gpio_irq5; + break; + case 6: + irq_n = EXTI9_5_IRQn; + vector = (uint32_t)&gpio_irq6; + break; + case 7: + irq_n = EXTI9_5_IRQn; + vector = (uint32_t)&gpio_irq7; + break; + case 8: + irq_n = EXTI9_5_IRQn; + vector = (uint32_t)&gpio_irq8; + break; + case 9: + irq_n = EXTI9_5_IRQn; + vector = (uint32_t)&gpio_irq9; + break; + case 10: + irq_n = EXTI15_10_IRQn; + vector = (uint32_t)&gpio_irq10; + break; + case 11: + irq_n = EXTI15_10_IRQn; + vector = (uint32_t)&gpio_irq11; + break; + case 12: + irq_n = EXTI15_10_IRQn; + vector = (uint32_t)&gpio_irq12; + break; + case 13: + irq_n = EXTI15_10_IRQn; + vector = (uint32_t)&gpio_irq13; + break; + case 14: + irq_n = EXTI15_10_IRQn; + vector = (uint32_t)&gpio_irq14; + break; + case 15: + irq_n = EXTI15_10_IRQn; + vector = (uint32_t)&gpio_irq15; + break; + default: + return -1; + } + + // Enable GPIO and AFIO clocks + RCC_APB2PeriphClockCmd((uint32_t)(RCC_APB2Periph_GPIOA << port_index), ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); + + // Connect EXTI line to pin + GPIO_EXTILineConfig(port_index, pin_index); + + // Configure EXTI line + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_InitStructure.EXTI_Line = (uint32_t)(1 << pin_index); + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + // Enable and set EXTI interrupt to the lowest priority + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = irq_n; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + NVIC_SetVector(irq_n, vector); + NVIC_EnableIRQ(irq_n); + + // Save for future use + obj->ch = pin_index; + obj->irq_n = irq_n; + obj->event = EDGE_NONE; + + channel_ids[obj->ch] = id; + + irq_handler = handler; + + return 0; +} + +void gpio_irq_free(gpio_irq_t *obj) { + channel_ids[obj->ch] = 0; + // Disable EXTI line + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_StructInit(&EXTI_InitStructure); + EXTI_Init(&EXTI_InitStructure); + obj->event = EDGE_NONE; +} + +void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) { + EXTI_InitTypeDef EXTI_InitStructure; + + EXTI_InitStructure.EXTI_Line = (uint32_t)(1 << obj->ch); + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + + if (event == IRQ_RISE) { + if ((obj->event == EDGE_FALL) || (obj->event == EDGE_BOTH)) { + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; + obj->event = EDGE_BOTH; + } + else { // NONE or RISE + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + obj->event = EDGE_RISE; + } + } + + if (event == IRQ_FALL) { + if ((obj->event == EDGE_RISE) || (obj->event == EDGE_BOTH)) { + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; + obj->event = EDGE_BOTH; + } + else { // NONE or FALL + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; + obj->event = EDGE_FALL; + } + } + + if (enable) { + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + } + else { + EXTI_InitStructure.EXTI_LineCmd = DISABLE; + } + + EXTI_Init(&EXTI_InitStructure); +} + +void gpio_irq_enable(gpio_irq_t *obj) { + NVIC_EnableIRQ(obj->irq_n); +} + +void gpio_irq_disable(gpio_irq_t *obj) { + NVIC_DisableIRQ(obj->irq_n); + obj->event = EDGE_NONE; +}