1
0
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:
benpicco 2022-04-26 11:27:02 +02:00 committed by GitHub
commit b6b1468240
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 628 additions and 0 deletions

View File

@ -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

View File

@ -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

View 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 */
/** @} */

View File

@ -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...
*/

View 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;
}
}

View 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();
}

View File

@ -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