From f0586dbf8f40c7b60771543a229221aff4f2c319 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 3 Sep 2021 13:04:53 +0200 Subject: [PATCH] cpu/nrf5x_common: implement periph/gpio_ll{,_irq} Co-authored-by: Gunar Schorcht --- cpu/nrf5x_common/Kconfig | 3 + cpu/nrf5x_common/Makefile.features | 1 + cpu/nrf5x_common/include/gpio_ll_arch.h | 157 +++++++++++++ cpu/nrf5x_common/include/periph_cpu_common.h | 44 ++++ cpu/nrf5x_common/periph/gpio_ll.c | 199 +++++++++++++++++ cpu/nrf5x_common/periph/gpio_ll_irq.c | 221 +++++++++++++++++++ cpu/nrf9160/Kconfig | 3 + 7 files changed, 628 insertions(+) create mode 100644 cpu/nrf5x_common/include/gpio_ll_arch.h create mode 100644 cpu/nrf5x_common/periph/gpio_ll.c create mode 100644 cpu/nrf5x_common/periph/gpio_ll_irq.c diff --git a/cpu/nrf5x_common/Kconfig b/cpu/nrf5x_common/Kconfig index e4897d3fc2..4a9ddba138 100644 --- a/cpu/nrf5x_common/Kconfig +++ b/cpu/nrf5x_common/Kconfig @@ -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 diff --git a/cpu/nrf5x_common/Makefile.features b/cpu/nrf5x_common/Makefile.features index 1ba09ebd57..d3a0b1102a 100644 --- a/cpu/nrf5x_common/Makefile.features +++ b/cpu/nrf5x_common/Makefile.features @@ -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 diff --git a/cpu/nrf5x_common/include/gpio_ll_arch.h b/cpu/nrf5x_common/include/gpio_ll_arch.h new file mode 100644 index 0000000000..67a44d56ca --- /dev/null +++ b/cpu/nrf5x_common/include/gpio_ll_arch.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2015 Jan Wagner + * 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 + * @author Timo Ziegler + * @author Hauke Petersen + * @author Jan Wagner + * @author Alexandre Abadie + */ + +#ifndef GPIO_LL_ARCH_H +#define GPIO_LL_ARCH_H + +#include + +#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 */ +/** @} */ diff --git a/cpu/nrf5x_common/include/periph_cpu_common.h b/cpu/nrf5x_common/include/periph_cpu_common.h index a8d90229b2..7e43a7dd09 100644 --- a/cpu/nrf5x_common/include/periph_cpu_common.h +++ b/cpu/nrf5x_common/include/periph_cpu_common.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... */ diff --git a/cpu/nrf5x_common/periph/gpio_ll.c b/cpu/nrf5x_common/periph/gpio_ll.c new file mode 100644 index 0000000000..c03e19437c --- /dev/null +++ b/cpu/nrf5x_common/periph/gpio_ll.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2015 Jan Wagner + * 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 + * @author Timo Ziegler + * @author Hauke Petersen + * @author Jan Wagner + * @author Alexandre Abadie + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include +#include + +#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; + } +} diff --git a/cpu/nrf5x_common/periph/gpio_ll_irq.c b/cpu/nrf5x_common/periph/gpio_ll_irq.c new file mode 100644 index 0000000000..55a48a6fbb --- /dev/null +++ b/cpu/nrf5x_common/periph/gpio_ll_irq.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2015 Jan Wagner + * 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 + * @author Timo Ziegler + * @author Hauke Petersen + * @author Jan Wagner + * @author Alexandre Abadie + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include + +#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(); +} diff --git a/cpu/nrf9160/Kconfig b/cpu/nrf9160/Kconfig index efc36bb285..e55b2c0dc6 100644 --- a/cpu/nrf9160/Kconfig +++ b/cpu/nrf9160/Kconfig @@ -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