mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
targets/TARGET_Cypress/TARGET_PSOC6/gpio_irq_api.c
- Committer:
- AnnaBridge
- Date:
- 2019-02-20
- Revision:
- 189:f392fc9709a3
- Parent:
- 188:bcfe06ba3d64
File content as of revision 189:f392fc9709a3:
/* * mbed Microcontroller Library * Copyright (c) 2017-2018 Future Electronics * Copyright (c) 2018-2019 Cypress Semiconductor Corporation * 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 "cmsis.h" #include "device.h" #include "mbed_assert.h" #include "gpio_object.h" #include "gpio_irq_api.h" #include "psoc6_utils.h" #include "cy_sysint.h" #define NUM_GPIO_PORTS IOSS_GPIO_GPIO_PORT_NR #define NUM_GPIO_PORT_PINS 8 #define GPIO_DEFAULT_IRQ_PRIORITY 5 static gpio_irq_t *irq_objects[NUM_GPIO_PORTS][NUM_GPIO_PORT_PINS] = {NULL}; typedef struct irq_port_info_s { IRQn_Type irqn; uint32_t pin_mask; } irq_port_info_t; static irq_port_info_t irq_port_usage[NUM_GPIO_PORTS] = {{0, 0},}; static void gpio_irq_dispatcher(uint32_t port_id) { uint32_t pin; gpio_irq_event event; GPIO_PRT_Type *port = Cy_GPIO_PortToAddr(port_id); for (pin = 0; pin < NUM_GPIO_PORT_PINS; ++pin) { if (Cy_GPIO_GetInterruptStatusMasked(port, pin)) { gpio_irq_t *obj = irq_objects[port_id][pin]; MBED_ASSERT(obj); Cy_GPIO_ClearInterrupt(port, pin); /* event = (obj->mode == IRQ_FALL)? IRQ_FALL : IRQ_RISE; */ /* Read pin to determine the edge to support "both" mode */ event = (0UL != Cy_GPIO_Read(port, pin)) ? IRQ_RISE : IRQ_FALL; if (0UL == (obj->mode & event)) { /* In case of very short pulse, actually both edges are occurred, so indicating only the supported one */ event = obj->mode; } /* Otherwise the determined edge is supported (0UL != (obj->mode & event)), so indicating it as is */ obj->handler(obj->id_arg, event); } } } static void gpio_irq_dispatcher_port0(void) { gpio_irq_dispatcher(0); } static void gpio_irq_dispatcher_port1(void) { gpio_irq_dispatcher(1); } static void gpio_irq_dispatcher_port2(void) { gpio_irq_dispatcher(2); } static void gpio_irq_dispatcher_port3(void) { gpio_irq_dispatcher(3); } static void gpio_irq_dispatcher_port4(void) { gpio_irq_dispatcher(4); } static void gpio_irq_dispatcher_port5(void) { gpio_irq_dispatcher(5); } static void gpio_irq_dispatcher_port6(void) { gpio_irq_dispatcher(6); } static void gpio_irq_dispatcher_port7(void) { gpio_irq_dispatcher(7); } static void gpio_irq_dispatcher_port8(void) { gpio_irq_dispatcher(8); } static void gpio_irq_dispatcher_port9(void) { gpio_irq_dispatcher(9); } static void gpio_irq_dispatcher_port10(void) { gpio_irq_dispatcher(10); } static void gpio_irq_dispatcher_port11(void) { gpio_irq_dispatcher(11); } static void gpio_irq_dispatcher_port12(void) { gpio_irq_dispatcher(12); } static void gpio_irq_dispatcher_port13(void) { gpio_irq_dispatcher(13); } static void gpio_irq_dispatcher_port14(void) { gpio_irq_dispatcher(14); } static void (*irq_dispatcher_table[])(void) = { gpio_irq_dispatcher_port0, gpio_irq_dispatcher_port1, gpio_irq_dispatcher_port2, gpio_irq_dispatcher_port3, gpio_irq_dispatcher_port4, gpio_irq_dispatcher_port5, gpio_irq_dispatcher_port6, gpio_irq_dispatcher_port7, gpio_irq_dispatcher_port8, gpio_irq_dispatcher_port9, gpio_irq_dispatcher_port10, gpio_irq_dispatcher_port11, gpio_irq_dispatcher_port12, gpio_irq_dispatcher_port13, gpio_irq_dispatcher_port14 }; static IRQn_Type gpio_irq_allocate_channel(gpio_irq_t *obj) { #if defined (TARGET_MCU_PSOC6_M0) obj->cm0p_irq_src = ioss_interrupts_gpio_0_IRQn + obj->port_id; return cy_m0_nvic_allocate_channel(CY_GPIO_IRQN_ID + obj->port_id); #else return (IRQn_Type)(ioss_interrupts_gpio_0_IRQn + obj->port_id); #endif // M0 } static void gpio_irq_release_channel(IRQn_Type channel, uint32_t port_id) { #if defined (TARGET_MCU_PSOC6_M0) cy_m0_nvic_release_channel(channel, CY_GPIO_IRQN_ID + port_id); #endif //M0 } static int gpio_irq_setup_channel(gpio_irq_t *obj) { cy_stc_sysint_t irq_config; if (irq_port_usage[obj->port_id].pin_mask == 0) { IRQn_Type irqn = gpio_irq_allocate_channel(obj); if (irqn < 0) { return (-1); } irq_port_usage[obj->port_id].irqn = irqn; // Configure NVIC irq_config.intrPriority = GPIO_DEFAULT_IRQ_PRIORITY; irq_config.intrSrc = irqn; #if defined (TARGET_MCU_PSOC6_M0) irq_config.cm0pSrc = obj->cm0p_irq_src; #endif if (Cy_SysInt_Init(&irq_config, irq_dispatcher_table[obj->port_id]) != CY_SYSINT_SUCCESS) { return (-1); } irq_port_usage[obj->port_id].pin_mask |= (1 << obj->pin); gpio_irq_enable(obj); NVIC_EnableIRQ(irqn); } return 0; } int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) { if (pin != NC) { obj->port_id = CY_PORT(pin); obj->port = Cy_GPIO_PortToAddr(obj->port_id); obj->pin = CY_PIN(pin); if (obj->pin > NUM_GPIO_PORT_PINS) { MBED_ASSERT("Invalid pin ID!"); return (-1); } obj->handler = handler; obj->id_arg = id; /* Save reference to current object */ irq_objects[obj->port_id][obj->pin] = obj; return gpio_irq_setup_channel(obj); } else { return (-1); } } void gpio_irq_free(gpio_irq_t *obj) { gpio_irq_disable(obj); // TODO: Need atomicity for the following operations. NVIC_DisableIRQ(irq_port_usage[obj->port_id].irqn); irq_port_usage[obj->port_id].pin_mask &= ~(1 << obj->pin); if (irq_port_usage[obj->port_id].pin_mask == 0) { gpio_irq_release_channel(irq_port_usage[obj->port_id].irqn, obj->port_id); return; } NVIC_EnableIRQ(irq_port_usage[obj->port_id].irqn); } void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) { if (enable) { if (event == IRQ_RISE) { if (obj->mode == IRQ_FALL) { obj->mode += IRQ_RISE; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_BOTH); } else { obj->mode = IRQ_RISE; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_RISING); } } else if (event == IRQ_FALL) { if (obj->mode == IRQ_RISE) { obj->mode += IRQ_FALL; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_BOTH); } else { obj->mode = IRQ_FALL; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_FALLING); } } else { obj->mode = IRQ_NONE; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_DISABLE); } } else if (obj->mode != IRQ_NONE) { if (event == IRQ_RISE) { if (obj->mode == IRQ_RISE) { obj->mode = IRQ_NONE; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_DISABLE); } else { obj->mode = IRQ_FALL; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_FALLING); } } else if (event == IRQ_FALL) { if (obj->mode == IRQ_FALL) { obj->mode = IRQ_NONE; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_DISABLE); } else { obj->mode = IRQ_RISE; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_RISING); } } else { obj->mode = IRQ_NONE; Cy_GPIO_SetInterruptEdge(obj->port, obj->pin, CY_GPIO_INTR_DISABLE); } } } void gpio_irq_enable(gpio_irq_t *obj) { Cy_GPIO_SetInterruptMask(obj->port, obj->pin, 1); } void gpio_irq_disable(gpio_irq_t *obj) { Cy_GPIO_SetInterruptMask(obj->port, obj->pin, 0); }