nrf52 GPIO/GPIOTE: better expose pin interrupt capability
This change improves upon current support for pin interrupts. Before, a pin interrupt was handled (with nrf52_gpiote_setevent) using one of the eight available GPIOTE channels. Moreover, it didn't event let the user specify which channel to use (simply tried to get a free one). Also, it was buggy since it did not consider unsetting the callback. Besides GPIOTE channels, there is another way to deal with pin interrupts. The GPIO peripheral is capable of generating a PORT event (for the whole GPIO port) depending on the pin SENSE configuration (HIGH or LOW, or NONE) and GPIO DETECTMODE register (latching or non-latching). This change then renames nrf52_gpiote_setevent into nrf52_gpiote_set_ch_event, maintaining functionality of original function, but now allows specifying channel (and correctly handles unsetting the callback). Then, a new nrf52_gpiote_set_pin_event is added, which allows to set a callback for a given pin. During initialization, interrupt for the PORT event is enabled and handled in such way that for each pin whose corresponding bit in LATCH register (indicates the result of pin SENSEing) the callback for this pin will be invoked. This mechanism means that every pin can get an ISR. It also avoids using GPIOTE channels for this purpose which carry higher current consumption. This new per-pin callback mechanism has some added memory requirement so it can be disabled and its default is dependant on DEFAULT_SMALL. When disabled, a callback for the PORT event can be set directly with nrf52_gpiote_set_port_event There was only one use of nrf52_gpio_setevent() which was migrated into nrf52_gpio_set_ch_event() passing channel zero.
This commit is contained in:
parent
723698c787
commit
f55a2879ca
@ -386,6 +386,24 @@ config NRF52_PROGMEM
|
||||
|
||||
menu "GPIO Interrupt Configuration"
|
||||
|
||||
config NRF52_PER_PIN_INTERRUPTS
|
||||
bool "Per-pin interrupt callbacks"
|
||||
default n if DEFAULT_SMALL
|
||||
default y if !DEFAULT_SMALL
|
||||
depends on NRF52_GPIOTE
|
||||
---help---
|
||||
The GPIOTE peripheral supports a limited number of channels which can
|
||||
be set to EVENT mode and thus generate interrupts on pin state changes.
|
||||
Another mechanism offered by the GPIO/GPIOTE peripherals is the PORT
|
||||
event. This event is generated from a signal shared by all pins in
|
||||
the GPIO port.
|
||||
|
||||
This option enables the ability to set per-pin callbacks that will
|
||||
be invoked from the main GPIOTE ISR when a PORT event is generated.
|
||||
As this involves extra storage to store each callback, this option can
|
||||
be disabled to save space. In such case, it is possible to set a callback
|
||||
for the whole PORT event directly.
|
||||
|
||||
endmenu # GPIO Interrupt Configuration
|
||||
|
||||
menu "PWM configuration"
|
||||
|
@ -57,6 +57,8 @@
|
||||
# define NRF52_GPIO_NPORTS 1
|
||||
#endif
|
||||
|
||||
#define NRF52_GPIO_NPINS 32
|
||||
|
||||
/* Register offsets *****************************************************************/
|
||||
|
||||
#define NRF52_GPIO_OUT_OFFSET 0x0504 /* Write GPIO port */
|
||||
@ -95,6 +97,9 @@
|
||||
|
||||
/* Register bit definitions *********************************************************/
|
||||
|
||||
#define GPIO_DETECTMODE_DEFAULT (0)
|
||||
#define GPIO_DETECTMODE_LDETECT (1)
|
||||
|
||||
#define GPIO_CNF_DIR (1 << 0) /* Bit 0: Pin direction */
|
||||
#define GPIO_CNF_INPUT (1 << 1) /* Bit 1: Input buffer disconnect */
|
||||
#define GPIO_CNF_PULL_SHIFT (2)
|
||||
@ -102,5 +107,20 @@
|
||||
# define GPIO_CNF_PULL_DISABLED (0 << GPIO_CNF_PULL_SHIFT)
|
||||
# define GPIO_CNF_PULL_DOWN (1 << GPIO_CNF_PULL_SHIFT)
|
||||
# define GPIO_CNF_PULL_UP (3 << GPIO_CNF_PULL_SHIFT)
|
||||
#define GPIO_CNF_DRIVE_SHIFT (8)
|
||||
#define GPIO_CNF_DRIVE_MASK (0x7 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_S0S1 (0 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_H0S1 (1 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_S0H1 (2 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_H0H1 (3 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_D0S1 (4 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_D0H1 (5 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_S0D1 (6 << GPIO_CNF_DRIVE_SHIFT)
|
||||
# define GPIO_CNF_DRIVE_H0D1 (7 << GPIO_CNF_DRIVE_SHIFT)
|
||||
#define GPIO_CNF_SENSE_SHIFT (16)
|
||||
#define GPIO_CNF_SENSE_MASK (0x3 << GPIO_CNF_SENSE_SHIFT)
|
||||
# define GPIO_CNF_SENSE_DISABLED (0 << GPIO_CNF_SENSE_SHIFT)
|
||||
# define GPIO_CNF_SENSE_HIGH (2 << GPIO_CNF_SENSE_SHIFT)
|
||||
# define GPIO_CNF_SENSE_LOW (3 << GPIO_CNF_SENSE_SHIFT)
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_GPIO_H */
|
||||
|
@ -67,7 +67,8 @@
|
||||
#define GPIOTE_INT_IN_MASK (0xff << GPIOTE_INT_IN_SHIFT)
|
||||
# define GPIOTE_INT_IN(i) ((1 << (i + GPIOTE_INT_IN_SHIFT)) & GPIOTE_INT_IN_MASK)
|
||||
|
||||
#define GPIOTE_INT_PORT 31 /* Bit 31: Enable interrupt for event PORT */
|
||||
#define GPIOTE_INT_PORT_SHIFT 31 /* Bit 31: Enable interrupt for event PORT */
|
||||
#define GPIOTE_INT_PORT (1 << GPIOTE_INT_PORT_SHIFT)
|
||||
|
||||
/* CONFIG Register */
|
||||
|
||||
|
@ -144,22 +144,54 @@ static inline void nrf52_gpio_mode(nrf52_pinset_t cfgset,
|
||||
mode = cfgset & GPIO_MODE_MASK;
|
||||
|
||||
regval = getreg32(offset);
|
||||
regval &= GPIO_CNF_PULL_MASK;
|
||||
regval &= ~GPIO_CNF_PULL_MASK;
|
||||
|
||||
if (mode == GPIO_PULLUP)
|
||||
{
|
||||
regval &= GPIO_CNF_PULL_MASK;
|
||||
regval |= GPIO_CNF_PULL_UP;
|
||||
}
|
||||
else if (mode == GPIO_PULLDOWN)
|
||||
{
|
||||
regval &= GPIO_CNF_PULL_MASK;
|
||||
regval |= GPIO_CNF_PULL_DOWN;
|
||||
}
|
||||
|
||||
putreg32(regval, offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpio_sense
|
||||
*
|
||||
* Description:
|
||||
* Set SENSE configuration for an input pin
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void nrf52_gpio_sense(nrf52_pinset_t cfgset,
|
||||
unsigned int port, unsigned int pin)
|
||||
{
|
||||
uint32_t mode;
|
||||
uint32_t regval;
|
||||
uint32_t offset;
|
||||
|
||||
mode = cfgset & GPIO_SENSE_MASK;
|
||||
|
||||
offset = nrf52_gpio_regget(port, NRF52_GPIO_PIN_CNF_OFFSET(pin));
|
||||
regval = getreg32(offset);
|
||||
|
||||
regval &= ~GPIO_CNF_SENSE_MASK;
|
||||
|
||||
if (mode == GPIO_SENSE_HIGH)
|
||||
{
|
||||
regval |= GPIO_CNF_SENSE_HIGH;
|
||||
}
|
||||
else
|
||||
{
|
||||
regval |= GPIO_CNF_SENSE_LOW;
|
||||
}
|
||||
|
||||
putreg32(regval, offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -204,7 +236,8 @@ int nrf52_gpio_config(nrf52_pinset_t cfgset)
|
||||
switch (cfgset & GPIO_FUNC_MASK)
|
||||
{
|
||||
case GPIO_INPUT: /* GPIO input pin */
|
||||
break; /* Already configured */
|
||||
nrf52_gpio_sense(cfgset, port, pin);
|
||||
break;
|
||||
|
||||
case GPIO_OUTPUT: /* GPIO outpout pin */
|
||||
nrf52_gpio_output(cfgset, port, pin);
|
||||
@ -313,3 +346,20 @@ bool nrf52_gpio_read(nrf52_pinset_t pinset)
|
||||
|
||||
return (regval >> pin) & 1UL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpio_detectmode
|
||||
*
|
||||
* Description:
|
||||
* Set DETECTMODE to either default or latched
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nrf52_gpio_detectmode(int port, enum nrf52_gpio_detectmode_e mode)
|
||||
{
|
||||
uint32_t offset = nrf52_gpio_regget(port, NRF52_GPIO_DETECTMODE_OFFSET);
|
||||
|
||||
putreg32(mode == NRF52_GPIO_DETECTMODE_DETECT ?
|
||||
GPIO_DETECTMODE_DEFAULT :
|
||||
GPIO_DETECTMODE_LDETECT, offset);
|
||||
}
|
||||
|
@ -187,6 +187,12 @@
|
||||
|
||||
typedef uint32_t nrf52_pinset_t;
|
||||
|
||||
enum nrf52_gpio_detectmode_e
|
||||
{
|
||||
NRF52_GPIO_DETECTMODE_DETECT,
|
||||
NRF52_GPIO_DETECTMODE_LDETECT,
|
||||
};
|
||||
|
||||
/************************************************************************************
|
||||
* Public Data
|
||||
************************************************************************************/
|
||||
|
@ -61,9 +61,21 @@ struct nrf52_gpiote_callback_s
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Interrupt handlers attached to each GPIOTE */
|
||||
/* Callbacks attached to each GPIOTE channel */
|
||||
|
||||
static struct nrf52_gpiote_callback_s g_gpiote_callbacks[GPIOTE_CHANNELS];
|
||||
static struct nrf52_gpiote_callback_s g_gpiote_ch_callbacks[GPIOTE_CHANNELS];
|
||||
|
||||
#ifdef CONFIG_NRF52_PER_PIN_INTERRUPTS
|
||||
/* Callbacks attached to each GPIO pin */
|
||||
|
||||
static struct nrf52_gpiote_callback_s
|
||||
g_gpiote_pin_callbacks[NRF52_GPIO_NPORTS][NRF52_GPIO_NPINS];
|
||||
#else
|
||||
/* Callback for the PORT event */
|
||||
|
||||
static struct nrf52_gpiote_callback_s
|
||||
g_gpiote_port_callback[NRF52_GPIO_NPORTS];
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -108,6 +120,9 @@ static int nrf52_gpiote_isr(int irq, FAR void *context, FAR void *arg)
|
||||
uint32_t regval = 0;
|
||||
int ret = OK;
|
||||
int i = 0;
|
||||
#ifdef CONFIG_NRF52_PER_PIN_INTERRUPTS
|
||||
int j = 0;
|
||||
#endif
|
||||
|
||||
/* Scan all GPIOTE channels */
|
||||
|
||||
@ -115,7 +130,7 @@ static int nrf52_gpiote_isr(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
/* Only if callback is registered */
|
||||
|
||||
if (g_gpiote_callbacks[i].callback != NULL)
|
||||
if (g_gpiote_ch_callbacks[i].callback != NULL)
|
||||
{
|
||||
/* Get input event register */
|
||||
|
||||
@ -124,8 +139,8 @@ static int nrf52_gpiote_isr(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
/* Execute callback */
|
||||
|
||||
xcpt_t callback = g_gpiote_callbacks[i].callback;
|
||||
FAR void *cbarg = g_gpiote_callbacks[i].arg;
|
||||
xcpt_t callback = g_gpiote_ch_callbacks[i].callback;
|
||||
FAR void *cbarg = g_gpiote_ch_callbacks[i].arg;
|
||||
ret = callback(irq, context, cbarg);
|
||||
|
||||
/* Clear event */
|
||||
@ -135,6 +150,76 @@ static int nrf52_gpiote_isr(int irq, FAR void *context, FAR void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for PORT event */
|
||||
|
||||
regval = nrf52_gpiote_getreg(NRF52_GPIOTE_EVENTS_PORT_OFFSET);
|
||||
if (regval)
|
||||
{
|
||||
uint32_t addr = 0;
|
||||
|
||||
/* Ack PORT event */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_EVENTS_PORT_OFFSET, 0);
|
||||
|
||||
/* For each GPIO port, get LATCH register */
|
||||
|
||||
for (i = 0; i < NRF52_GPIO_NPORTS; i++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
addr = NRF52_GPIO_P0_BASE + NRF52_GPIO_LATCH_OFFSET;
|
||||
break;
|
||||
#ifdef CONFIG_NRF52_HAVE_PORT1
|
||||
case 1:
|
||||
addr = NRF52_GPIO_P1_BASE + NRF52_GPIO_LATCH_OFFSET;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Retrieve LATCH register */
|
||||
|
||||
regval = getreg32(addr);
|
||||
|
||||
/* Clear LATCH register (this may set PORT again) */
|
||||
|
||||
putreg32(0xffffffff, addr);
|
||||
|
||||
#ifdef CONFIG_NRF52_PER_PIN_INTERRUPTS
|
||||
/* Check for pins with DETECT bit high in LATCH register
|
||||
* and dispatch callback if set
|
||||
*/
|
||||
|
||||
for (j = 0; j < NRF52_GPIO_NPINS && regval; j++)
|
||||
{
|
||||
if (regval & (1 << j) && g_gpiote_pin_callbacks[i][j].callback)
|
||||
{
|
||||
/* Run callback */
|
||||
|
||||
xcpt_t callback = g_gpiote_pin_callbacks[i][j].callback;
|
||||
FAR void *cbarg = g_gpiote_pin_callbacks[i][j].arg;
|
||||
|
||||
ret = callback(irq, context, cbarg);
|
||||
|
||||
/* Mark bit is as "visited", we can stop looping sooner
|
||||
* this way
|
||||
*/
|
||||
|
||||
regval &= ~(1 << j);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (g_gpiote_port_callback[i].callback)
|
||||
{
|
||||
xcpt_t callback = g_gpiote_port_callback[i].callback;
|
||||
FAR void *cbarg = g_gpiote_port_callback[i].arg;
|
||||
|
||||
ret = callback(irq, context, cbarg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -142,11 +227,126 @@ static int nrf52_gpiote_isr(int irq, FAR void *context, FAR void *arg)
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NRF52_PER_PIN_INTERRUPTS
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiosetevent
|
||||
* Name: nrf52_gpiote_set_pin_event
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears GPIO based event and interrupt triggers.
|
||||
* Sets/clears a handler for a given pin for the GPIO PORT event. This
|
||||
* will mean edge-sensitive or level-sensitive according to GPIO detect
|
||||
* mode configuration for the port (see nrf52_gpio_detectmode()). Pin
|
||||
* will be sensitive to high/low according to GPIO_SENSE_LOW/HIGH
|
||||
* (set via nrf52_gpio_config()).
|
||||
*
|
||||
* The passed handler will be invoked from the main ISR for the PORT
|
||||
* event and will take care of clearing the LATCH register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: GPIO pin configuration
|
||||
* - func: When non-NULL, generate interrupt
|
||||
* - arg: Argument passed to the interrupt callback
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure indicating the
|
||||
* nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nrf52_gpiote_set_pin_event(uint32_t pinset, xcpt_t func, FAR void *arg)
|
||||
{
|
||||
int pin = 0;
|
||||
int port = 0;
|
||||
irqstate_t flags;
|
||||
|
||||
pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
|
||||
#ifdef CONFIG_NRF52_HAVE_PORT1
|
||||
port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
#endif
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
g_gpiote_pin_callbacks[port][pin].callback = func;
|
||||
g_gpiote_pin_callbacks[port][pin].arg = arg;
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
#else
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiote_set_port_event
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears the handler for the GPIO PORT event.
|
||||
*
|
||||
* The passed handler will be invoked from the main ISR for the PORT
|
||||
* event and will take care of clearing the LATCH register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: GPIO port will be extracted from this parameter
|
||||
* - func: When non-NULL, generate interrupt
|
||||
* - arg: Argument passed to the interrupt callback
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure indicating the
|
||||
* nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nrf52_gpiote_set_port_event(uint32_t pinset, xcpt_t func, FAR void *arg)
|
||||
{
|
||||
int port = 0;
|
||||
irqstate_t flags;
|
||||
|
||||
#ifdef CONFIG_NRF52_HAVE_PORT1
|
||||
port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
#endif
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
g_gpiote_port_callback[port].callback = func;
|
||||
g_gpiote_port_callback[port].arg = arg;
|
||||
|
||||
if (func)
|
||||
{
|
||||
/* Enable the ISR */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_INTENSET_OFFSET, GPIOTE_INT_PORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NRF52_GPIO_NPORTS > 1
|
||||
/* Check if we can disable the ISR */
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NRF52_GPIO_NPORTS; i++)
|
||||
{
|
||||
if (g_gpiote_port_callback[port].callback)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == NRF52_GPIO_NPORTS)
|
||||
{
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_INTENCLR_OFFSET, GPIOTE_INT_PORT);
|
||||
}
|
||||
#else
|
||||
/* Disable the ISR */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_INTENCLR_OFFSET, GPIOTE_INT_PORT);
|
||||
#endif
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiote_set_ch_event
|
||||
*
|
||||
* Description:
|
||||
* Configures a GPIOTE channel in EVENT mode, assigns it to a given pin
|
||||
* and sets a handler for the corresponding channel events.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: GPIO pin configuration
|
||||
@ -162,122 +362,90 @@ static int nrf52_gpiote_isr(int irq, FAR void *context, FAR void *arg)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nrf52_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
|
||||
bool event, xcpt_t func, FAR void *arg)
|
||||
void nrf52_gpiote_set_ch_event(uint32_t pinset, int channel,
|
||||
bool risingedge, bool fallingedge,
|
||||
xcpt_t func, FAR void *arg)
|
||||
{
|
||||
int ret = OK;
|
||||
int i = 0;
|
||||
int pin = 0;
|
||||
#ifdef CONFIG_NRF52_HAVE_PORT1
|
||||
int port = 0;
|
||||
#endif
|
||||
uint32_t regval = 0;
|
||||
bool found = false;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Find available GPIOTE channel */
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
for (i = 0; i < GPIOTE_CHANNELS; i += 1)
|
||||
{
|
||||
if (g_gpiote_callbacks[i].callback == NULL)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
/* Return error if there is no free channel */
|
||||
|
||||
if (found == false)
|
||||
{
|
||||
ret = -ENODEV;
|
||||
goto errout;
|
||||
}
|
||||
DEBUGASSERT(channel < GPIOTE_CHANNELS);
|
||||
|
||||
/* NOTE: GPIOTE module has priority over GPIO module
|
||||
* so GPIO configuration will be ignored
|
||||
*/
|
||||
|
||||
/* Select GPIOTE pin */
|
||||
flags = enter_critical_section();
|
||||
|
||||
pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
|
||||
regval = (pin << GPIOTE_CONFIG_PSEL_SHIFT);
|
||||
if (func)
|
||||
{
|
||||
/* Select EVENT mode */
|
||||
|
||||
regval |= GPIOTE_CONFIG_MODE_EV;
|
||||
|
||||
/* Select GPIOTE pin */
|
||||
|
||||
pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
|
||||
regval |= (pin << GPIOTE_CONFIG_PSEL_SHIFT);
|
||||
|
||||
#ifdef CONFIG_NRF52_HAVE_PORT1
|
||||
port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
regval |= (port << GPIOTE_CONFIG_PORT_SHIFT);
|
||||
port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
regval |= (port << GPIOTE_CONFIG_PORT_SHIFT);
|
||||
#endif
|
||||
|
||||
/* Select EVENT mode */
|
||||
/* Select polarity */
|
||||
|
||||
if (event || func)
|
||||
{
|
||||
regval &= ~GPIOTE_CONFIG_MODE_MASK;
|
||||
regval |= GPIOTE_CONFIG_MODE_EV;
|
||||
}
|
||||
if (risingedge == true && fallingedge == true)
|
||||
{
|
||||
regval |= GPIOTE_CONFIG_POL_TG;
|
||||
}
|
||||
else if (risingedge == true)
|
||||
{
|
||||
regval |= GPIOTE_CONFIG_POL_LTH;
|
||||
}
|
||||
else if (fallingedge == true)
|
||||
{
|
||||
regval |= GPIOTE_CONFIG_POL_HTL;
|
||||
}
|
||||
|
||||
/* Select polarity */
|
||||
/* Enable callback for channel */
|
||||
|
||||
if (risingedge == true && fallingedge == true)
|
||||
{
|
||||
regval |= GPIOTE_CONFIG_POL_TG;
|
||||
g_gpiote_ch_callbacks[channel].callback = func;
|
||||
g_gpiote_ch_callbacks[channel].arg = arg;
|
||||
|
||||
/* Enable interrupt for given event */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_INTENSET_OFFSET,
|
||||
GPIOTE_INT_IN(channel));
|
||||
}
|
||||
else if (risingedge == true)
|
||||
else
|
||||
{
|
||||
regval |= GPIOTE_CONFIG_POL_LTH;
|
||||
}
|
||||
else if (fallingedge == true)
|
||||
{
|
||||
regval |= GPIOTE_CONFIG_POL_HTL;
|
||||
/* Leave register as zero (disabled mode) */
|
||||
|
||||
/* Disable interrupt for given event */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_INTENCLR_OFFSET,
|
||||
GPIOTE_INT_IN(channel));
|
||||
|
||||
/* Remove callback configuration */
|
||||
|
||||
g_gpiote_ch_callbacks[channel].callback = NULL;
|
||||
g_gpiote_ch_callbacks[channel].arg = NULL;
|
||||
}
|
||||
|
||||
/* Write CONFIG register */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_CONFIG_OFFSET(i), regval);
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_CONFIG_OFFSET(channel), regval);
|
||||
|
||||
/* Enable interrupt for given event */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_INTENSET_OFFSET, GPIOTE_INT_IN(i));
|
||||
|
||||
/* Connect callback */
|
||||
|
||||
g_gpiote_callbacks[i].callback = func;
|
||||
g_gpiote_callbacks[i].arg = arg;
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiote_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize GPIOTE
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nrf52_gpiote_init(void)
|
||||
{
|
||||
/* Reset GPIOTE data */
|
||||
|
||||
memset(&g_gpiote_callbacks,
|
||||
0,
|
||||
sizeof(struct nrf52_gpiote_callback_s)*GPIOTE_CHANNELS);
|
||||
|
||||
/* Attach GPIOTE interrupt handler */
|
||||
|
||||
irq_attach(NRF52_IRQ_GPIOTE, nrf52_gpiote_isr, NULL);
|
||||
up_enable_irq(NRF52_IRQ_GPIOTE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiotaskset
|
||||
* Name: nrf52_gpio_set_task
|
||||
*
|
||||
* Description:
|
||||
* Configure GPIO in TASK mode (to be controlled via tasks).
|
||||
@ -299,8 +467,9 @@ int nrf52_gpiote_init(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nrf52_gpiotaskset(uint32_t pinset, int channel,
|
||||
bool output_high, enum nrf52_gpiote_outcfg_e outcfg)
|
||||
void nrf52_gpiote_set_task(uint32_t pinset, int channel,
|
||||
bool output_high,
|
||||
enum nrf52_gpiote_outcfg_e outcfg)
|
||||
{
|
||||
uint32_t regval;
|
||||
int pin;
|
||||
@ -351,6 +520,36 @@ int nrf52_gpiotaskset(uint32_t pinset, int channel,
|
||||
/* Write register */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_CONFIG_OFFSET(channel), regval);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiote_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize GPIOTE
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nrf52_gpiote_init(void)
|
||||
{
|
||||
/* Reset GPIOTE data */
|
||||
|
||||
memset(&g_gpiote_ch_callbacks, 0, sizeof(g_gpiote_ch_callbacks));
|
||||
|
||||
#ifdef CONFIG_NRF52_PER_PIN_INTERRUPTS
|
||||
memset(&g_gpiote_pin_callbacks, 0, sizeof(g_gpiote_pin_callbacks));
|
||||
|
||||
/* Enable PORT event interrupt */
|
||||
|
||||
nrf52_gpiote_putreg(NRF52_GPIOTE_INTENSET_OFFSET, GPIOTE_INT_PORT);
|
||||
#else
|
||||
memset(&g_gpiote_port_callback, 0, sizeof(g_gpiote_port_callback));
|
||||
#endif
|
||||
|
||||
/* Attach GPIOTE interrupt handler */
|
||||
|
||||
irq_attach(NRF52_IRQ_GPIOTE, nrf52_gpiote_isr, NULL);
|
||||
up_enable_irq(NRF52_IRQ_GPIOTE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
@ -49,17 +49,19 @@ enum nrf52_gpiote_outcfg_e
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiosetevent
|
||||
* Name: nrf52_gpiote_set_ch_event
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears GPIO based event and interrupt triggers.
|
||||
* Configures a GPIOTE channel in EVENT mode, assigns it to a given pin
|
||||
* and sets a handler for the corresponding channel events.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: gpio pin configuration
|
||||
* - rising/falling edge: enables
|
||||
* - event: generate event when set
|
||||
* - func: when non-NULL, generate interrupt
|
||||
* - arg: Argument passed to the interrupt callback
|
||||
* - pinset: GPIO pin configuration
|
||||
* - risingedge: Enables interrupt on rising edges
|
||||
* - fallingedge: Enables interrupt on falling edges
|
||||
* - event: Generate event when set
|
||||
* - func: When non-NULL, generate interrupt
|
||||
* - arg: Argument passed to the interrupt callback
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure indicating the
|
||||
@ -67,11 +69,65 @@ enum nrf52_gpiote_outcfg_e
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nrf52_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
|
||||
bool event, xcpt_t func, FAR void *arg);
|
||||
void nrf52_gpiote_set_ch_event(uint32_t pinset, int channel,
|
||||
bool risingedge, bool fallingedge,
|
||||
xcpt_t func, FAR void *arg);
|
||||
|
||||
#ifdef CONFIG_NRF52_PER_PIN_INTERRUPTS
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiote_set_pin_event
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears a handler for a given pin for the GPIO PORT event. This
|
||||
* will mean edge-sensitive or level-sensitive according to GPIO detect
|
||||
* mode configuration for the port (see nrf52_gpio_detectmode()). Pin
|
||||
* will be sensitive to high/low according to GPIO_SENSE_LOW/HIGH
|
||||
* (set via nrf52_gpio_config()).
|
||||
*
|
||||
* The passed handler will be invoked from the main ISR for the PORT
|
||||
* event and will take care of clearing the LATCH register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: GPIO pin configuration
|
||||
* - func: When non-NULL, generate interrupt
|
||||
* - arg: Argument passed to the interrupt callback
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure indicating the
|
||||
* nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nrf52_gpiote_set_pin_event(uint32_t pinset, xcpt_t func, FAR void *arg);
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiotaskset
|
||||
* Name: nrf52_gpiote_set_port_event
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears the handler for the GPIO PORT event.
|
||||
*
|
||||
* The passed handler will be invoked from the main ISR for the PORT
|
||||
* event and will take care of clearing the LATCH register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: GPIO port will be extracted from this parameter
|
||||
* - func: When non-NULL, generate interrupt
|
||||
* - arg: Argument passed to the interrupt callback
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure indicating the
|
||||
* nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nrf52_gpiote_set_port_event(uint32_t pinset, xcpt_t func,
|
||||
FAR void *arg);
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpio_set_task
|
||||
*
|
||||
* Description:
|
||||
* Configure GPIO in TASK mode (to be controlled via tasks).
|
||||
@ -93,8 +149,8 @@ int nrf52_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nrf52_gpiotaskset(uint32_t pinset, int channel, bool output_high,
|
||||
enum nrf52_gpiote_outcfg_e outcfg);
|
||||
void nrf52_gpio_set_task(uint32_t pinset, int channel,
|
||||
bool output_high, enum nrf52_gpiote_outcfg_e outcfg);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf52_gpiote_init
|
||||
|
@ -88,7 +88,7 @@ static int sx127x_irq0_attach(xcpt_t isr, FAR void *arg)
|
||||
|
||||
/* IRQ on rising edge */
|
||||
|
||||
nrf52_gpiosetevent(GPIO_SX127X_DIO0, true, false, false, isr, arg);
|
||||
nrf52_gpiote_set_ch_event(GPIO_SX127X_DIO0, 0, true, false, isr, arg);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user