mirror of https://github.com/ARMmbed/mbed-os.git
220 lines
6.1 KiB
C
220 lines
6.1 KiB
C
/* mbed Microcontroller Library
|
|
* Copyright (c) 2019 ARM Limited
|
|
* 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.
|
|
*/
|
|
|
|
/* Low-level implementation of gpio interrupts for MSP432.
|
|
* This implementation uses bit-banding, so no masking of bits
|
|
* is necessary during simple get/set operations for a single pin.
|
|
*
|
|
* See hal/gpio_api.h for a detailed description of the following
|
|
* functions.
|
|
*/
|
|
#if DEVICE_INTERRUPTIN
|
|
|
|
#include "gpio_irq_api.h"
|
|
#include "mbed_error.h"
|
|
#include "gpio_msp432.h"
|
|
|
|
static uint32_t irq_ids [6][8] = {0};
|
|
static uint8_t both_edges[6][8] = {0};
|
|
|
|
static gpio_irq_handler irq_handler = 0;
|
|
|
|
|
|
/** 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)
|
|
{
|
|
if (pin == (PinName)NC) {
|
|
obj->pin_base = 0;
|
|
return -1;
|
|
}
|
|
uint8_t port_index = MSP432_PORT_IDX(pin);
|
|
uint8_t pin_index = MSP432_PIN_IDX(pin);
|
|
if (port_index > 5 || pin_index > 7) {
|
|
obj->pin_base = 0;
|
|
error("IRQs not supported on GPIO P%d.%d\r\n", port_index + 1, pin_index);
|
|
return -1;
|
|
}
|
|
// Initialize the gpio_t object
|
|
obj->pin_base = PIN_BASE(port_index, pin_index);
|
|
obj->port = port_index;
|
|
obj->pin = pin_index;
|
|
obj->rise = 0;
|
|
obj->fall = 0;
|
|
// Store irq handler. We do not have to store
|
|
// a separate handler for every pin, because the
|
|
// InterruptIn-driver will always use the same one...
|
|
irq_handler = handler;
|
|
// Store the ID for this specific pin. It will be
|
|
// used as a pointer to one InterruptIn instance by
|
|
// the InterruptIn class.
|
|
irq_ids[port_index][pin_index] = id;
|
|
// Clear pending IRQ
|
|
PIN_REG(obj->pin_base, REG_IFG) = 0;
|
|
// Enable IRQs on this port
|
|
NVIC_EnableIRQ((IRQn_Type)(35 + port_index));
|
|
return 0;
|
|
}
|
|
|
|
/** Release the GPIO IRQ PIN
|
|
*
|
|
* @param obj The gpio object
|
|
*/
|
|
void gpio_irq_free(gpio_irq_t *obj)
|
|
{
|
|
// Disable the interrupts
|
|
gpio_irq_disable(obj);
|
|
// Clear the ID
|
|
irq_ids[obj->port][obj->pin] = 0;
|
|
// Clear the gpio_irq_t object
|
|
obj->pin_base = 0;
|
|
obj->port = 0;
|
|
obj->pin = 0;
|
|
obj->rise = 0;
|
|
obj->fall = 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)
|
|
{
|
|
// Disable irqs for this pin while we are in the
|
|
// configuration process (so we have a chance to
|
|
// clear spurious interrupts.
|
|
PIN_REG(obj->pin_base, REG_IE) = 0;
|
|
switch (event) {
|
|
case IRQ_RISE: {
|
|
// Listen to rising edges
|
|
PIN_REG(obj->pin_base, REG_IES) = 0;
|
|
obj->rise = enable;
|
|
// Check if we have enabled both edges
|
|
both_edges[obj->port][obj->pin] = obj->rise && obj->fall;
|
|
break;
|
|
}
|
|
case IRQ_FALL: {
|
|
// Listen to falling edges
|
|
PIN_REG(obj->pin_base, REG_IES) = 1;
|
|
obj->fall = enable;
|
|
// Check if we have enabled both edges
|
|
both_edges[obj->port][obj->pin] = obj->rise && obj->fall;
|
|
break;
|
|
}
|
|
case IRQ_NONE:
|
|
default:
|
|
break;
|
|
}
|
|
// Enable IRQ as requested
|
|
enable ? gpio_irq_enable(obj) : gpio_irq_disable(obj);
|
|
}
|
|
|
|
void gpio_irq_enable(gpio_irq_t *obj)
|
|
{
|
|
// Clear pending interrupts (just in case...)
|
|
PIN_REG(obj->pin_base, REG_IFG) = 0;
|
|
// Check if both edges need to be detected and
|
|
// set initial edge select accordingly
|
|
if (both_edges[obj->port][obj->pin]) {
|
|
PIN_REG(obj->pin_base, REG_IES) = PIN_REG(obj->pin_base, REG_IN);
|
|
// Make sure we don't accidently trigger a irq!
|
|
PIN_REG(obj->pin_base, REG_IFG) = 0;
|
|
}
|
|
// Enable irqs for this pin
|
|
PIN_REG(obj->pin_base, REG_IE) = 1;
|
|
}
|
|
|
|
void gpio_irq_disable(gpio_irq_t *obj)
|
|
{
|
|
// Disable irqs for this pin
|
|
PIN_REG(obj->pin_base, REG_IE) = 0;
|
|
// Clear pending interrupts
|
|
PIN_REG(obj->pin_base, REG_IFG) = 0;
|
|
}
|
|
|
|
/**********************************/
|
|
/* Interrupt handlers for P1...P6 */
|
|
/**********************************/
|
|
void handle_interrupt_in(uint8_t port, uint8_t pin)
|
|
{
|
|
__IO uint8_t *pin_base = PIN_BASE(port, pin);
|
|
// Call the second-stage handler
|
|
if (irq_handler) {
|
|
irq_handler(irq_ids[port][pin],
|
|
PIN_REG(pin_base, REG_IN) ? IRQ_RISE : IRQ_FALL);
|
|
}
|
|
// Change the edge select when listening on both edges
|
|
if (both_edges[port][pin]) {
|
|
PIN_REG(pin_base, REG_IES) = PIN_REG(pin_base, REG_IN);
|
|
// Make sure we don't accidently trigger a irq!
|
|
PIN_REG(pin_base, REG_IFG) = 0;
|
|
}
|
|
}
|
|
|
|
void PORT1_IRQHandler(void)
|
|
{
|
|
uint32_t pin = P1->IV >> 1;
|
|
if (pin--) {
|
|
handle_interrupt_in(0, pin);
|
|
}
|
|
}
|
|
void PORT2_IRQHandler(void)
|
|
{
|
|
uint32_t pin = P2->IV >> 1;
|
|
if (pin--) {
|
|
handle_interrupt_in(1, pin);
|
|
}
|
|
}
|
|
void PORT3_IRQHandler(void)
|
|
{
|
|
uint32_t pin = P3->IV >> 1;
|
|
if (pin--) {
|
|
handle_interrupt_in(2, pin);
|
|
}
|
|
}
|
|
void PORT4_IRQHandler(void)
|
|
{
|
|
uint32_t pin = P4->IV >> 1;
|
|
if (pin--) {
|
|
handle_interrupt_in(3, pin);
|
|
}
|
|
}
|
|
void PORT5_IRQHandler(void)
|
|
{
|
|
uint32_t pin = P5->IV >> 1;
|
|
if (pin--) {
|
|
handle_interrupt_in(4, pin);
|
|
}
|
|
}
|
|
void PORT6_IRQHandler(void)
|
|
{
|
|
uint32_t pin = P6->IV >> 1;
|
|
if (pin--) {
|
|
handle_interrupt_in(5, pin);
|
|
}
|
|
}
|
|
|
|
#endif /* DEVICE_INTERRUPTIN */
|