1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

Merge pull request #10828 from aabadie/pr/cpu/nrf5x_gpiote_multi_channel

cpu/nrf5x: handle multiple exti pins in gpio driver
This commit is contained in:
Leandro Lanzieri 2019-01-22 17:05:12 +01:00 committed by GitHub
commit 5d1f2e24c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,6 +1,7 @@
/*
* 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
@ -22,6 +23,7 @@
* @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>
*
* @}
*/
@ -35,10 +37,30 @@
#define PIN_MASK (0x1f)
#ifdef MODULE_PERIPH_GPIO_IRQ
#if CPU_FAM_NRF51
#define GPIOTE_CHAN_NUMOF (4U)
#else
#define GPIOTE_CHAN_NUMOF (8U)
#endif
/**
* @brief Index of next interrupt in GPIOTE channel list.
*
* The index is incremented at the end of each call to gpio_init_int.
* The index cannot be greater or equal than GPIOTE_CHAN_NUMOF.
*/
static uint8_t _gpiote_next_index = 0;
/**
* @brief Array containing a mapping between GPIOTE channel and pin
*/
static gpio_t _exti_pins[GPIOTE_CHAN_NUMOF];
/**
* @brief Place to store the interrupt context
*/
static gpio_isr_ctx_t exti_chan;
static gpio_isr_ctx_t exti_chan[GPIOTE_CHAN_NUMOF];
#endif /* MODULE_PERIPH_GPIO_IRQ */
/**
@ -125,44 +147,76 @@ void gpio_write(gpio_t pin, int value)
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
/* disable external interrupt in case one is active */
NRF_GPIOTE->INTENSET &= ~(GPIOTE_INTENSET_IN0_Msk);
uint8_t _pin_index = 0xff;
/* Looking for already known pin in exti table */
for (unsigned int i = 0; i < _gpiote_next_index; i++) {
if (_exti_pins[i] == pin) {
_pin_index = i;
break;
}
}
/* New pin */
if (_pin_index == 0xff) {
assert(_gpiote_next_index < GPIOTE_CHAN_NUMOF);
_pin_index = _gpiote_next_index;
/* associate the current pin with channel index */
_exti_pins[_pin_index] = pin;
/* increase next index for next pin initialization */
_gpiote_next_index++;
}
/* save callback */
exti_chan.cb = cb;
exti_chan.arg = arg;
exti_chan[_pin_index].cb = cb;
exti_chan[_pin_index].arg = arg;
/* configure pin as input */
gpio_init(pin, mode);
/* set interrupt priority and enable global GPIOTE interrupt */
NVIC_EnableIRQ(GPIOTE_IRQn);
/* configure the GPIOTE channel: set even mode, pin and active flank */
NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_MODE_Event |
NRF_GPIOTE->CONFIG[_pin_index] = (GPIOTE_CONFIG_MODE_Event |
(pin_num(pin) << GPIOTE_CONFIG_PSEL_Pos) |
#ifdef CPU_MODEL_NRF52840XXAA
((pin & PORT_BIT) << 8) |
#endif
(flank << GPIOTE_CONFIG_POLARITY_Pos));
/* enable external interrupt */
NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN0_Msk;
NRF_GPIOTE->INTENSET |= (GPIOTE_INTENSET_IN0_Msk << _pin_index);
return 0;
}
void gpio_irq_enable(gpio_t pin)
{
(void) pin;
NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN0_Msk;
for (unsigned int i = 0; i < _gpiote_next_index; i++) {
if (_exti_pins[i] == pin) {
NRF_GPIOTE->CONFIG[i] |= GPIOTE_CONFIG_MODE_Event;
NRF_GPIOTE->INTENSET |= (GPIOTE_INTENSET_IN0_Msk << i);
break;
}
}
}
void gpio_irq_disable(gpio_t pin)
{
(void) pin;
NRF_GPIOTE->INTENCLR |= GPIOTE_INTENSET_IN0_Msk;
for (unsigned int i = 0; i < _gpiote_next_index; i++) {
if (_exti_pins[i] == pin) {
/* Clear mode configuration: 00 = Disabled */
NRF_GPIOTE->CONFIG[i] &= ~(GPIOTE_CONFIG_MODE_Msk);
NRF_GPIOTE->INTENCLR = (GPIOTE_INTENCLR_IN0_Msk << i);
break;
}
}
}
void isr_gpiote(void)
{
if (NRF_GPIOTE->EVENTS_IN[0] == 1) {
NRF_GPIOTE->EVENTS_IN[0] = 0;
exti_chan.cb(exti_chan.arg);
for (unsigned int i = 0; i < _gpiote_next_index; ++i) {
if (NRF_GPIOTE->EVENTS_IN[i] == 1) {
NRF_GPIOTE->EVENTS_IN[i] = 0;
exti_chan[i].cb(exti_chan[i].arg);
break;
}
}
cortexm_isr_end();
}