mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
e7fbaf3815
- removed the __attribute__((naked)) from ISRs - removed ISR_ENTER() and ISR_EXIT() macros Rationale: Cortex-Mx MCUs save registers R0-R4 automatically on calling ISRs. The naked attribute tells the compiler not to save any other registers. This is fine, as long as the code in the ISR is not nested. If nested, it will use also R4 and R5, which will then lead to currupted registers on exit of the ISR. Removing the naked will fix this.
313 lines
6.6 KiB
C
313 lines
6.6 KiB
C
/*
|
|
* 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"
|
|
|
|
/* guard file in case no GPIO device is defined */
|
|
#if GPIO_NUMOF
|
|
|
|
typedef struct {
|
|
gpio_t dev;
|
|
gpio_cb_t cb;
|
|
void *arg;
|
|
} 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
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int gpio_init_out(gpio_t dev, gpio_pp_t pullup)
|
|
{
|
|
int pin = get_pin(dev);
|
|
if (pin < 0) {
|
|
return pin;
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int gpio_init_in(gpio_t dev, gpio_pp_t pullup)
|
|
{
|
|
int pin = get_pin(dev);
|
|
if (pin < 0) {
|
|
return pin;
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
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;
|
|
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 */
|
|
gpio_config.dev = dev;
|
|
gpio_config.cb = cb;
|
|
gpio_config.arg = arg;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
void gpio_irq_enable(gpio_t dev)
|
|
{
|
|
if (gpio_config.dev == dev) {
|
|
NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN0_Msk;
|
|
}
|
|
}
|
|
|
|
void gpio_irq_disable(gpio_t dev)
|
|
{
|
|
if (gpio_config.dev == dev) {
|
|
NRF_GPIOTE->INTENCLR |= GPIOTE_INTENSET_IN0_Msk;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void gpio_set(gpio_t dev)
|
|
{
|
|
int pin = get_pin(dev);
|
|
if (pin < 0) {
|
|
return;
|
|
}
|
|
NRF_GPIO->OUTSET = (1 << pin);
|
|
}
|
|
|
|
void gpio_clear(gpio_t dev)
|
|
{
|
|
int pin = get_pin(dev);
|
|
if (pin < 0) {
|
|
return;
|
|
}
|
|
NRF_GPIO->OUTCLR = (1 << 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);
|
|
}
|
|
}
|
|
|
|
void isr_gpiote(void)
|
|
{
|
|
if (NRF_GPIOTE->EVENTS_IN[0] == 1)
|
|
{
|
|
NRF_GPIOTE->EVENTS_IN[0] = 0;
|
|
gpio_config.cb(gpio_config.arg);
|
|
}
|
|
if (sched_context_switch_request) {
|
|
thread_yield();
|
|
}
|
|
}
|
|
|
|
#endif /* GPIO_NUMOF */
|