mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #17980 from maribu/gpio_ll/nrf5x
cpu/nrf5x_common: implement periph/gpio_ll{,_irq}
This commit is contained in:
commit
b6b1468240
@ -13,6 +13,9 @@ config CPU_COMMON_NRF5X
|
||||
select HAS_PERIPH_FLASHPAGE_PAGEWISE
|
||||
select HAS_PERIPH_GPIO
|
||||
select HAS_PERIPH_GPIO_IRQ
|
||||
select HAS_PERIPH_GPIO_LL
|
||||
select HAS_PERIPH_GPIO_LL_IRQ
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_UNMASK
|
||||
select HAS_PERIPH_HWRNG
|
||||
select HAS_PERIPH_TEMPERATURE
|
||||
select HAS_PERIPH_TIMER_PERIODIC
|
||||
|
@ -4,6 +4,7 @@ FEATURES_PROVIDED += periph_flashpage
|
||||
FEATURES_PROVIDED += periph_flashpage_in_address_space
|
||||
FEATURES_PROVIDED += periph_flashpage_pagewise
|
||||
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
|
||||
FEATURES_PROVIDED += periph_gpio_ll periph_gpio_ll_irq periph_gpio_ll_irq_unmask
|
||||
FEATURES_PROVIDED += periph_timer_periodic
|
||||
FEATURES_PROVIDED += periph_uart_modecfg
|
||||
|
||||
|
157
cpu/nrf5x_common/include/gpio_ll_arch.h
Normal file
157
cpu/nrf5x_common/include/gpio_ll_arch.h
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jan Wagner <mail@jwagner.eu>
|
||||
* 2015-2016 Freie Universität Berlin
|
||||
* 2019 Inria
|
||||
*
|
||||
* 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_nrf5x_common
|
||||
* @ingroup drivers_periph_gpio_ll
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief CPU specific part of the Peripheral GPIO Low-Level API
|
||||
*
|
||||
* @note This GPIO driver implementation supports only one pin to be
|
||||
* defined as external interrupt.
|
||||
*
|
||||
* @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>
|
||||
* @author Jan Wagner <mail@jwagner.eu>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef GPIO_LL_ARCH_H
|
||||
#define GPIO_LL_ARCH_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "irq.h"
|
||||
#include "periph_cpu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN /* hide implementation specific details from Doxygen */
|
||||
|
||||
#define PORT_BIT (1 << 5)
|
||||
#define PIN_MASK (0x1f)
|
||||
#define NRF5X_IO_AREA_START (0x40000000UL)
|
||||
|
||||
/* Compatibility wrapper defines for nRF9160 */
|
||||
#ifdef NRF_P0_S
|
||||
#define NRF_P0 NRF_P0_S
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FAM_NRF51)
|
||||
#define GPIO_PORT(num) ((gpio_port_t)NRF_GPIO)
|
||||
#define GPIO_PORT_NUM(port) 0
|
||||
#elif defined(NRF_P1)
|
||||
#define GPIO_PORT(num) ((num) ? (gpio_port_t)NRF_P1 : (gpio_port_t)NRF_P0)
|
||||
#define GPIO_PORT_NUM(port) ((port == (gpio_port_t)NRF_P1) ? 1 : 0)
|
||||
#else
|
||||
#define GPIO_PORT(num) ((gpio_port_t)NRF_P0)
|
||||
#define GPIO_PORT_NUM(port) 0
|
||||
#endif
|
||||
|
||||
static inline uword_t gpio_ll_read(gpio_port_t port)
|
||||
{
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
return p->IN;
|
||||
}
|
||||
|
||||
static inline uword_t gpio_ll_read_output(gpio_port_t port)
|
||||
{
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
return p->OUT;
|
||||
}
|
||||
|
||||
static inline void gpio_ll_set(gpio_port_t port, uword_t mask)
|
||||
{
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
p->OUTSET = mask;
|
||||
}
|
||||
|
||||
static inline void gpio_ll_clear(gpio_port_t port, uword_t mask)
|
||||
{
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
p->OUTCLR = mask;
|
||||
}
|
||||
|
||||
static inline void gpio_ll_toggle(gpio_port_t port, uword_t mask)
|
||||
{
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
unsigned state = irq_disable();
|
||||
p->OUT ^= mask;
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
static inline void gpio_ll_write(gpio_port_t port, uword_t value)
|
||||
{
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
p->OUT = value;
|
||||
}
|
||||
|
||||
static inline gpio_port_t gpio_get_port(gpio_t pin)
|
||||
{
|
||||
#if defined(NRF_P1)
|
||||
return GPIO_PORT(pin >> 5);
|
||||
#else
|
||||
(void)pin;
|
||||
return GPIO_PORT(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t gpio_get_pin_num(gpio_t pin)
|
||||
{
|
||||
#if defined(NRF_P1)
|
||||
return pin & PIN_MASK;
|
||||
#else
|
||||
return (uint8_t)pin;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline gpio_port_t gpio_port_pack_addr(void *addr)
|
||||
{
|
||||
return (gpio_port_t)addr;
|
||||
}
|
||||
|
||||
static inline void * gpio_port_unpack_addr(gpio_port_t port)
|
||||
{
|
||||
/* NRF5X_IO_AREA_START is the start of the memory mapped I/O area. Both data
|
||||
* and flash are mapped before it. So if it is an I/O address, it
|
||||
* cannot be a packed data address and (hopefully) is a GPIO port */
|
||||
if (port >= NRF5X_IO_AREA_START) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *)port;
|
||||
}
|
||||
|
||||
static inline bool is_gpio_port_num_valid(uint_fast8_t num)
|
||||
{
|
||||
switch (num) {
|
||||
default:
|
||||
return false;
|
||||
case 0:
|
||||
#if defined(NRF_P1)
|
||||
case 1:
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DOXYGEN */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GPIO_LL_ARCH_H */
|
||||
/** @} */
|
@ -80,6 +80,50 @@ extern "C" {
|
||||
*/
|
||||
#define GPIO_MODE(oe, ic, pr, dr) (oe | (ic << 1) | (pr << 2) | (dr << 8))
|
||||
|
||||
#ifndef DOXYGEN /* BEGIN: GPIO LL overwrites */
|
||||
#define HAVE_GPIO_SLEW_T
|
||||
typedef enum {
|
||||
GPIO_SLEW_SLOWEST = 0,
|
||||
GPIO_SLEW_SLOW = 0,
|
||||
GPIO_SLEW_FAST = 0,
|
||||
GPIO_SLEW_FASTEST = 0,
|
||||
} gpio_slew_t;
|
||||
|
||||
#define HAVE_GPIO_PULL_STRENGTH_T
|
||||
typedef enum {
|
||||
GPIO_PULL_WEAKEST = 0,
|
||||
GPIO_PULL_WEAK = 0,
|
||||
GPIO_PULL_STRONG = 0,
|
||||
GPIO_PULL_STRONGEST = 0
|
||||
} gpio_pull_strength_t;
|
||||
|
||||
#define HAVE_GPIO_DRIVE_STRENGTH_T
|
||||
typedef enum {
|
||||
GPIO_DRIVE_WEAKEST = 0,
|
||||
GPIO_DRIVE_WEAK = 0,
|
||||
GPIO_DRIVE_STRONG = 1,
|
||||
GPIO_DRIVE_STRONGEST = 1
|
||||
} gpio_drive_strength_t;
|
||||
|
||||
#define HAVE_GPIO_IRQ_TRIG_T
|
||||
typedef enum {
|
||||
GPIO_TRIGGER_EDGE_RISING = GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos,
|
||||
GPIO_TRIGGER_EDGE_FALLING = GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos,
|
||||
GPIO_TRIGGER_EDGE_BOTH = GPIO_TRIGGER_EDGE_RISING | GPIO_TRIGGER_EDGE_FALLING,
|
||||
GPIO_TRIGGER_LEVEL_HIGH = 0, /**< unsupported */
|
||||
GPIO_TRIGGER_LEVEL_LOW = 0, /**< unsupported */
|
||||
} gpio_irq_trig_t;
|
||||
|
||||
#define HAVE_GPIO_PULL_T
|
||||
typedef enum {
|
||||
GPIO_FLOATING = 0,
|
||||
GPIO_PULL_UP = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos,
|
||||
GPIO_PULL_DOWN = GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos,
|
||||
/* GPIO_PULL_KEEP is not supported by, gpio_ll_init() returns -ENOTSUP */
|
||||
GPIO_PULL_KEEP = 0xff
|
||||
} gpio_pull_t;
|
||||
#endif /* END: GPIO LL overwrites */
|
||||
|
||||
/**
|
||||
* @brief No support for HW chip select...
|
||||
*/
|
||||
|
199
cpu/nrf5x_common/periph/gpio_ll.c
Normal file
199
cpu/nrf5x_common/periph/gpio_ll.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jan Wagner <mail@jwagner.eu>
|
||||
* 2015-2016 Freie Universität Berlin
|
||||
* 2019 Inria
|
||||
* 2021 Otto-von-Guericke-Universität Magdeburg
|
||||
*
|
||||
* 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_nrf5x_common
|
||||
* @ingroup drivers_periph_gpio_ll
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Peripheral GPIO Low-Level API implementation for the nRF5x MCU family
|
||||
*
|
||||
* @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>
|
||||
* @author Jan Wagner <mail@jwagner.eu>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "periph/gpio_ll.h"
|
||||
#include "periph_cpu.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf)
|
||||
{
|
||||
if (conf->pull == GPIO_PULL_KEEP) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
uint32_t pin_cnf = conf->pull;
|
||||
switch (conf->state) {
|
||||
case GPIO_OUTPUT_PUSH_PULL:
|
||||
/* INPUT bit needs to be *CLEARED* in input mode, so set to disconnect input buffer */
|
||||
pin_cnf |= GPIO_PIN_CNF_DIR_Msk | GPIO_PIN_CNF_INPUT_Msk;
|
||||
if (conf->drive_strength) {
|
||||
pin_cnf |= GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos;
|
||||
}
|
||||
break;
|
||||
case GPIO_OUTPUT_OPEN_DRAIN:
|
||||
pin_cnf |= GPIO_PIN_CNF_DIR_Msk;
|
||||
if (conf->drive_strength) {
|
||||
pin_cnf |= GPIO_PIN_CNF_DRIVE_H0D1 << GPIO_PIN_CNF_DRIVE_Pos;
|
||||
}
|
||||
else {
|
||||
pin_cnf |= GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos;
|
||||
}
|
||||
break;
|
||||
case GPIO_OUTPUT_OPEN_SOURCE:
|
||||
pin_cnf |= GPIO_PIN_CNF_DIR_Msk;
|
||||
if (conf->drive_strength) {
|
||||
pin_cnf |= GPIO_PIN_CNF_DRIVE_D0H1 << GPIO_PIN_CNF_DRIVE_Pos;
|
||||
}
|
||||
else {
|
||||
pin_cnf |= GPIO_PIN_CNF_DRIVE_D0S1 << GPIO_PIN_CNF_DRIVE_Pos;
|
||||
}
|
||||
break;
|
||||
case GPIO_INPUT:
|
||||
break;
|
||||
case GPIO_DISCONNECT:
|
||||
default:
|
||||
/* INPUT bit needs to be *CLEARED* in input mode, so set to disconnect input buffer */
|
||||
pin_cnf |= GPIO_PIN_CNF_INPUT_Msk;
|
||||
break;
|
||||
}
|
||||
|
||||
if (conf->state != GPIO_OUTPUT_PUSH_PULL) {
|
||||
switch (conf->pull) {
|
||||
default:
|
||||
case GPIO_FLOATING:
|
||||
break;
|
||||
case GPIO_PULL_UP:
|
||||
pin_cnf |= GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos;
|
||||
break;
|
||||
case GPIO_PULL_DOWN:
|
||||
pin_cnf |= GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
if (conf->initial_value) {
|
||||
p->OUTSET = 1UL << pin;
|
||||
}
|
||||
else {
|
||||
p->OUTCLR = 1UL << pin;
|
||||
}
|
||||
p->PIN_CNF[pin] = pin_cnf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
assert((dest != NULL)
|
||||
&& (NULL == gpio_port_unpack_addr(port))
|
||||
&& (pin < 32));
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
/* Searching "Schmitt" in
|
||||
* https://infocenter.nordicsemi.com/pdf/nRF52840_OPS_v0.5.pdf yields
|
||||
* no matches. Assuming Schmitt trigger cannot be disabled for the
|
||||
* nRF5x MCU.
|
||||
*/
|
||||
dest->schmitt_trigger = true;
|
||||
dest->state = GPIO_INPUT;
|
||||
|
||||
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
|
||||
uint32_t cnf = p->PIN_CNF[pin];
|
||||
|
||||
if (cnf & GPIO_PIN_CNF_DIR_Msk) {
|
||||
/* some kind of output, determine which: */
|
||||
switch ((cnf >> GPIO_PIN_CNF_DRIVE_Pos) & 0xf) {
|
||||
default:
|
||||
/* push-pull with mix of high drive and standard drive (e.g. high
|
||||
* drive for 0, standard drive for 1) is also possible
|
||||
* hardware-wise, but not supported via the API. Anyways, if someone
|
||||
* bypassed the API to set this, get at least the closest match to
|
||||
* the configuration.
|
||||
*/
|
||||
case GPIO_PIN_CNF_DRIVE_S0S1:
|
||||
/* standard drive 0, standard drive 1
|
||||
* --> push pull with weak drive */
|
||||
dest->state = GPIO_OUTPUT_PUSH_PULL;
|
||||
dest->drive_strength = GPIO_DRIVE_WEAK;
|
||||
break;
|
||||
case GPIO_PIN_CNF_DRIVE_H0H1:
|
||||
/* high drive 0, high drive 1
|
||||
* --> push pull with high drive */
|
||||
dest->state = GPIO_OUTPUT_PUSH_PULL;
|
||||
dest->drive_strength = GPIO_DRIVE_STRONG;
|
||||
break;
|
||||
case GPIO_PIN_CNF_DRIVE_S0D1:
|
||||
/* standard drive 0, disconnect at 1
|
||||
* --> open drain with weak drive */
|
||||
dest->state = GPIO_OUTPUT_OPEN_DRAIN;
|
||||
dest->drive_strength = GPIO_DRIVE_WEAK;
|
||||
break;
|
||||
case GPIO_PIN_CNF_DRIVE_H0D1:
|
||||
/* high drive 0, disconnect at 1
|
||||
* --> open drain with strong drive */
|
||||
dest->state = GPIO_OUTPUT_OPEN_DRAIN;
|
||||
dest->drive_strength = GPIO_DRIVE_STRONG;
|
||||
break;
|
||||
case GPIO_PIN_CNF_DRIVE_D0S1:
|
||||
/* disconnect at 0, standard drive 1
|
||||
* --> open emitter with weak drive */
|
||||
dest->state = GPIO_OUTPUT_OPEN_SOURCE;
|
||||
dest->drive_strength = GPIO_DRIVE_WEAK;
|
||||
break;
|
||||
case GPIO_PIN_CNF_DRIVE_D0H1:
|
||||
/* disconnect at 0, high drive 1
|
||||
* --> open emitter with strong drive */
|
||||
dest->state = GPIO_OUTPUT_OPEN_SOURCE;
|
||||
dest->drive_strength = GPIO_DRIVE_STRONG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (cnf & GPIO_PIN_CNF_INPUT_Msk) {
|
||||
/* input buffer is disconnected and pin is not in output mode
|
||||
* --> GPIO pin is off
|
||||
*/
|
||||
dest->state = GPIO_DISCONNECT;
|
||||
}
|
||||
}
|
||||
|
||||
switch ((cnf & GPIO_PIN_CNF_PULL_Msk) >> GPIO_PIN_CNF_PULL_Pos) {
|
||||
case GPIO_PIN_CNF_PULL_Pullup:
|
||||
dest->pull = GPIO_PULL_UP;
|
||||
break;
|
||||
case GPIO_PIN_CNF_PULL_Pulldown:
|
||||
dest->pull = GPIO_PULL_DOWN;
|
||||
break;
|
||||
default:
|
||||
dest->pull = GPIO_FLOATING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dest->state == GPIO_INPUT) {
|
||||
dest->initial_value = (gpio_ll_read(port) >> pin) & 1UL;
|
||||
}
|
||||
else {
|
||||
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL;
|
||||
}
|
||||
}
|
221
cpu/nrf5x_common/periph/gpio_ll_irq.c
Normal file
221
cpu/nrf5x_common/periph/gpio_ll_irq.c
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jan Wagner <mail@jwagner.eu>
|
||||
* 2015-2016 Freie Universität Berlin
|
||||
* 2019 Inria
|
||||
* 2021 Otto-von-Guericke-Universität Magdeburg
|
||||
*
|
||||
* 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_nrf5x_common
|
||||
* @ingroup drivers_periph_gpio_ll_irq
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief IRQ implementation of the GPIO Low-Level API for the nRF5x MCU family
|
||||
*
|
||||
* @note This GPIO driver implementation supports only one pin to be
|
||||
* defined as external interrupt.
|
||||
*
|
||||
* @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>
|
||||
* @author Jan Wagner <mail@jwagner.eu>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "periph/gpio_ll.h"
|
||||
#include "periph/gpio_ll_irq.h"
|
||||
#include "periph_conf.h"
|
||||
#include "periph_cpu.h"
|
||||
|
||||
#ifdef NRF_GPIOTE0_S
|
||||
#define NRF_GPIOTE NRF_GPIOTE0_S
|
||||
#define GPIOTE_IRQn GPIOTE0_IRQn
|
||||
#endif
|
||||
|
||||
#if CPU_FAM_NRF51
|
||||
#define GPIOTE_CHAN_NUMOF (4U)
|
||||
#else
|
||||
#define GPIOTE_CHAN_NUMOF (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Place to store the interrupt context
|
||||
*/
|
||||
struct isr_ctx {
|
||||
gpio_ll_cb_t cb;
|
||||
void *arg;
|
||||
};
|
||||
static struct isr_ctx isr_ctx[GPIOTE_CHAN_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief get the GPIOTE channel used to monitor the given pin
|
||||
*
|
||||
* @return the GPIOTE channel monitoring the specified pin
|
||||
* @retval GPIOTE_CHAN_NUMOF no GPIOTE channel is monitoring the given pin
|
||||
*/
|
||||
static unsigned get_channel_of_pin(uint8_t port_num, uint8_t pin)
|
||||
{
|
||||
/* port_num unused for nrf51 */
|
||||
(void)port_num;
|
||||
for (unsigned i = 0; i < GPIOTE_CHAN_NUMOF; i++) {
|
||||
uint32_t conf = NRF_GPIOTE->CONFIG[i];
|
||||
uint32_t mode = (conf & GPIOTE_CONFIG_MODE_Msk) >> GPIOTE_CONFIG_MODE_Pos;
|
||||
if (mode == GPIOTE_CONFIG_MODE_Event) {
|
||||
uint8_t pinsel = (conf & GPIOTE_CONFIG_PSEL_Msk) >> GPIOTE_CONFIG_PSEL_Pos;
|
||||
#ifdef GPIOTE_CONFIG_PORT_Msk
|
||||
uint8_t portsel = (conf & GPIOTE_CONFIG_PORT_Msk) >> GPIOTE_CONFIG_PORT_Pos;
|
||||
#endif
|
||||
if ((pinsel == pin)
|
||||
#ifdef GPIOTE_CONFIG_PORT_Msk
|
||||
&& (portsel == port_num)
|
||||
#endif
|
||||
) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GPIOTE_CHAN_NUMOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief select a GPIOTE channel suitable for managing the irq for the given
|
||||
* pin
|
||||
*
|
||||
* @return if one channel is already used for the given pin, return that.
|
||||
* Otherwise return a free channel
|
||||
* @retval GPIOTE_CHAN_NUMOF all GPIOTE channels occupied by pins different
|
||||
* to the selected one
|
||||
*/
|
||||
static unsigned get_channel_for_pin(uint8_t port_num, uint8_t pin)
|
||||
{
|
||||
unsigned result = get_channel_of_pin(port_num, pin);
|
||||
if (result != GPIOTE_CHAN_NUMOF) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* no channel devoted to the pin yet, return first free channel instead */
|
||||
for (unsigned i = 0; i < GPIOTE_CHAN_NUMOF; i++) {
|
||||
uint32_t conf = NRF_GPIOTE->CONFIG[i];
|
||||
uint32_t mode = (conf & GPIOTE_CONFIG_MODE_Msk) >> GPIOTE_CONFIG_MODE_Pos;
|
||||
if (mode != GPIOTE_CONFIG_MODE_Event) {
|
||||
/* free channel found */
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return GPIOTE_CHAN_NUMOF;
|
||||
}
|
||||
|
||||
int gpio_ll_irq(gpio_port_t port, uint8_t pin,
|
||||
gpio_irq_trig_t trig, gpio_ll_cb_t cb, void *arg)
|
||||
{
|
||||
/* param port is not used on nRF5x variants with only one GPIO port */
|
||||
(void)port;
|
||||
uint8_t port_num = GPIO_PORT_NUM(port);
|
||||
uint8_t channel = get_channel_for_pin(port_num, pin);
|
||||
assert((trig != GPIO_TRIGGER_LEVEL_HIGH) && (trig != GPIO_TRIGGER_LEVEL_LOW));
|
||||
|
||||
if (channel == GPIOTE_CHAN_NUMOF) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* mask IRQ */
|
||||
NRF_GPIOTE->INTENCLR = GPIOTE_INTENSET_IN0_Msk << channel;
|
||||
|
||||
isr_ctx[channel].cb = cb;
|
||||
isr_ctx[channel].arg = arg;
|
||||
|
||||
/* use event mode */
|
||||
uint32_t config = GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos;
|
||||
/* set pin and (nRF52 only) port */
|
||||
config |= (uint32_t)pin << GPIOTE_CONFIG_PSEL_Pos;
|
||||
#ifdef GPIOTE_CONFIG_PORT_Pos
|
||||
config |= (uint32_t)port_num << GPIOTE_CONFIG_PORT_Pos;
|
||||
#endif
|
||||
/* set trigger */
|
||||
config |= (uint32_t)trig & GPIOTE_CONFIG_POLARITY_Msk;
|
||||
/* apply config */
|
||||
NRF_GPIOTE->CONFIG[channel] = config;
|
||||
/* enable IRQ */
|
||||
NVIC_EnableIRQ(GPIOTE_IRQn);
|
||||
/* clear any spurious IRQ still present */
|
||||
NRF_GPIOTE->EVENTS_IN[channel] = 0;
|
||||
/* unmask IRQ */
|
||||
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Msk << channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
/* param port is not used on nRF5x variants with only one GPIO port */
|
||||
(void)port;
|
||||
uint8_t port_num = GPIO_PORT_NUM(port);
|
||||
unsigned channel = get_channel_of_pin(port_num, pin);
|
||||
assert(channel != GPIOTE_CHAN_NUMOF);
|
||||
if (channel != GPIOTE_CHAN_NUMOF) {
|
||||
NRF_GPIOTE->INTENCLR = GPIOTE_INTENCLR_IN0_Msk << channel;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
/* param port is not used on nRF5x variants with only one GPIO port */
|
||||
(void)port;
|
||||
uint8_t port_num = GPIO_PORT_NUM(port);
|
||||
unsigned channel = get_channel_of_pin(port_num, pin);
|
||||
assert(channel != GPIOTE_CHAN_NUMOF);
|
||||
if (channel != GPIOTE_CHAN_NUMOF) {
|
||||
NRF_GPIOTE->INTENSET = GPIOTE_INTENCLR_IN0_Msk << channel;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_ll_irq_unmask_and_clear(gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
/* param port is not used on nRF5x variants with only one GPIO port */
|
||||
(void)port;
|
||||
uint8_t port_num = GPIO_PORT_NUM(port);
|
||||
unsigned channel = get_channel_of_pin(port_num, pin);
|
||||
assert(channel != GPIOTE_CHAN_NUMOF);
|
||||
if (channel != GPIOTE_CHAN_NUMOF) {
|
||||
NRF_GPIOTE->EVENTS_IN[channel] = 0;
|
||||
NRF_GPIOTE->INTENSET = GPIOTE_INTENCLR_IN0_Msk << channel;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_ll_irq_off(gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
/* param port is not used on nRF5x variants with only one GPIO port */
|
||||
(void)port;
|
||||
uint8_t port_num = GPIO_PORT_NUM(port);
|
||||
unsigned channel = get_channel_of_pin(port_num, pin);
|
||||
assert(channel != GPIOTE_CHAN_NUMOF);
|
||||
if (channel != GPIOTE_CHAN_NUMOF) {
|
||||
NRF_GPIOTE->INTENSET = GPIOTE_INTENCLR_IN0_Msk << channel;
|
||||
NRF_GPIOTE->CONFIG[channel] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void isr_gpiote(void)
|
||||
{
|
||||
for (unsigned int i = 0; i < GPIOTE_CHAN_NUMOF; ++i) {
|
||||
if (NRF_GPIOTE->EVENTS_IN[i] == 1) {
|
||||
NRF_GPIOTE->EVENTS_IN[i] = 0;
|
||||
isr_ctx[i].cb(isr_ctx[i].arg);
|
||||
}
|
||||
}
|
||||
cortexm_isr_end();
|
||||
}
|
@ -13,6 +13,9 @@ config CPU_FAM_NRF9160
|
||||
select HAS_PERIPH_FLASHPAGE_PAGEWISE
|
||||
select HAS_PERIPH_GPIO
|
||||
select HAS_PERIPH_GPIO_IRQ
|
||||
select HAS_PERIPH_GPIO_LL
|
||||
select HAS_PERIPH_GPIO_LL_IRQ
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_UNMASK
|
||||
select HAS_PERIPH_TIMER_PERIODIC
|
||||
select HAS_PERIPH_UART_MODECFG
|
||||
select HAS_PERIPH_SPI_GPIO_MODE
|
||||
|
Loading…
Reference in New Issue
Block a user