2014-07-30 14:59:14 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Freie Universität Berlin
|
|
|
|
*
|
|
|
|
* 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 cpu_nrf51822
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @file gpio.c
|
|
|
|
* @brief Low-level GPIO driver implementation
|
|
|
|
*
|
|
|
|
* NOTE: this GPIO driver implementation supports due to hardware limitations
|
|
|
|
* only one pin configured as external interrupt source at a time!
|
|
|
|
*
|
|
|
|
* @author Christian Kühling <kuehling@zedat.fu-berlin.de>
|
|
|
|
* @author Timo Ziegler <timo.ziegler@fu-berlin.de>
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
|
|
*
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "sched.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "periph/gpio.h"
|
|
|
|
#include "periph_conf.h"
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
/* guard file in case no GPIO device is defined */
|
|
|
|
#if GPIO_NUMOF
|
|
|
|
|
2014-07-30 14:59:14 +02:00
|
|
|
typedef struct {
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_t dev;
|
|
|
|
gpio_cb_t cb;
|
|
|
|
void *arg;
|
2014-07-30 14:59:14 +02:00
|
|
|
} gpio_state_t;
|
|
|
|
|
|
|
|
static gpio_state_t gpio_config;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief helper function to get the pin that corresponds to a GPIO device
|
|
|
|
*
|
|
|
|
* @param[in] dev the device the returned pin corresponds to
|
|
|
|
*
|
|
|
|
* @return the pin number of for the given device
|
|
|
|
* @return -1 if device unknown
|
|
|
|
*/
|
|
|
|
static inline int get_pin(gpio_t dev)
|
|
|
|
{
|
|
|
|
switch (dev) {
|
|
|
|
#if GPIO_0_EN
|
|
|
|
case GPIO_0:
|
|
|
|
return GPIO_0_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_1_EN
|
|
|
|
case GPIO_1:
|
|
|
|
return GPIO_1_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_2_EN
|
|
|
|
case GPIO_2:
|
|
|
|
return GPIO_2_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_3_EN
|
|
|
|
case GPIO_3:
|
|
|
|
return GPIO_3_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_4_EN
|
|
|
|
case GPIO_4:
|
|
|
|
return GPIO_4_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_5_EN
|
|
|
|
case GPIO_5:
|
|
|
|
return GPIO_5_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_6_EN
|
|
|
|
case GPIO_6:
|
|
|
|
return GPIO_6_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_7_EN
|
|
|
|
case GPIO_7:
|
|
|
|
return GPIO_7_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_8_EN
|
|
|
|
case GPIO_8:
|
|
|
|
return GPIO_8_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_9_EN
|
|
|
|
case GPIO_9:
|
|
|
|
return GPIO_9_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_10_EN
|
|
|
|
case GPIO_10:
|
|
|
|
return GPIO_10_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_11_EN
|
|
|
|
case GPIO_11:
|
|
|
|
return GPIO_11_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_12_EN
|
|
|
|
case GPIO_12:
|
|
|
|
return GPIO_12_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_13_EN
|
|
|
|
case GPIO_13:
|
|
|
|
return GPIO_13_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_14_EN
|
|
|
|
case GPIO_14:
|
|
|
|
return GPIO_14_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if GPIO_15_EN
|
|
|
|
case GPIO_15:
|
|
|
|
return GPIO_15_PIN;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2014-07-28 16:23:24 +02:00
|
|
|
|
|
|
|
return -1;
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int gpio_init_out(gpio_t dev, gpio_pp_t pullup)
|
|
|
|
{
|
|
|
|
int pin = get_pin(dev);
|
|
|
|
if (pin < 0) {
|
|
|
|
return pin;
|
|
|
|
}
|
|
|
|
|
2014-09-26 17:25:21 +02:00
|
|
|
/* configure pin: output, input buffer disabled */
|
|
|
|
NRF_GPIO->PIN_CNF[pin] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
|
|
|
|
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);
|
|
|
|
/* configure pull up value, map 0x1 -> 0x2; 0x2 -> 0x1 */
|
|
|
|
if (pullup > 0) {
|
|
|
|
NRF_GPIO->PIN_CNF[pin] |= ((pullup ^ 0x3) << GPIO_PIN_CNF_PULL_Pos);
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gpio_init_in(gpio_t dev, gpio_pp_t pullup)
|
|
|
|
{
|
|
|
|
int pin = get_pin(dev);
|
|
|
|
if (pin < 0) {
|
|
|
|
return pin;
|
|
|
|
}
|
|
|
|
|
2014-09-26 17:25:21 +02:00
|
|
|
/* configure pin: output, input buffer disabled */
|
|
|
|
NRF_GPIO->PIN_CNF[pin] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
|
|
|
|
(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos);
|
|
|
|
/* configure pull up value, map 0x1 -> 0x2; 0x2 -> 0x1 */
|
|
|
|
if (pullup > 0) {
|
|
|
|
NRF_GPIO->PIN_CNF[pin] |= ((pullup ^ 0x3) << GPIO_PIN_CNF_PULL_Pos);
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
int gpio_init_int(gpio_t dev, gpio_pp_t pullup, gpio_flank_t flank, gpio_cb_t cb, void *arg)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
|
|
|
int res;
|
|
|
|
uint32_t pin;
|
|
|
|
|
|
|
|
/* configure pin as input */
|
|
|
|
res = gpio_init_in(dev, pullup);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get pin */
|
|
|
|
pin = get_pin(dev); /* no need to check return value, init_in already did */
|
|
|
|
|
|
|
|
/* set interrupt priority and enable global GPIOTE interrupt */
|
|
|
|
NVIC_SetPriority(GPIOTE_IRQn, GPIO_IRQ_PRIO);
|
|
|
|
NVIC_EnableIRQ(GPIOTE_IRQn);
|
|
|
|
|
|
|
|
/* save callback */
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_config.dev = dev;
|
2014-07-30 14:59:14 +02:00
|
|
|
gpio_config.cb = cb;
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_config.arg = arg;
|
2014-07-30 14:59:14 +02:00
|
|
|
|
|
|
|
/* reset GPIOTE configuration register to EVENT mode*/
|
|
|
|
NRF_GPIOTE->CONFIG[0] = GPIOTE_CONFIG_MODE_Event;
|
|
|
|
|
|
|
|
/* select active pin for external interrupt */
|
|
|
|
NRF_GPIOTE->CONFIG[0] |= (pin << GPIOTE_CONFIG_PSEL_Pos);
|
|
|
|
|
|
|
|
/* set active flank */
|
|
|
|
switch (flank) {
|
|
|
|
case GPIO_FALLING:
|
|
|
|
NRF_GPIOTE->CONFIG[0] |= (1 << GPIOTE_CONFIG_POLARITY_Pos);
|
|
|
|
break;
|
|
|
|
case GPIO_RISING:
|
|
|
|
NRF_GPIOTE->CONFIG[0] |= (2 << GPIOTE_CONFIG_POLARITY_Pos);
|
|
|
|
break;
|
|
|
|
case GPIO_BOTH:
|
|
|
|
NRF_GPIOTE->CONFIG[0] |= (3 << GPIOTE_CONFIG_POLARITY_Pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enable external interrupt */
|
|
|
|
NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN0_Msk;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
void gpio_irq_enable(gpio_t dev)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
2014-07-28 16:23:24 +02:00
|
|
|
if (gpio_config.dev == dev) {
|
|
|
|
NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN0_Msk;
|
|
|
|
}
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
void gpio_irq_disable(gpio_t dev)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
2014-07-28 16:23:24 +02:00
|
|
|
if (gpio_config.dev == dev) {
|
|
|
|
NRF_GPIOTE->INTENCLR |= GPIOTE_INTENSET_IN0_Msk;
|
|
|
|
}
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int gpio_read(gpio_t dev)
|
|
|
|
{
|
|
|
|
uint32_t pin;
|
|
|
|
int res = -1;
|
|
|
|
|
|
|
|
/* get pin */
|
|
|
|
pin = get_pin(dev);
|
|
|
|
if (pin < 0) {
|
|
|
|
return pin;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read pin value depending if pin is input or output */
|
|
|
|
if (NRF_GPIO->DIR & (1 << pin)) {
|
|
|
|
res = (NRF_GPIO->OUT & (1 << pin));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
res = (NRF_GPIO->IN & (1 << pin));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fix issue with negative number if pin 31 is set */
|
|
|
|
if (res < -1) {
|
|
|
|
res = 1;
|
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
return res;
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
void gpio_set(gpio_t dev)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
|
|
|
int pin = get_pin(dev);
|
|
|
|
if (pin < 0) {
|
2014-07-28 16:23:24 +02:00
|
|
|
return;
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
NRF_GPIO->OUTSET = (1 << pin);
|
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
void gpio_clear(gpio_t dev)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
|
|
|
int pin = get_pin(dev);
|
|
|
|
if (pin < 0) {
|
2014-07-28 16:23:24 +02:00
|
|
|
return;
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
NRF_GPIO->OUTCLR = (1 << pin);
|
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
void gpio_toggle(gpio_t dev)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
|
|
|
if (gpio_read(dev)) {
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_clear(dev);
|
2014-07-30 14:59:14 +02:00
|
|
|
} else {
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_set(dev);
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-28 16:23:24 +02:00
|
|
|
void gpio_write(gpio_t dev, int value)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
|
|
|
if (value) {
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_set(dev);
|
2014-07-30 14:59:14 +02:00
|
|
|
} else {
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_clear(dev);
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-16 23:13:01 +02:00
|
|
|
void isr_gpiote(void)
|
2014-07-30 14:59:14 +02:00
|
|
|
{
|
|
|
|
if (NRF_GPIOTE->EVENTS_IN[0] == 1)
|
|
|
|
{
|
|
|
|
NRF_GPIOTE->EVENTS_IN[0] = 0;
|
2014-07-28 16:23:24 +02:00
|
|
|
gpio_config.cb(gpio_config.arg);
|
2014-07-30 14:59:14 +02:00
|
|
|
}
|
|
|
|
if (sched_context_switch_request) {
|
|
|
|
thread_yield();
|
|
|
|
}
|
|
|
|
}
|
2014-07-28 16:23:24 +02:00
|
|
|
|
|
|
|
#endif /* GPIO_NUMOF */
|