1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/cc2538/periph/gpio.c
2014-10-24 14:00:47 +02:00

659 lines
12 KiB
C

/*
* Copyright (C) 2014 Loci Controls Inc.
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup driver_periph
* @{
*
* @file gpio.c
* @brief Low-level GPIO driver implementation
*
* @author Ian Martin <ian@locicontrols.com>
*
* @}
*/
#include <stdint.h>
#include "cpu.h"
#include "sched.h"
#include "thread.h"
#include "cc2538-gpio.h"
#include "ioc.h"
#include "periph/gpio.h"
#include "periph_conf.h"
/* guard file in case no GPIO devices are defined */
#if GPIO_NUMOF
/**
* @brief Generate a bit mask in which only the specified bit is high.
*
* @param[in] n Number of the bit to set high in the mask.
*
* @return A bit mask in which bit n is high.
*/
#define BIT(n) ( 1 << (n) )
/**
* @brief Checks a bit in enable_lut to determine if a GPIO is enabled
*
* @param[in] dev RIOT GPIO device number
*
* @return 0 or 1 indicating if the specified GPIO is enabled
*/
#define gpio_enabled(dev) ( (enable_lut >> (dev)) & 1 )
typedef struct {
gpio_cb_t cb; /**< callback called from GPIO interrupt */
void *arg; /**< argument passed to the callback */
} gpio_state_t;
static gpio_state_t gpio_config[GPIO_NUMOF];
const uint32_t enable_lut = 0
#if GPIO_0_EN
| BIT(0)
#endif
#if GPIO_1_EN
| BIT(1)
#endif
#if GPIO_2_EN
| BIT(2)
#endif
#if GPIO_3_EN
| BIT(3)
#endif
#if GPIO_4_EN
| BIT(4)
#endif
#if GPIO_5_EN
| BIT(5)
#endif
#if GPIO_6_EN
| BIT(6)
#endif
#if GPIO_7_EN
| BIT(7)
#endif
#if GPIO_8_EN
| BIT(8)
#endif
#if GPIO_9_EN
| BIT(9)
#endif
#if GPIO_10_EN
| BIT(10)
#endif
#if GPIO_11_EN
| BIT(11)
#endif
#if GPIO_12_EN
| BIT(12)
#endif
#if GPIO_13_EN
| BIT(13)
#endif
#if GPIO_14_EN
| BIT(14)
#endif
#if GPIO_15_EN
| BIT(15)
#endif
#if GPIO_16_EN
| BIT(16)
#endif
#if GPIO_17_EN
| BIT(17)
#endif
#if GPIO_18_EN
| BIT(18)
#endif
#if GPIO_19_EN
| BIT(19)
#endif
#if GPIO_20_EN
| BIT(20)
#endif
#if GPIO_21_EN
| BIT(21)
#endif
#if GPIO_22_EN
| BIT(22)
#endif
#if GPIO_23_EN
| BIT(23)
#endif
#if GPIO_24_EN
| BIT(24)
#endif
#if GPIO_25_EN
| BIT(25)
#endif
#if GPIO_26_EN
| BIT(26)
#endif
#if GPIO_27_EN
| BIT(27)
#endif
#if GPIO_28_EN
| BIT(28)
#endif
#if GPIO_29_EN
| BIT(29)
#endif
#if GPIO_30_EN
| BIT(30)
#endif
#if GPIO_31_EN
| BIT(31)
#endif
;
const unsigned int pin_lut[] = {
#if GPIO_0_EN
[ 0] = GPIO_0_PIN,
#endif
#if GPIO_1_EN
[ 1] = GPIO_1_PIN,
#endif
#if GPIO_2_EN
[ 2] = GPIO_2_PIN,
#endif
#if GPIO_3_EN
[ 3] = GPIO_3_PIN,
#endif
#if GPIO_4_EN
[ 4] = GPIO_4_PIN,
#endif
#if GPIO_5_EN
[ 5] = GPIO_5_PIN,
#endif
#if GPIO_6_EN
[ 6] = GPIO_6_PIN,
#endif
#if GPIO_7_EN
[ 7] = GPIO_7_PIN,
#endif
#if GPIO_8_EN
[ 8] = GPIO_8_PIN,
#endif
#if GPIO_9_EN
[ 9] = GPIO_9_PIN,
#endif
#if GPIO_10_EN
[10] = GPIO_10_PIN,
#endif
#if GPIO_11_EN
[11] = GPIO_11_PIN,
#endif
#if GPIO_12_EN
[12] = GPIO_12_PIN,
#endif
#if GPIO_13_EN
[13] = GPIO_13_PIN,
#endif
#if GPIO_14_EN
[14] = GPIO_14_PIN,
#endif
#if GPIO_15_EN
[15] = GPIO_15_PIN,
#endif
#if GPIO_16_EN
[16] = GPIO_16_PIN,
#endif
#if GPIO_17_EN
[17] = GPIO_17_PIN,
#endif
#if GPIO_18_EN
[18] = GPIO_18_PIN,
#endif
#if GPIO_19_EN
[19] = GPIO_19_PIN,
#endif
#if GPIO_20_EN
[20] = GPIO_20_PIN,
#endif
#if GPIO_21_EN
[21] = GPIO_21_PIN,
#endif
#if GPIO_22_EN
[22] = GPIO_22_PIN,
#endif
#if GPIO_23_EN
[23] = GPIO_23_PIN,
#endif
#if GPIO_24_EN
[24] = GPIO_24_PIN,
#endif
#if GPIO_25_EN
[25] = GPIO_25_PIN,
#endif
#if GPIO_26_EN
[26] = GPIO_26_PIN,
#endif
#if GPIO_27_EN
[27] = GPIO_27_PIN,
#endif
#if GPIO_28_EN
[28] = GPIO_28_PIN,
#endif
#if GPIO_29_EN
[29] = GPIO_29_PIN,
#endif
#if GPIO_30_EN
[30] = GPIO_30_PIN,
#endif
#if GPIO_31_EN
[31] = GPIO_31_PIN,
#endif
};
static const uint8_t reverse_pin_lut[] = {
#if GPIO_0_EN
[GPIO_0_PIN] = 0,
#endif
#if GPIO_1_EN
[GPIO_1_PIN] = 1,
#endif
#if GPIO_2_EN
[GPIO_2_PIN] = 2,
#endif
#if GPIO_3_EN
[GPIO_3_PIN] = 3,
#endif
#if GPIO_4_EN
[GPIO_4_PIN] = 4,
#endif
#if GPIO_5_EN
[GPIO_5_PIN] = 5,
#endif
#if GPIO_6_EN
[GPIO_6_PIN] = 6,
#endif
#if GPIO_7_EN
[GPIO_7_PIN] = 7,
#endif
#if GPIO_8_EN
[GPIO_8_PIN] = 8,
#endif
#if GPIO_9_EN
[GPIO_9_PIN] = 9,
#endif
#if GPIO_10_EN
[GPIO_10_PIN] = 10,
#endif
#if GPIO_11_EN
[GPIO_11_PIN] = 11,
#endif
#if GPIO_12_EN
[GPIO_12_PIN] = 12,
#endif
#if GPIO_13_EN
[GPIO_13_PIN] = 13,
#endif
#if GPIO_14_EN
[GPIO_14_PIN] = 14,
#endif
#if GPIO_15_EN
[GPIO_15_PIN] = 15,
#endif
#if GPIO_16_EN
[GPIO_16_PIN] = 16,
#endif
#if GPIO_17_EN
[GPIO_17_PIN] = 17,
#endif
#if GPIO_18_EN
[GPIO_18_PIN] = 18,
#endif
#if GPIO_19_EN
[GPIO_19_PIN] = 19,
#endif
#if GPIO_20_EN
[GPIO_20_PIN] = 20,
#endif
#if GPIO_21_EN
[GPIO_21_PIN] = 21,
#endif
#if GPIO_22_EN
[GPIO_22_PIN] = 22,
#endif
#if GPIO_23_EN
[GPIO_23_PIN] = 23,
#endif
#if GPIO_24_EN
[GPIO_24_PIN] = 24,
#endif
#if GPIO_25_EN
[GPIO_25_PIN] = 25,
#endif
#if GPIO_26_EN
[GPIO_26_PIN] = 26,
#endif
#if GPIO_27_EN
[GPIO_27_PIN] = 27,
#endif
#if GPIO_28_EN
[GPIO_28_PIN] = 28,
#endif
#if GPIO_29_EN
[GPIO_29_PIN] = 29,
#endif
#if GPIO_30_EN
[GPIO_30_PIN] = 30,
#endif
#if GPIO_31_EN
[GPIO_31_PIN] = 31,
#endif
};
static const uint32_t ioc_mask_lut[] = {
[GPIO_NOPULL ] = IOC_OVERRIDE_OE,
[GPIO_PULLUP ] = IOC_OVERRIDE_OE | IOC_OVERRIDE_PUE,
[GPIO_PULLDOWN] = IOC_OVERRIDE_OE | IOC_OVERRIDE_PDE,
};
int gpio_init_out(gpio_t dev, gpio_pp_t pushpull)
{
int pin;
if (!gpio_enabled(dev)) {
return -1;
}
pin = pin_lut[dev];
gpio_software_control(pin);
gpio_dir_output(pin);
/* configure the pin's pull resistor state */
IOC_PXX_OVER[pin] = ioc_mask_lut[pushpull];
return 0;
}
int gpio_init_in(gpio_t dev, gpio_pp_t pushpull)
{
int pin;
if (!gpio_enabled(dev)) {
return -1;
}
pin = pin_lut[dev];
gpio_software_control(pin);
gpio_dir_input(pin);
/* configure the pin's pull resistor state */
IOC_PXX_OVER[pin] = ioc_mask_lut[pushpull];
return 0;
}
int gpio_init_int(gpio_t dev, gpio_pp_t pullup, gpio_flank_t flank, gpio_cb_t cb, void *arg)
{
int res, pin, irq_num;
uint32_t mask;
cc2538_gpio_t* instance;
/* Note: gpio_init_in() also checks if the gpio is enabled. */
res = gpio_init_in(dev, pullup);
if (res < 0) {
return res;
}
/* Store the callback information for later: */
gpio_config[dev].cb = cb;
gpio_config[dev].arg = arg;
pin = pin_lut[dev];
mask = GPIO_PIN_MASK(GPIO_BIT_NUM(pin));
instance = GPIO_NUM_TO_DEV(pin);
/* Enable power-up interrupts for this GPIO port: */
SYS_CTRL_IWE |= BIT(GPIO_NUM_TO_PORT_NUM(pin));
switch(flank) {
case GPIO_FALLING:
instance->IBE &= ~mask; /**< Not both edges */
instance->IEV &= ~mask; /**< Falling edge */
instance->P_EDGE_CTRL |= BIT(pin); /**< Falling edge power-up interrupt */
break;
case GPIO_RISING:
instance->IBE &= ~mask; /**< Not both edges */
instance->IEV |= mask; /**< Rising edge */
instance->P_EDGE_CTRL &= ~BIT(pin); /**< Rising edge power-up interrupt */
break;
case GPIO_BOTH:
instance->IBE = mask; /**< Both edges */
break;
}
instance->IS &= ~mask; /**< Edge triggered (as opposed to level-triggered) */
instance->IC |= mask; /**< Clear any preexisting interrupt state */
instance->PI_IEN |= BIT(pin); /**< Enable power-up interrupts for this pin */
/* Set interrupt priority for the whole GPIO port: */
irq_num = GPIO_PORT_A_IRQn + GPIO_NUM_TO_PORT_NUM(pin);
NVIC_SetPriority(irq_num, GPIO_IRQ_PRIO);
/* Enable interrupts for the whole GPIO port: */
NVIC_EnableIRQ(irq_num);
/* Enable interrupts for the specific pin: */
instance->IE |= mask;
return 0;
}
void gpio_irq_enable(gpio_t dev)
{
if (gpio_enabled(dev)) {
int pin = pin_lut[dev];
GPIO_NUM_TO_DEV(pin)->IE |= GPIO_PIN_MASK(GPIO_BIT_NUM(pin));
}
}
void gpio_irq_disable(gpio_t dev)
{
if (gpio_enabled(dev)) {
int pin = pin_lut[dev];
GPIO_NUM_TO_DEV(pin)->IE &= ~GPIO_PIN_MASK(GPIO_BIT_NUM(pin));
}
}
int gpio_read(gpio_t dev)
{
int pin;
if (!gpio_enabled(dev)) {
return -1;
}
pin = pin_lut[dev];
return (GPIO_NUM_TO_DEV(pin)->DATA >> GPIO_BIT_NUM(pin)) & 1;
}
void gpio_set(gpio_t dev)
{
int pin;
if (!gpio_enabled(dev)) {
return;
}
pin = pin_lut[dev];
GPIO_NUM_TO_DEV(pin)->DATA |= GPIO_PIN_MASK(GPIO_BIT_NUM(pin));
}
void gpio_clear(gpio_t dev)
{
int pin;
if (!gpio_enabled(dev)) {
return;
}
pin = pin_lut[dev];
GPIO_NUM_TO_DEV(pin)->DATA &= ~GPIO_PIN_MASK(GPIO_BIT_NUM(pin));
}
void gpio_toggle(gpio_t dev)
{
if (gpio_read(dev)) {
gpio_clear(dev);
}
else {
gpio_set(dev);
}
}
void gpio_write(gpio_t dev, int value)
{
if (value) {
gpio_set(dev);
}
else {
gpio_clear(dev);
}
}
/** @brief Interrupt service routine for Port A */
__attribute__((naked))
void isr_gpioa(void)
{
int mis, bit;
gpio_state_t* state;
ISR_ENTER();
asm("push {r4-r5}");
/* Latch and clear the interrupt status early on: */
mis = GPIO_A->MIS;
GPIO_A->IC = 0x000000ff;
GPIO_A->IRQ_DETECT_ACK = 0x000000ff;
for (bit = 0; bit < GPIO_BITS_PER_PORT; bit++) {
if (mis & 1) {
state = gpio_config + reverse_pin_lut[GPIO_PXX_TO_NUM(PORT_A, bit)];
state->cb(state->arg);
}
mis >>= 1;
}
if (sched_context_switch_request) {
thread_yield();
}
asm("pop {r4-r5}");
ISR_EXIT();
}
/** @brief Interrupt service routine for Port B */
__attribute__((naked))
void isr_gpiob(void)
{
int mis, bit;
gpio_state_t* state;
ISR_ENTER();
asm("push {r4-r5}");
/* Latch and clear the interrupt status early on: */
mis = GPIO_B->MIS;
GPIO_B->IC = 0x000000ff;
GPIO_B->IRQ_DETECT_ACK = 0x0000ff00;
for (bit = 0; bit < GPIO_BITS_PER_PORT; bit++) {
if (mis & 1) {
state = gpio_config + reverse_pin_lut[GPIO_PXX_TO_NUM(PORT_B, bit)];
state->cb(state->arg);
}
mis >>= 1;
}
if (sched_context_switch_request) {
thread_yield();
}
asm("pop {r4-r5}");
ISR_EXIT();
}
/** @brief Interrupt service routine for Port C */
__attribute__((naked))
void isr_gpioc(void)
{
int mis, bit;
gpio_state_t* state;
ISR_ENTER();
asm("push {r4-r5}");
/* Latch and clear the interrupt status early on: */
mis = GPIO_C->MIS;
GPIO_C->IC = 0x000000ff;
GPIO_C->IRQ_DETECT_ACK = 0x00ff0000;
for (bit = 0; bit < GPIO_BITS_PER_PORT; bit++) {
if (mis & 1) {
state = gpio_config + reverse_pin_lut[GPIO_PXX_TO_NUM(PORT_C, bit)];
state->cb(state->arg);
}
mis >>= 1;
}
if (sched_context_switch_request) {
thread_yield();
}
asm("pop {r4-r5}");
ISR_EXIT();
}
/** @brief Interrupt service routine for Port D */
__attribute__((naked))
void isr_gpiod(void)
{
int mis, bit;
gpio_state_t* state;
ISR_ENTER();
asm("push {r4-r5}");
/* Latch and clear the interrupt status early on: */
mis = GPIO_D->MIS;
GPIO_D->IC = 0x000000ff;
GPIO_D->IRQ_DETECT_ACK = 0xff000000;
for (bit = 0; bit < GPIO_BITS_PER_PORT; bit++) {
if (mis & 1) {
state = gpio_config + reverse_pin_lut[GPIO_PXX_TO_NUM(PORT_D, bit)];
state->cb(state->arg);
}
mis >>= 1;
}
if (sched_context_switch_request) {
thread_yield();
}
asm("pop {r4-r5}");
ISR_EXIT();
}
#endif /* GPIO_NUMOF */